From 6e157404b6f7413c587562fe0531a71929122270 Mon Sep 17 00:00:00 2001 From: Pedro Novais <1478752+jpnovais@users.noreply.github.com> Date: Mon, 13 Jan 2025 14:21:27 +0000 Subject: [PATCH 1/9] prover: Dockerfile remove legacy/unused data/work folder (#537) --- prover/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/prover/Dockerfile b/prover/Dockerfile index 678086c33..25f14ed67 100644 --- a/prover/Dockerfile +++ b/prover/Dockerfile @@ -30,7 +30,7 @@ RUN make bin/controller FROM alpine:3 RUN apk add --no-cache bash musl-dev libgcc -RUN mkdir -p /opt/linea/prover/lib/compressor /data/work /app/logs +RUN mkdir -p /opt/linea/prover/lib/compressor /app/logs # Import the LICENSE COPY ./LICENSE /opt/linea/prover/ From 1ad613107969253deaee6fa0a940344ac62464cf Mon Sep 17 00:00:00 2001 From: Pedro Novais <1478752+jpnovais@users.noreply.github.com> Date: Tue, 14 Jan 2025 16:39:02 +0000 Subject: [PATCH 2/9] coordinator: update traces limits-v2 (#548) --- config/common/traces-limits-v2.toml | 23 ++++++++-------- ...ator-docker-traces-v2-override.config.toml | 4 +-- .../coordinator-docker.config.toml | 9 +++---- config/coordinator/log4j2-dev.xml | 8 ++++++ .../app/config/CoordinatorConfigTest.kt | 27 ++++++++++--------- 5 files changed, 39 insertions(+), 32 deletions(-) diff --git a/config/common/traces-limits-v2.toml b/config/common/traces-limits-v2.toml index 1f06f6de5..9e1d4285e 100644 --- a/config/common/traces-limits-v2.toml +++ b/config/common/traces-limits-v2.toml @@ -10,12 +10,12 @@ BLOCK_HASH = 512 EC_DATA = 262144 EUC = 65536 EXP = 8192 -EXT = 65536 +EXT = 1048576 GAS = 65536 HUB = 2097152 LOG_DATA = 65536 LOG_INFO = 4096 -MMIO = 2097152 +MMIO = 4194304 MMU = 4194304 MOD = 131072 MUL = 65536 @@ -23,21 +23,21 @@ MXP = 524288 OOB = 262144 RLP_ADDR = 4096 RLP_TXN = 131072 -RLP_TXN_RCPT = 32768 -ROM = 8388608 +RLP_TXN_RCPT = 65536 +ROM = 4194304 ROM_LEX = 1024 SHAKIRA_DATA = 32768 SHF = 65536 -STP = 32768 -TRM = 8192 +STP = 16384 +TRM = 32768 TXN_DATA = 8192 WCP = 262144 # -# Reference table limits +# Reference table limits, set to UInt.MAX_VALUE # -BIN_REFERENCE_TABLE = 196864 -SHF_REFERENCE_TABLE = 4096 -INSTRUCTION_DECODER = 512 +BIN_REFERENCE_TABLE = 4294967295 +SHF_REFERENCE_TABLE = 4294967295 +INSTRUCTION_DECODER = 4294967295 # # Precompiles limits # @@ -48,7 +48,7 @@ PRECOMPILE_MODEXP_EFFECTIVE_CALLS = 4 PRECOMPILE_ECADD_EFFECTIVE_CALLS = 16384 PRECOMPILE_ECMUL_EFFECTIVE_CALLS = 32 PRECOMPILE_ECPAIRING_FINAL_EXPONENTIATIONS = 16 -PRECOMPILE_ECPAIRING_G2_MEMBERSHIP_CALLS = 64 +PRECOMPILE_ECPAIRING_G2_MEMBERSHIP_CALLS = 64 PRECOMPILE_ECPAIRING_MILLER_LOOPS = 64 PRECOMPILE_BLAKE_EFFECTIVE_CALLS = 600 PRECOMPILE_BLAKE_ROUNDS = 600 @@ -59,4 +59,3 @@ BLOCK_KECCAK = 8192 BLOCK_L1_SIZE = 1000000 BLOCK_L2_L1_LOGS = 16 BLOCK_TRANSACTIONS = 200 - diff --git a/config/coordinator/coordinator-docker-traces-v2-override.config.toml b/config/coordinator/coordinator-docker-traces-v2-override.config.toml index 096338011..c9e01f473 100644 --- a/config/coordinator/coordinator-docker-traces-v2-override.config.toml +++ b/config/coordinator/coordinator-docker-traces-v2-override.config.toml @@ -18,12 +18,12 @@ blob-compressor-version="V1_0_1" expected-traces-api-version-v2="v0.8.0-rc8" [traces.counters-v2] endpoints=["http://traces-node-v2:8545/"] -request-limit-per-endpoint=2 +request-limit-per-endpoint=1 request-retry.backoff-delay="PT1S" request-retry.failures-warning-threshold=2 [traces.conflation-v2] endpoints=["http://traces-node-v2:8545/"] -request-limit-per-endpoint=2 +request-limit-per-endpoint=1 request-retry.backoff-delay="PT1S" request-retry.failures-warning-threshold=2 diff --git a/config/coordinator/coordinator-docker.config.toml b/config/coordinator/coordinator-docker.config.toml index 4778c8ebc..62ce6851f 100644 --- a/config/coordinator/coordinator-docker.config.toml +++ b/config/coordinator/coordinator-docker.config.toml @@ -126,12 +126,11 @@ fee-history-reward-percentile=15 last-hash-search-window=25 anchoring-receipt-polling-interval="PT01S" max-receipt-retries=120 -# Number of children blocks to wait before considering a block "finalized" -# and elegible for conflation and +# Number of children blocks to wait before considering a won't be reverted and elegible for conflation. # this a workaround to mitigate Geth fork issues with Clique PoA # Coordinator will consider block as finalized after being included in the chain wtih children blocks-to-finalization -# Recommended minimum of 2 -blocks-to-finalization=2 +# Recommended: Geth sequencer minimum of 2, Besu sequencer minimum of 1, 0 is safe localy +blocks-to-finalization=0 [blob-submission] disabled=true @@ -153,7 +152,7 @@ proof-submission-delay="PT1S" [proof-aggregation] aggregation-proofs-limit=3 -aggregation-deadline="PT1M" +aggregation-deadline="PT10S" aggregation-coordinator-polling-interval="PT2S" deadline-check-interval="PT8S" target-end-blocks=[] diff --git a/config/coordinator/log4j2-dev.xml b/config/coordinator/log4j2-dev.xml index 48aa11611..dbd489ee6 100644 --- a/config/coordinator/log4j2-dev.xml +++ b/config/coordinator/log4j2-dev.xml @@ -100,6 +100,10 @@ + + + + @@ -112,6 +116,10 @@ + + + + diff --git a/coordinator/app/src/test/kotlin/net/consensys/zkevm/coordinator/app/config/CoordinatorConfigTest.kt b/coordinator/app/src/test/kotlin/net/consensys/zkevm/coordinator/app/config/CoordinatorConfigTest.kt index 9e1dfdec7..33005abe6 100644 --- a/coordinator/app/src/test/kotlin/net/consensys/zkevm/coordinator/app/config/CoordinatorConfigTest.kt +++ b/coordinator/app/src/test/kotlin/net/consensys/zkevm/coordinator/app/config/CoordinatorConfigTest.kt @@ -100,12 +100,12 @@ class CoordinatorConfigTest { TracingModuleV2.EC_DATA to 262144u, TracingModuleV2.EUC to 65536u, TracingModuleV2.EXP to 8192u, - TracingModuleV2.EXT to 65536u, + TracingModuleV2.EXT to 1048576u, TracingModuleV2.GAS to 65536u, TracingModuleV2.HUB to 2097152u, TracingModuleV2.LOG_DATA to 65536u, TracingModuleV2.LOG_INFO to 4096u, - TracingModuleV2.MMIO to 2097152u, + TracingModuleV2.MMIO to 4194304u, TracingModuleV2.MMU to 4194304u, TracingModuleV2.MOD to 131072u, TracingModuleV2.MUL to 65536u, @@ -113,18 +113,18 @@ class CoordinatorConfigTest { TracingModuleV2.OOB to 262144u, TracingModuleV2.RLP_ADDR to 4096u, TracingModuleV2.RLP_TXN to 131072u, - TracingModuleV2.RLP_TXN_RCPT to 32768u, - TracingModuleV2.ROM to 8388608u, + TracingModuleV2.RLP_TXN_RCPT to 65536u, + TracingModuleV2.ROM to 4194304u, TracingModuleV2.ROM_LEX to 1024u, TracingModuleV2.SHAKIRA_DATA to 32768u, TracingModuleV2.SHF to 65536u, - TracingModuleV2.STP to 32768u, - TracingModuleV2.TRM to 8192u, + TracingModuleV2.STP to 16384u, + TracingModuleV2.TRM to 32768u, TracingModuleV2.TXN_DATA to 8192u, TracingModuleV2.WCP to 262144u, - TracingModuleV2.BIN_REFERENCE_TABLE to 196864u, - TracingModuleV2.SHF_REFERENCE_TABLE to 4096u, - TracingModuleV2.INSTRUCTION_DECODER to 512u, + TracingModuleV2.BIN_REFERENCE_TABLE to 4294967295u, + TracingModuleV2.SHF_REFERENCE_TABLE to 4294967295u, + TracingModuleV2.INSTRUCTION_DECODER to 4294967295u, TracingModuleV2.PRECOMPILE_ECRECOVER_EFFECTIVE_CALLS to 128u, TracingModuleV2.PRECOMPILE_SHA2_BLOCKS to 671u, TracingModuleV2.PRECOMPILE_RIPEMD_BLOCKS to 671u, @@ -235,7 +235,7 @@ class CoordinatorConfigTest { private val aggregationConfig = AggregationConfig( aggregationProofsLimit = 3, - aggregationDeadline = Duration.parse("PT1M"), + aggregationDeadline = Duration.parse("PT10S"), aggregationCoordinatorPollingInterval = Duration.parse("PT2S"), deadlineCheckInterval = Duration.parse("PT8S") ) @@ -359,7 +359,7 @@ class CoordinatorConfigTest { maxFeePerGasCap = 100000000000u, feeHistoryBlockCount = 4U, feeHistoryRewardPercentile = 15.0, - blocksToFinalization = 2U, + blocksToFinalization = 0U, lastHashSearchWindow = 25U, anchoringReceiptPollingInterval = Duration.parse("PT01S"), maxReceiptRetries = 120U @@ -837,13 +837,14 @@ class CoordinatorConfigTest { blobCompressorVersion = BlobCompressorVersion.V1_0_1, expectedTracesApiVersionV2 = "v0.8.0-rc8", conflationV2 = tracesConfig.conflation.copy( - endpoints = listOf(URI("http://traces-node-v2:8545/").toURL()) + endpoints = listOf(URI("http://traces-node-v2:8545/").toURL()), + requestLimitPerEndpoint = 1U ), countersV2 = TracesConfig.FunctionalityEndpoint( listOf( URI("http://traces-node-v2:8545/").toURL() ), - requestLimitPerEndpoint = 2U, + requestLimitPerEndpoint = 1U, requestRetry = RequestRetryConfigTomlFriendly( backoffDelay = Duration.parse("PT1S"), failuresWarningThreshold = 2 From 27cc9eb0900999246c8d9a7c27352bc2c59b2907 Mon Sep 17 00:00:00 2001 From: Pedro Novais <1478752+jpnovais@users.noreply.github.com> Date: Wed, 15 Jan 2025 08:37:48 +0000 Subject: [PATCH 3/9] Coordinator fix logging (#551) * coordinator: log retried errors as info/debug instead of error --- .../ProofGeneratingConflationHandlerImpl.kt | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/coordinator/core/src/main/kotlin/net/consensys/zkevm/ethereum/coordination/conflation/ProofGeneratingConflationHandlerImpl.kt b/coordinator/core/src/main/kotlin/net/consensys/zkevm/ethereum/coordination/conflation/ProofGeneratingConflationHandlerImpl.kt index 0a258556d..9da2cac96 100644 --- a/coordinator/core/src/main/kotlin/net/consensys/zkevm/ethereum/coordination/conflation/ProofGeneratingConflationHandlerImpl.kt +++ b/coordinator/core/src/main/kotlin/net/consensys/zkevm/ethereum/coordination/conflation/ProofGeneratingConflationHandlerImpl.kt @@ -38,7 +38,12 @@ class ProofGeneratingConflationHandlerImpl( vertx = vertx, backoffDelay = config.conflationAndProofGenerationRetryInterval, exceptionConsumer = { - log.error("Conflation and proof creation flow failed!", it) + // log failure as warning, but keeps on retrying... + log.warn( + "conflation and proof creation flow failed batch={} errorMessage={}", + blockIntervalString, + it.message + ) } ) { conflationToProofCreation(conflation) @@ -46,7 +51,7 @@ class ProofGeneratingConflationHandlerImpl( }.getOrElse { error -> SafeFuture.failedFuture(error) } .whenException { th -> log.error( - "Traces conflation or proof failed: batch={} errorMessage={}", + "traces conflation or proof request failed: batch={} errorMessage={}", blockIntervalString, th.message, th @@ -60,8 +65,8 @@ class ProofGeneratingConflationHandlerImpl( return tracesProductionCoordinator .conflateExecutionTraces(blockNumbersAndHash) .whenException { th -> - log.error( - "Traces conflation failed: batch={} errorMessage={}", + log.debug( + "traces conflation failed: batch={} errorMessage={}", conflation.conflationResult.intervalString(), th.message, th @@ -79,7 +84,7 @@ class ProofGeneratingConflationHandlerImpl( log.info("execution proof generated: batch={}", blockIntervalString) } .whenException { th -> - log.error( + log.debug( "execution proof failure: batch={} errorMessage={}", blockIntervalString, th.message, From 522d9f18ef2dc6a0d133affb6cd13a5d2805c42e Mon Sep 17 00:00:00 2001 From: AlexandreBelling Date: Wed, 15 Jan 2025 09:48:45 +0100 Subject: [PATCH 4/9] chores(ci): deactivate the slack notification for prover-ci (#546) * chores(ci): deactivate the slack notification for prover-ci * Update .github/workflows/prover-testing.yml --------- Signed-off-by: AlexandreBelling Co-authored-by: kyzooghost <73516204+kyzooghost@users.noreply.github.com> --- .github/workflows/prover-testing.yml | 56 +--------------------------- 1 file changed, 1 insertion(+), 55 deletions(-) diff --git a/.github/workflows/prover-testing.yml b/.github/workflows/prover-testing.yml index 29780c57e..692c9493b 100644 --- a/.github/workflows/prover-testing.yml +++ b/.github/workflows/prover-testing.yml @@ -1,13 +1,6 @@ name: Prover testing CI -on: - workflow_call: - secrets: - SLACK_WEBHOOK_CI_PROVER_FAIL: - required: true - SLACK_WEBHOOK_CI_PROVER_SUCCESS: - required: true - +on: workflow_call env: GOPROXY: "https://proxy.golang.org" @@ -93,50 +86,3 @@ jobs: if: matrix.go-version == '1.20.x' run: | go test -p=1 -tags=nocorset,fuzzlight -timeout=30m -short -race ./... - - slack-workflow-status-failed: - if: failure() - name: Prover notify slack - needs: - - staticcheck - - test - runs-on: [self-hosted, ubuntu-20.04, X64, small] - steps: - - name: Notify slack -- workflow failed - id: slack - uses: slackapi/slack-github-action@v1.23.0 - with: - payload: | - { - "actor": "${{ github.actor }}", - "repo": "${{ github.repository }}", - "status": "FAIL", - "title": "${{ github.event.pull_request.title }}", - "pr": "${{ github.event.pull_request.head.ref }}" - } - env: - SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_CI_PROVER_FAIL }} - - slack-workflow-status-success: - if: success() - name: Prover notify slack - needs: - - staticcheck - - test - runs-on: [self-hosted, ubuntu-20.04, X64, small] - steps: - - name: Notify slack -- workflow succeeded - id: slack - uses: slackapi/slack-github-action@v1.23.0 - with: - payload: | - { - "actor": "${{ github.actor }}", - "repo": "${{ github.repository }}", - "status": "SUCCESS", - "title": "${{ github.event.pull_request.title }}", - "pr": "${{ github.event.pull_request.head.ref }}" - } - env: - SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_CI_PROVER_SUCCESS }} - From 4cb0c60fe0c1a69480a58faef7463b5d85535ba7 Mon Sep 17 00:00:00 2001 From: Pedro Novais <1478752+jpnovais@users.noreply.github.com> Date: Wed, 15 Jan 2025 10:18:04 +0000 Subject: [PATCH 5/9] coordinator: decouple configs test from real configs (#552) * coordinator: decouple configs test from real configs --- .../linea/coordinator/config/ConfigLoader.kt | 136 ++++ .../coordinator/app/CoordinatorAppCli.kt | 147 +---- .../app/config/CoordinatorConfigTest.kt | 606 ++++-------------- .../app/config/ExpectedGasPriceMultipliers.kt | 172 +++++ .../app/config/ExpectedTracesLimitsV1.kt | 48 ++ .../app/config/ExpectedTracesLimitsV2.kt | 60 ++ ...coordinator-traces-v2-override.config.toml | 40 ++ ...oordinator-web3signer-override.config.toml | 13 + .../resources/configs/coordinator.config.toml | 292 +++++++++ ...gas-price-cap-time-of-day-multipliers.toml | 184 ++++++ .../configs/smart-contract-errors.toml | 10 + .../resources/configs/traces-limits-v1.toml | 40 ++ .../resources/configs/traces-limits-v2.toml | 53 ++ 13 files changed, 1175 insertions(+), 626 deletions(-) create mode 100644 coordinator/app/src/main/kotlin/linea/coordinator/config/ConfigLoader.kt create mode 100644 coordinator/app/src/test/kotlin/net/consensys/zkevm/coordinator/app/config/ExpectedGasPriceMultipliers.kt create mode 100644 coordinator/app/src/test/kotlin/net/consensys/zkevm/coordinator/app/config/ExpectedTracesLimitsV1.kt create mode 100644 coordinator/app/src/test/kotlin/net/consensys/zkevm/coordinator/app/config/ExpectedTracesLimitsV2.kt create mode 100644 coordinator/app/src/test/resources/configs/coordinator-traces-v2-override.config.toml create mode 100644 coordinator/app/src/test/resources/configs/coordinator-web3signer-override.config.toml create mode 100644 coordinator/app/src/test/resources/configs/coordinator.config.toml create mode 100644 coordinator/app/src/test/resources/configs/gas-price-cap-time-of-day-multipliers.toml create mode 100644 coordinator/app/src/test/resources/configs/smart-contract-errors.toml create mode 100644 coordinator/app/src/test/resources/configs/traces-limits-v1.toml create mode 100644 coordinator/app/src/test/resources/configs/traces-limits-v2.toml diff --git a/coordinator/app/src/main/kotlin/linea/coordinator/config/ConfigLoader.kt b/coordinator/app/src/main/kotlin/linea/coordinator/config/ConfigLoader.kt new file mode 100644 index 000000000..d80c1c1d5 --- /dev/null +++ b/coordinator/app/src/main/kotlin/linea/coordinator/config/ConfigLoader.kt @@ -0,0 +1,136 @@ +package linea.coordinator.config + +import com.github.michaelbull.result.Err +import com.github.michaelbull.result.Ok +import com.github.michaelbull.result.Result +import com.github.michaelbull.result.get +import com.github.michaelbull.result.getOrElse +import com.sksamuel.hoplite.ConfigLoaderBuilder +import com.sksamuel.hoplite.addPathSource +import net.consensys.linea.traces.TracesCountersV1 +import net.consensys.linea.traces.TracesCountersV2 +import net.consensys.zkevm.coordinator.app.config.CoordinatorConfig +import net.consensys.zkevm.coordinator.app.config.CoordinatorConfigTomlDto +import net.consensys.zkevm.coordinator.app.config.GasPriceCapTimeOfDayMultipliersConfig +import net.consensys.zkevm.coordinator.app.config.SmartContractErrorCodesConfig +import net.consensys.zkevm.coordinator.app.config.TracesLimitsV1ConfigFile +import net.consensys.zkevm.coordinator.app.config.TracesLimitsV2ConfigFile +import org.apache.logging.log4j.LogManager +import org.apache.logging.log4j.Logger +import java.nio.file.Path + +inline fun loadConfigsOrError( + configFiles: List +): Result { + val confBuilder: ConfigLoaderBuilder = ConfigLoaderBuilder.Companion.empty().addDefaults() + for (configFile in configFiles.reversed()) { + // files must be added in reverse order for overriding + confBuilder.addPathSource(configFile, false) + } + + return confBuilder.build().loadConfig(emptyList()).let { config -> + if (config.isInvalid()) { + Err(config.getInvalidUnsafe().description()) + } else { + Ok(config.getUnsafe()) + } + } +} + +fun logErrorIfPresent( + configName: String, + configFiles: List, + configLoadingResult: Result, + logger: Logger +) { + if (configLoadingResult is Err) { + logger.error("Failed to load $configName from files=$configFiles with error=${configLoadingResult.error}") + } +} + +inline fun loadConfigsAndLogErrors( + configFiles: List, + configName: String, + logger: Logger = LogManager.getLogger("linea.coordinator.config") +): Result { + return loadConfigsOrError(configFiles) + .also { logErrorIfPresent(configName, configFiles, it, logger) } +} + +fun loadConfigsOrError( + coordinatorConfigFiles: List, + tracesLimitsFileV1: Path?, + tracesLimitsFileV2: Path?, + gasPriceCapTimeOfDayMultipliersFile: Path, + smartContractErrorsFile: Path, + logger: Logger = LogManager.getLogger("linea.coordinator.config") +): Result { + val coordinatorBaseConfigs = + loadConfigsAndLogErrors(coordinatorConfigFiles, "coordinator", logger) + val tracesLimitsV1Configs = tracesLimitsFileV1 + ?.let { loadConfigsAndLogErrors(listOf(it), "traces limit v1", logger) } + val tracesLimitsV2Configs = tracesLimitsFileV2 + ?.let { loadConfigsAndLogErrors(listOf(it), "traces limits v2", logger) } + val gasPriceCapTimeOfDayMultipliersConfig = + loadConfigsAndLogErrors( + listOf(gasPriceCapTimeOfDayMultipliersFile), + "l1 submission gas prices caps", + logger + ) + val smartContractErrorsConfig = loadConfigsAndLogErrors( + listOf(smartContractErrorsFile), + "smart contract errors", + logger + ) + val configError = listOf( + coordinatorBaseConfigs, + tracesLimitsV1Configs, + tracesLimitsV1Configs, + gasPriceCapTimeOfDayMultipliersConfig, + smartContractErrorsConfig + ) + .find { it is Err } + + if (configError != null) { + @Suppress("UNCHECKED_CAST") + return configError as Result + } + + val baseConfig = coordinatorBaseConfigs.get()!! + val finalConfig = baseConfig.copy( + conflation = baseConfig.conflation.copy( + _tracesLimitsV1 = tracesLimitsV1Configs?.get()?.tracesLimits?.let { TracesCountersV1(it) }, + _tracesLimitsV2 = tracesLimitsV2Configs?.get()?.tracesLimits?.let { TracesCountersV2(it) }, + _smartContractErrors = smartContractErrorsConfig.get()!!.smartContractErrors + ), + l1DynamicGasPriceCapService = baseConfig.l1DynamicGasPriceCapService.copy( + gasPriceCapCalculation = baseConfig.l1DynamicGasPriceCapService.gasPriceCapCalculation.copy( + timeOfDayMultipliers = gasPriceCapTimeOfDayMultipliersConfig.get()?.gasPriceCapTimeOfDayMultipliers + ) + ) + ) + return Ok(finalConfig) +} + +fun loadConfigs( + coordinatorConfigFiles: List, + tracesLimitsFileV1: Path?, + tracesLimitsFileV2: Path?, + gasPriceCapTimeOfDayMultipliersFile: Path, + smartContractErrorsFile: Path, + logger: Logger = LogManager.getLogger("linea.coordinator.config") +): CoordinatorConfig { + loadConfigsOrError( + coordinatorConfigFiles, + tracesLimitsFileV1, + tracesLimitsFileV2, + gasPriceCapTimeOfDayMultipliersFile, + smartContractErrorsFile, + logger + ).let { + return it + .getOrElse { + throw RuntimeException("Invalid configurations: $it") + }.reified() + } +} diff --git a/coordinator/app/src/main/kotlin/net/consensys/zkevm/coordinator/app/CoordinatorAppCli.kt b/coordinator/app/src/main/kotlin/net/consensys/zkevm/coordinator/app/CoordinatorAppCli.kt index e552add8c..febd8afec 100644 --- a/coordinator/app/src/main/kotlin/net/consensys/zkevm/coordinator/app/CoordinatorAppCli.kt +++ b/coordinator/app/src/main/kotlin/net/consensys/zkevm/coordinator/app/CoordinatorAppCli.kt @@ -1,21 +1,6 @@ package net.consensys.zkevm.coordinator.app -import com.github.michaelbull.result.Err -import com.github.michaelbull.result.Ok -import com.github.michaelbull.result.Result -import com.github.michaelbull.result.get -import com.github.michaelbull.result.getError -import com.github.michaelbull.result.onFailure -import com.sksamuel.hoplite.ConfigLoaderBuilder -import com.sksamuel.hoplite.addFileSource -import net.consensys.linea.traces.TracesCountersV1 -import net.consensys.linea.traces.TracesCountersV2 import net.consensys.zkevm.coordinator.app.config.CoordinatorConfig -import net.consensys.zkevm.coordinator.app.config.CoordinatorConfigTomlDto -import net.consensys.zkevm.coordinator.app.config.GasPriceCapTimeOfDayMultipliersConfig -import net.consensys.zkevm.coordinator.app.config.SmartContractErrorCodesConfig -import net.consensys.zkevm.coordinator.app.config.TracesLimitsV1ConfigFile -import net.consensys.zkevm.coordinator.app.config.TracesLimitsV2ConfigFile import org.apache.logging.log4j.LogManager import org.apache.logging.log4j.Logger import picocli.CommandLine @@ -115,13 +100,14 @@ internal constructor(private val errorWriter: PrintWriter, private val startActi } } - val configs = validateConfigs( - tracesLimitsFile, - tracesLimitsV2File, - smartContractErrorsFile, - gasPriceCapTimeOfDayMultipliersFile, - configFiles - ) ?: return 1 + val configs = linea.coordinator.config.loadConfigs( + coordinatorConfigFiles = configFiles.map { it.toPath() }, + tracesLimitsFileV1 = tracesLimitsFile?.toPath(), + tracesLimitsFileV2 = tracesLimitsV2File?.toPath(), + smartContractErrorsFile = smartContractErrorsFile.toPath(), + gasPriceCapTimeOfDayMultipliersFile = gasPriceCapTimeOfDayMultipliersFile.toPath(), + logger = logger + ) if (checkConfigsOnly) { logger.info("All configs are valid. Final configs: {}", configs) @@ -144,7 +130,7 @@ internal constructor(private val errorWriter: PrintWriter, private val startActi } fun reportUserError(ex: Throwable) { - logger.fatal(ex.message, ex) + logger.fatal(ex.message) errorWriter.println(ex.message) printUsage(errorWriter) } @@ -155,97 +141,6 @@ internal constructor(private val errorWriter: PrintWriter, private val startActi outputWriter.println(COMMAND_NAME + " --help") } - private fun validateConfigs( - tracesLimitsFile: File?, - tracesLimitsV2File: File?, - smartContractErrorsFile: File, - gasPriceCapTimeOfDayMultipliersFile: File, - coordinatorConfigFiles: List - ): CoordinatorConfig? { - var hasConfigError = false - val tracesLimitsV1Configs = if (tracesLimitsFile == null) { - null - } else { - loadConfigsOrError(listOf(tracesLimitsFile)) - } - - val tracesLimitsV2Configs = if (tracesLimitsV2File == null) { - null - } else { - loadConfigsOrError(listOf(tracesLimitsV2File)) - } - - val smartContractErrorCodes = - loadConfigsOrError(listOf(smartContractErrorsFile)) - - val gasPriceCapTimeOfDayMultipliers = - loadConfigsOrError(listOf(gasPriceCapTimeOfDayMultipliersFile)) - - val configs = loadConfigsOrError(coordinatorConfigFiles) - - if (tracesLimitsV1Configs is Err) { - hasConfigError = true - logger.error("Reading {} failed: {}", tracesLimitsFile, tracesLimitsV1Configs.getError()) - } else if (tracesLimitsV1Configs is Ok) { - runCatching { - TracesCountersV1(tracesLimitsV1Configs.get()!!.tracesLimits) - }.getOrElse { - hasConfigError = true - logger.error("Traces limits file {} is incomplete. {}", tracesLimitsFile, it.message) - } - } - - if (tracesLimitsV2Configs is Err) { - hasConfigError = true - logger.error("Reading {} failed: {}", tracesLimitsV2File, tracesLimitsV2Configs.getError()) - } else if (tracesLimitsV2Configs is Ok) { - runCatching { - TracesCountersV2(tracesLimitsV2Configs.get()!!.tracesLimits) - }.getOrElse { - hasConfigError = true - logger.error("Traces limits file {} is incomplete. {}", tracesLimitsV2File, it.message) - } - } - - if (smartContractErrorCodes is Err) { - hasConfigError = true - logger.error("Reading {} failed: {}", smartContractErrorsFile, smartContractErrorCodes.getError()) - } - - if (gasPriceCapTimeOfDayMultipliers is Err) { - hasConfigError = true - logger.error( - "Reading {} failed: {}", - gasPriceCapTimeOfDayMultipliersFile, - gasPriceCapTimeOfDayMultipliers.getError() - ) - } - - if (configs is Err) { - hasConfigError = true - logger.error("Reading {} failed: {}", configFiles, configs.getError()) - } - - return if (hasConfigError) { - null - } else { - configs.get()?.let { config: CoordinatorConfigTomlDto -> - config.copy( - conflation = config.conflation.copy( - _tracesLimitsV1 = tracesLimitsV1Configs?.get()?.tracesLimits?.let { TracesCountersV1(it) }, - _tracesLimitsV2 = tracesLimitsV2Configs?.get()?.tracesLimits?.let { TracesCountersV2(it) }, - _smartContractErrors = smartContractErrorCodes.get()?.smartContractErrors - ), - l1DynamicGasPriceCapService = config.l1DynamicGasPriceCapService.copy( - gasPriceCapCalculation = config.l1DynamicGasPriceCapService.gasPriceCapCalculation.copy( - timeOfDayMultipliers = gasPriceCapTimeOfDayMultipliers.get()?.gasPriceCapTimeOfDayMultipliers - ) - ) - ).reified() - } - } - } - /** * Not using a static field for this log instance because some code in this class executes prior * to the logging configuration being applied so it's not always safe to use the logger. @@ -267,29 +162,5 @@ internal constructor(private val errorWriter: PrintWriter, private val startActi val errorWriter = PrintWriter(System.err, true, Charset.defaultCharset()) return CoordinatorAppCli(errorWriter, startAction) } - - inline fun loadConfigs(configFiles: List, errorWriter: PrintWriter): T? { - return loadConfigsOrError(configFiles).onFailure { error -> - errorWriter.println(error) - }.get() - } - - inline fun loadConfigsOrError( - configFiles: List - ): Result { - val confBuilder: ConfigLoaderBuilder = ConfigLoaderBuilder.Companion.empty().addDefaults() - for (configFile in configFiles.reversed()) { - // files must be added in reverse order for overriding - confBuilder.addFileSource(configFile, false) - } - - return confBuilder.build().loadConfig(emptyList()).let { config -> - if (config.isInvalid()) { - Err(config.getInvalidUnsafe().description()) - } else { - Ok(config.getUnsafe()) - } - } - } } } diff --git a/coordinator/app/src/test/kotlin/net/consensys/zkevm/coordinator/app/config/CoordinatorConfigTest.kt b/coordinator/app/src/test/kotlin/net/consensys/zkevm/coordinator/app/config/CoordinatorConfigTest.kt index 33005abe6..3b62a295a 100644 --- a/coordinator/app/src/test/kotlin/net/consensys/zkevm/coordinator/app/config/CoordinatorConfigTest.kt +++ b/coordinator/app/src/test/kotlin/net/consensys/zkevm/coordinator/app/config/CoordinatorConfigTest.kt @@ -1,10 +1,9 @@ package net.consensys.zkevm.coordinator.app.config -import com.github.michaelbull.result.get import com.github.michaelbull.result.getError -import com.github.michaelbull.result.onFailure -import com.github.michaelbull.result.onSuccess import com.sksamuel.hoplite.Masked +import linea.coordinator.config.loadConfigs +import linea.coordinator.config.loadConfigsOrError import net.consensys.linea.BlockParameter import net.consensys.linea.blob.BlobCompressorVersion import net.consensys.linea.ethereum.gaspricing.BoundableFeeCalculator @@ -15,178 +14,39 @@ import net.consensys.linea.ethereum.gaspricing.staticcap.MinerExtraDataV1Calcula 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 import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Assertions.assertEquals -import org.junit.jupiter.api.Assertions.fail import org.junit.jupiter.api.Test import org.junit.jupiter.api.assertDoesNotThrow import org.junit.jupiter.api.assertThrows -import java.io.File import java.math.BigInteger import java.net.URI import java.nio.file.Path +import java.nio.file.Paths import java.time.Duration import kotlin.time.Duration.Companion.minutes import kotlin.time.Duration.Companion.seconds class CoordinatorConfigTest { companion object { - private val apiConfig = ApiConfig(9545U) - private val conflationConfig = ConflationConfig( consistentNumberOfBlocksOnL1ToWait = 1, conflationDeadline = Duration.parse("PT6S"), conflationDeadlineCheckInterval = Duration.parse("PT3S"), conflationDeadlineLastBlockConfirmationDelay = Duration.parse("PT2S"), blocksLimit = 2, - _tracesLimitsV1 = TracesCountersV1( - mapOf( - TracingModuleV1.ADD to 524288U, - TracingModuleV1.BIN to 262144U, - TracingModuleV1.BIN_RT to 262144U, - TracingModuleV1.EC_DATA to 4096U, - TracingModuleV1.EXT to 131072U, - TracingModuleV1.HUB to 2097152U, - TracingModuleV1.INSTRUCTION_DECODER to 512U, - TracingModuleV1.MMIO to 131072U, - TracingModuleV1.MMU to 131072U, - TracingModuleV1.MMU_ID to 131072U, - TracingModuleV1.MOD to 131072U, - TracingModuleV1.MUL to 65536U, - TracingModuleV1.MXP to 524288U, - TracingModuleV1.PHONEY_RLP to 32768U, - TracingModuleV1.PUB_HASH to 32768U, - TracingModuleV1.PUB_HASH_INFO to 32768U, - TracingModuleV1.PUB_LOG to 16384U, - TracingModuleV1.PUB_LOG_INFO to 16384U, - TracingModuleV1.RLP to 512U, - TracingModuleV1.ROM to 4194304U, - TracingModuleV1.SHF to 65536U, - TracingModuleV1.SHF_RT to 4096U, - TracingModuleV1.TX_RLP to 131072U, - TracingModuleV1.WCP to 262144U, - TracingModuleV1.BLOCK_TX to 200U, - TracingModuleV1.BLOCK_L2L1LOGS to 16U, - TracingModuleV1.BLOCK_KECCAK to 8192U, - TracingModuleV1.PRECOMPILE_ECRECOVER to 10000U, - TracingModuleV1.PRECOMPILE_SHA2 to 10000U, - TracingModuleV1.PRECOMPILE_RIPEMD to 10000U, - TracingModuleV1.PRECOMPILE_IDENTITY to 10000U, - TracingModuleV1.PRECOMPILE_MODEXP to 10000U, - TracingModuleV1.PRECOMPILE_ECADD to 10000U, - TracingModuleV1.PRECOMPILE_ECMUL to 10000U, - TracingModuleV1.PRECOMPILE_ECPAIRING to 10000U, - TracingModuleV1.PRECOMPILE_BLAKE2F to 512U - ) - ), - _tracesLimitsV2 = TracesCountersV2( - mapOf( - TracingModuleV2.ADD to 524288u, - TracingModuleV2.BIN to 262144u, - TracingModuleV2.BLAKE_MODEXP_DATA to 16384u, - TracingModuleV2.BLOCK_DATA to 1024u, - TracingModuleV2.BLOCK_HASH to 512u, - TracingModuleV2.EC_DATA to 262144u, - TracingModuleV2.EUC to 65536u, - TracingModuleV2.EXP to 8192u, - TracingModuleV2.EXT to 1048576u, - TracingModuleV2.GAS to 65536u, - TracingModuleV2.HUB to 2097152u, - TracingModuleV2.LOG_DATA to 65536u, - TracingModuleV2.LOG_INFO to 4096u, - TracingModuleV2.MMIO to 4194304u, - TracingModuleV2.MMU to 4194304u, - TracingModuleV2.MOD to 131072u, - TracingModuleV2.MUL to 65536u, - TracingModuleV2.MXP to 524288u, - TracingModuleV2.OOB to 262144u, - TracingModuleV2.RLP_ADDR to 4096u, - TracingModuleV2.RLP_TXN to 131072u, - TracingModuleV2.RLP_TXN_RCPT to 65536u, - TracingModuleV2.ROM to 4194304u, - TracingModuleV2.ROM_LEX to 1024u, - TracingModuleV2.SHAKIRA_DATA to 32768u, - TracingModuleV2.SHF to 65536u, - TracingModuleV2.STP to 16384u, - TracingModuleV2.TRM to 32768u, - TracingModuleV2.TXN_DATA to 8192u, - TracingModuleV2.WCP to 262144u, - TracingModuleV2.BIN_REFERENCE_TABLE to 4294967295u, - TracingModuleV2.SHF_REFERENCE_TABLE to 4294967295u, - TracingModuleV2.INSTRUCTION_DECODER to 4294967295u, - TracingModuleV2.PRECOMPILE_ECRECOVER_EFFECTIVE_CALLS to 128u, - TracingModuleV2.PRECOMPILE_SHA2_BLOCKS to 671u, - TracingModuleV2.PRECOMPILE_RIPEMD_BLOCKS to 671u, - TracingModuleV2.PRECOMPILE_MODEXP_EFFECTIVE_CALLS to 4u, - TracingModuleV2.PRECOMPILE_ECADD_EFFECTIVE_CALLS to 16384u, - TracingModuleV2.PRECOMPILE_ECMUL_EFFECTIVE_CALLS to 32u, - TracingModuleV2.PRECOMPILE_ECPAIRING_FINAL_EXPONENTIATIONS to 16u, - TracingModuleV2.PRECOMPILE_ECPAIRING_G2_MEMBERSHIP_CALLS to 64u, - TracingModuleV2.PRECOMPILE_ECPAIRING_MILLER_LOOPS to 64u, - TracingModuleV2.PRECOMPILE_BLAKE_EFFECTIVE_CALLS to 600u, - TracingModuleV2.PRECOMPILE_BLAKE_ROUNDS to 600u, - TracingModuleV2.BLOCK_KECCAK to 8192u, - TracingModuleV2.BLOCK_L1_SIZE to 1000000u, - TracingModuleV2.BLOCK_L2_L1_LOGS to 16u, - TracingModuleV2.BLOCK_TRANSACTIONS to 200u - ) - ), + _tracesLimitsV1 = expectedTracesCountersV1, + _tracesLimitsV2 = expectedTracesLimitsV2, _smartContractErrors = mapOf( // L1 Linea Rollup "0f06cd15" to "DataAlreadySubmitted", "c01eab56" to "EmptySubmissionData", - "abefa5e8" to "DataStartingBlockDoesNotMatch", - "5548c6b3" to "DataParentHasEmptyShnarf", - "36459fa0" to "L1RollingHashDoesNotExistOnL1", - "cbbd7953" to "FirstBlockGreaterThanFinalBlock", - "a386ed70" to "FirstBlockLessThanOrEqualToLastFinalizedBlock", - "70614405" to "FinalBlockNumberLessThanOrEqualToLastFinalizedBlock", - "2898482a" to "FinalBlockStateEqualsZeroHash", - "bf81c6e0" to "FinalizationInTheFuture", - "0c256592" to "MissingMessageNumberForRollingHash", - "5228f4c8" to "MissingRollingHashForMessageNumber", - "729eebce" to "FirstByteIsNotZero", - "6426c6c5" to "BytesLengthNotMultipleOf32", - "68dcad5f" to "PointEvaluationResponseInvalid", - "f75db381" to "PrecompileReturnDataLengthWrong", - "a71194af" to "PointEvaluationFailed", - "2f22b98a" to "LastFinalizedShnarfWrong", - "7dc2487d" to "SnarkHashIsZeroHash", - "bc5aad11" to "FinalizationStateIncorrect", - "b1504a5f" to "BlobSubmissionDataIsMissing", - "c0e41e1d" to "EmptyBlobDataAtIndex", - "fb4cd6ef" to "FinalBlockDoesNotMatchShnarfFinalBlock", - "2526F108" to "ShnarfAndFinalBlockNumberLengthsMismatched", - "d3664fb3" to "FinalShnarfWrong", - "4e686675" to "L2MerkleRootDoesNotExist", - "e5d14425" to "L2MerkleRootAlreadyAnchored", - "0c91d776" to "BytesLengthNotMultipleOfTwo", - "ead4c30e" to "StartingRootHashDoesNotMatch", - "7907d79b" to "ProofIsEmpty", - "69ed70ab" to "InvalidProofType", - "09bde339" to "InvalidProof", - "db246dde" to "IsPaused", - "b015579f" to "IsNotPaused", - "3b174434" to "MessageHashesListLengthHigherThanOneHundred", - "ca389c44" to "InvalidProofOrProofVerificationRanOutOfGas", - "42ab979d" to "ParentBlobNotSubmitted", - "edeae83c" to "FinalBlobNotSubmitted", - // L2 Message Service - "6446cc9c" to "MessageHashesListLengthIsZero", - "d39e75f9" to "L1MessageNumberSynchronizationWrong", - "7557a60a" to "L1RollingHashSynchronizationWrong", - "36a4bb94" to "FinalRollingHashIsZero" + "abefa5e8" to "DataStartingBlockDoesNotMatch" ), fetchBlocksLimit = 4000 ) @@ -478,176 +338,7 @@ class CoordinatorConfigTest { gasPriceCapsCheckCoefficient = 0.9, historicBaseFeePerBlobGasLowerBound = 100_000_000u, historicAvgRewardConstant = 100_000_000u, - timeOfDayMultipliers = mapOf( - "SUNDAY_0" to 1.7489178377946066, - "SUNDAY_1" to 1.7494632175198737, - "SUNDAY_2" to 1.75, - "SUNDAY_3" to 1.733166295438555, - "SUNDAY_4" to 1.6993775444542885, - "SUNDAY_5" to 1.6350086618091364, - "SUNDAY_6" to 1.5627740860151331, - "SUNDAY_7" to 1.4831149222064164, - "SUNDAY_8" to 1.4101476768256929, - "SUNDAY_9" to 1.370085278922007, - "SUNDAY_10" to 1.3516015544068651, - "SUNDAY_11" to 1.3482404546676368, - "SUNDAY_12" to 1.3580905751578942, - "SUNDAY_13" to 1.3775497419563296, - "SUNDAY_14" to 1.3700255667542938, - "SUNDAY_15" to 1.2642948506461285, - "SUNDAY_16" to 1.2794806131912935, - "SUNDAY_17" to 1.2750892256476676, - "SUNDAY_18" to 1.2919720208955585, - "SUNDAY_19" to 1.317984990098603, - "SUNDAY_20" to 1.4433501639513178, - "SUNDAY_21" to 1.4705921238901998, - "SUNDAY_22" to 1.515043370430801, - "SUNDAY_23" to 1.5556742617266397, - "MONDAY_0" to 1.5381562278760164, - "MONDAY_1" to 1.5423761828433993, - "MONDAY_2" to 1.539015963719092, - "MONDAY_3" to 1.487676153648977, - "MONDAY_4" to 1.430973985132037, - "MONDAY_5" to 1.4656765439056292, - "MONDAY_6" to 1.4484298622828233, - "MONDAY_7" to 1.4459076216659752, - "MONDAY_8" to 1.4899061835032241, - "MONDAY_9" to 1.5249733712852067, - "MONDAY_10" to 1.511367489481033, - "MONDAY_11" to 1.4225695658047797, - "MONDAY_12" to 1.2887291896624584, - "MONDAY_13" to 1.1460926897291355, - "MONDAY_14" to 1.0004897955233254, - "MONDAY_15" to 0.8694664537368378, - "MONDAY_16" to 0.8270273375962802, - "MONDAY_17" to 0.7868289022833883, - "MONDAY_18" to 0.7780303121746551, - "MONDAY_19" to 0.7756215256634205, - "MONDAY_20" to 0.7984895728860915, - "MONDAY_21" to 0.8918589268832423, - "MONDAY_22" to 0.9967716668541272, - "MONDAY_23" to 1.0973334887144106, - "TUESDAY_0" to 1.2233064209957951, - "TUESDAY_1" to 1.3238883432855082, - "TUESDAY_2" to 1.3874518307497257, - "TUESDAY_3" to 1.463621147171298, - "TUESDAY_4" to 1.4975989065490154, - "TUESDAY_5" to 1.481679186141442, - "TUESDAY_6" to 1.452778387763161, - "TUESDAY_7" to 1.3414858185569951, - "TUESDAY_8" to 1.2869454637983988, - "TUESDAY_9" to 1.249347290389873, - "TUESDAY_10" to 1.196488297386161, - "TUESDAY_11" to 1.1136140507034202, - "TUESDAY_12" to 0.9867528660797885, - "TUESDAY_13" to 0.8018989158195754, - "TUESDAY_14" to 0.6173048748109258, - "TUESDAY_15" to 0.46718586671750373, - "TUESDAY_16" to 0.4103633833041902, - "TUESDAY_17" to 0.4871260756989506, - "TUESDAY_18" to 0.5667378483016126, - "TUESDAY_19" to 0.6464203510900723, - "TUESDAY_20" to 0.7780268325299871, - "TUESDAY_21" to 0.8995921101255763, - "TUESDAY_22" to 1.0077600114996088, - "TUESDAY_23" to 1.1109769960680498, - "WEDNESDAY_0" to 1.2097668746150059, - "WEDNESDAY_1" to 1.2631002319009361, - "WEDNESDAY_2" to 1.2912775191940549, - "WEDNESDAY_3" to 1.3229785939630059, - "WEDNESDAY_4" to 1.3428607301494424, - "WEDNESDAY_5" to 1.3750788517823973, - "WEDNESDAY_6" to 1.3752344527256497, - "WEDNESDAY_7" to 1.3505490078766218, - "WEDNESDAY_8" to 1.2598503219367945, - "WEDNESDAY_9" to 1.2051668977452374, - "WEDNESDAY_10" to 1.0320896222195326, - "WEDNESDAY_11" to 0.8900138031631949, - "WEDNESDAY_12" to 0.6341155208698448, - "WEDNESDAY_13" to 0.48337590254714624, - "WEDNESDAY_14" to 0.2903189399226416, - "WEDNESDAY_15" to 0.25, - "WEDNESDAY_16" to 0.25711039485046006, - "WEDNESDAY_17" to 0.37307641907591793, - "WEDNESDAY_18" to 0.45280799454961196, - "WEDNESDAY_19" to 0.5631397823847637, - "WEDNESDAY_20" to 0.6285005244224133, - "WEDNESDAY_21" to 0.6671897537279405, - "WEDNESDAY_22" to 0.7268406397452634, - "WEDNESDAY_23" to 0.8068904097486369, - "THURSDAY_0" to 0.9021601102971811, - "THURSDAY_1" to 1.023741688964238, - "THURSDAY_2" to 1.1340689935096755, - "THURSDAY_3" to 1.2530130345819006, - "THURSDAY_4" to 1.3163421664973542, - "THURSDAY_5" to 1.3536343767230727, - "THURSDAY_6" to 1.3432290485306728, - "THURSDAY_7" to 1.2864983218982178, - "THURSDAY_8" to 1.2320488534113174, - "THURSDAY_9" to 1.1984530721079034, - "THURSDAY_10" to 1.0877338251341975, - "THURSDAY_11" to 0.9999324929016475, - "THURSDAY_12" to 0.87536726762619, - "THURSDAY_13" to 0.6560822412167919, - "THURSDAY_14" to 0.44836474861432074, - "THURSDAY_15" to 0.36145134935025247, - "THURSDAY_16" to 0.2695997829759713, - "THURSDAY_17" to 0.2898426312618241, - "THURSDAY_18" to 0.3970093434340387, - "THURSDAY_19" to 0.5193273246848977, - "THURSDAY_20" to 0.6426415257034419, - "THURSDAY_21" to 0.800685718218497, - "THURSDAY_22" to 0.9215516833839711, - "THURSDAY_23" to 1.053701659160912, - "FRIDAY_0" to 1.149649788723893, - "FRIDAY_1" to 1.2046315447861193, - "FRIDAY_2" to 1.2724031281576726, - "FRIDAY_3" to 1.3525693456352732, - "FRIDAY_4" to 1.3746126314960814, - "FRIDAY_5" to 1.3744591862592468, - "FRIDAY_6" to 1.3297812543035683, - "FRIDAY_7" to 1.2762064429631657, - "FRIDAY_8" to 1.235662409263294, - "FRIDAY_9" to 1.2171558028785991, - "FRIDAY_10" to 1.182722399785398, - "FRIDAY_11" to 1.137345538963285, - "FRIDAY_12" to 0.9999308422620752, - "FRIDAY_13" to 0.8055000309055653, - "FRIDAY_14" to 0.5667135273493851, - "FRIDAY_15" to 0.4081529603000651, - "FRIDAY_16" to 0.3987031354907009, - "FRIDAY_17" to 0.5030075499003412, - "FRIDAY_18" to 0.6518159532641841, - "FRIDAY_19" to 0.8733483414970974, - "FRIDAY_20" to 1.0496224913080463, - "FRIDAY_21" to 1.1820684558591705, - "FRIDAY_22" to 1.2561688567574458, - "FRIDAY_23" to 1.3204704912328773, - "SATURDAY_0" to 1.3832230236620218, - "SATURDAY_1" to 1.4632908341022142, - "SATURDAY_2" to 1.5019230781315296, - "SATURDAY_3" to 1.5437332506007084, - "SATURDAY_4" to 1.5934153179751855, - "SATURDAY_5" to 1.6245578072557723, - "SATURDAY_6" to 1.6294919789890665, - "SATURDAY_7" to 1.6027665451672717, - "SATURDAY_8" to 1.6068061069158674, - "SATURDAY_9" to 1.624257927970777, - "SATURDAY_10" to 1.5996112411089, - "SATURDAY_11" to 1.5659672993092648, - "SATURDAY_12" to 1.5333537902522736, - "SATURDAY_13" to 1.445292929996356, - "SATURDAY_14" to 1.2966021477035259, - "SATURDAY_15" to 1.250999408961155, - "SATURDAY_16" to 1.2535364828163025, - "SATURDAY_17" to 1.2736456128871074, - "SATURDAY_18" to 1.3348268054897328, - "SATURDAY_19" to 1.4571388900094875, - "SATURDAY_20" to 1.5073787902995706, - "SATURDAY_21" to 1.5605139580010123, - "SATURDAY_22" to 1.5885303316932382, - "SATURDAY_23" to 1.6169891066719597 - ) + timeOfDayMultipliers = expectedTimeOfDayMultipliers ), feeHistoryFetcher = L1DynamicGasPriceCapServiceConfig.FeeHistoryFetcher( fetchInterval = Duration.parse("PT1S"), @@ -689,201 +380,141 @@ class CoordinatorConfigTest { private data class TestConfig(val extraField: String) @Test - fun parsesValidConfig() { - val smartContractErrorConfig = - CoordinatorAppCli.loadConfigsOrError( - listOf(File("../../config/common/smart-contract-errors.toml")) - ) - val timeOfDayMultipliers = - CoordinatorAppCli.loadConfigsOrError( - listOf(File("../../config/common/gas-price-cap-time-of-day-multipliers.toml")) - ) - val tracesLimitsConfigs = - CoordinatorAppCli.loadConfigsOrError( - listOf(File("../../config/common/traces-limits-v1.toml")) - ) - val tracesLimitsV2Configs = - CoordinatorAppCli.loadConfigsOrError( - listOf(File("../../config/common/traces-limits-v2.toml")) - ) - CoordinatorAppCli.loadConfigsOrError( - listOf(File("../../config/coordinator/coordinator-docker.config.toml")) - ) - .onFailure { error: String -> fail(error) } - .onSuccess { config: CoordinatorConfigTomlDto -> - val configs = config.copy( - conflation = config.conflation.copy( - _tracesLimitsV1 = tracesLimitsConfigs.get()?.tracesLimits?.let { TracesCountersV1(it) }, - _tracesLimitsV2 = tracesLimitsV2Configs.get()?.tracesLimits?.let { TracesCountersV2(it) }, - _smartContractErrors = smartContractErrorConfig.get()!!.smartContractErrors - ), - l1DynamicGasPriceCapService = config.l1DynamicGasPriceCapService.copy( - gasPriceCapCalculation = config.l1DynamicGasPriceCapService.gasPriceCapCalculation.copy( - timeOfDayMultipliers = timeOfDayMultipliers.get()?.gasPriceCapTimeOfDayMultipliers - ) - ) - ) - assertEquals(coordinatorConfig, configs.reified()) - assertEquals(coordinatorConfig.l1.rpcEndpoint, coordinatorConfig.l1.ethFeeHistoryEndpoint) - } + fun `should keep local stack testing configs uptodate with the code`() { + // Just assert that Files have been loaded and parsed correctly + // This is to prevent Code changes in coordinator and forgetting to update config files used in the local stack + loadConfigs( + coordinatorConfigFiles = listOf( + Path.of("../../config/coordinator/coordinator-docker.config.toml"), + Path.of("../../config/coordinator/coordinator-docker-traces-v2-override.config.toml"), + Path.of("../../config/coordinator/coordinator-docker-web3signer-override.config.toml"), + Path.of("../../config/coordinator/coordinator-local-dev.config.overrides.toml"), + Path.of("../../config/coordinator/coordinator-local-dev.config-traces-v2.overrides.toml") + ), + tracesLimitsFileV1 = Path.of("../../config/common/traces-limits-v1.toml"), + tracesLimitsFileV2 = Path.of("../../config/common/traces-limits-v2.toml"), + gasPriceCapTimeOfDayMultipliersFile = Path.of("../../config/common/gas-price-cap-time-of-day-multipliers.toml"), + smartContractErrorsFile = Path.of("../../config/common/smart-contract-errors.toml") + ) + } + + private fun pathToResource(resource: String): Path { + return Paths.get( + this::class.java.classLoader.getResource(resource)?.toURI() + ?: error("Resource not found: $resource") + ) } @Test - fun parsesValidWeb3SignerConfigOverride() { - val smartContractErrorCodes: SmartContractErrors = - CoordinatorAppCli.loadConfigsOrError( - listOf(File("../../config/common/smart-contract-errors.toml")) - ).get()!!.smartContractErrors - val timeOfDayMultipliers = - CoordinatorAppCli.loadConfigsOrError( - listOf(File("../../config/common/gas-price-cap-time-of-day-multipliers.toml")) - ) - val tracesLimitsConfigs = - CoordinatorAppCli.loadConfigsOrError( - listOf(File("../../config/common/traces-limits-v1.toml")) - ) - val tracesLimitsV2Configs = - CoordinatorAppCli.loadConfigsOrError( - listOf(File("../../config/common/traces-limits-v2.toml")) - ) + fun `should parse and consolidate configs`() { + val configs = loadConfigs( + coordinatorConfigFiles = listOf(pathToResource("configs/coordinator.config.toml")), + tracesLimitsFileV1 = pathToResource("configs/traces-limits-v1.toml"), + tracesLimitsFileV2 = pathToResource("configs/traces-limits-v2.toml"), + gasPriceCapTimeOfDayMultipliersFile = pathToResource("configs/gas-price-cap-time-of-day-multipliers.toml"), + smartContractErrorsFile = pathToResource("configs/smart-contract-errors.toml") + ) - CoordinatorAppCli.loadConfigsOrError( - listOf( - File("../../config/coordinator/coordinator-docker.config.toml"), - File("../../config/coordinator/coordinator-docker-web3signer-override.config.toml") - ) + assertEquals(coordinatorConfig, configs) + assertEquals(coordinatorConfig.l1.rpcEndpoint, coordinatorConfig.l1.ethFeeHistoryEndpoint) + } + + @Test + fun parsesValidWeb3SignerConfigOverride() { + val config = loadConfigs( + coordinatorConfigFiles = listOf( + pathToResource("configs/coordinator.config.toml"), + pathToResource("configs/coordinator-web3signer-override.config.toml") + ), + tracesLimitsFileV1 = pathToResource("configs/traces-limits-v1.toml"), + tracesLimitsFileV2 = pathToResource("configs/traces-limits-v2.toml"), + gasPriceCapTimeOfDayMultipliersFile = pathToResource("configs/gas-price-cap-time-of-day-multipliers.toml"), + smartContractErrorsFile = pathToResource("configs/smart-contract-errors.toml") ) - .onFailure { error: String -> fail(error) } - .onSuccess { - val configs = it.copy( - conflation = it.conflation.copy( - _tracesLimitsV1 = tracesLimitsConfigs.get()?.tracesLimits?.let { TracesCountersV1(it) }, - _tracesLimitsV2 = tracesLimitsV2Configs.get()?.tracesLimits?.let { TracesCountersV2(it) }, - _smartContractErrors = smartContractErrorCodes - ), - l1DynamicGasPriceCapService = it.l1DynamicGasPriceCapService.copy( - gasPriceCapCalculation = it.l1DynamicGasPriceCapService.gasPriceCapCalculation.copy( - timeOfDayMultipliers = timeOfDayMultipliers.get()?.gasPriceCapTimeOfDayMultipliers - ) - ) - ) - val expectedConfig = - coordinatorConfig.copy( - finalizationSigner = finalizationSigner.copy(type = SignerConfig.Type.Web3Signer), - dataSubmissionSigner = dataSubmissionSigner.copy(type = SignerConfig.Type.Web3Signer), - l2Signer = l2SignerConfig.copy(type = SignerConfig.Type.Web3Signer) - ) + val expectedConfig = + coordinatorConfig.copy( + finalizationSigner = finalizationSigner.copy(type = SignerConfig.Type.Web3Signer), + dataSubmissionSigner = dataSubmissionSigner.copy(type = SignerConfig.Type.Web3Signer), + l2Signer = l2SignerConfig.copy(type = SignerConfig.Type.Web3Signer) + ) - assertEquals(expectedConfig, configs.reified()) - } + assertThat(config).isEqualTo(expectedConfig) } @Test fun parsesValidTracesV2ConfigOverride() { - val smartContractErrorCodes: SmartContractErrors = - CoordinatorAppCli.loadConfigsOrError( - listOf(File("../../config/common/smart-contract-errors.toml")) - ).get()!!.smartContractErrors - val timeOfDayMultipliers = - CoordinatorAppCli.loadConfigsOrError( - listOf(File("../../config/common/gas-price-cap-time-of-day-multipliers.toml")) - ) - val tracesLimitsConfigs = - CoordinatorAppCli.loadConfigsOrError( - listOf(File("../../config/common/traces-limits-v1.toml")) - ) - val tracesLimitsV2Configs = - CoordinatorAppCli.loadConfigsOrError( - listOf(File("../../config/common/traces-limits-v2.toml")) - ) - - CoordinatorAppCli.loadConfigsOrError( - listOf( - File("../../config/coordinator/coordinator-docker.config.toml"), - File("../../config/coordinator/coordinator-docker-traces-v2-override.config.toml") - ) + val config = loadConfigs( + coordinatorConfigFiles = listOf( + pathToResource("configs/coordinator.config.toml"), + pathToResource("configs/coordinator-traces-v2-override.config.toml") + ), + tracesLimitsFileV1 = pathToResource("configs/traces-limits-v1.toml"), + tracesLimitsFileV2 = pathToResource("configs/traces-limits-v2.toml"), + gasPriceCapTimeOfDayMultipliersFile = pathToResource("configs/gas-price-cap-time-of-day-multipliers.toml"), + smartContractErrorsFile = pathToResource("configs/smart-contract-errors.toml") ) - .onFailure { error: String -> fail(error) } - .onSuccess { - val configs = it.copy( - conflation = it.conflation.copy( - _tracesLimitsV1 = tracesLimitsConfigs.get()?.tracesLimits?.let { TracesCountersV1(it) }, - _tracesLimitsV2 = tracesLimitsV2Configs.get()?.tracesLimits?.let { TracesCountersV2(it) }, - _smartContractErrors = smartContractErrorCodes + + val expectedConfig = + coordinatorConfig.copy( + zkTraces = zkTracesConfig.copy(ethApi = URI("http://traces-node-v2:8545").toURL()), + l2NetworkGasPricingService = l2NetworkGasPricingServiceConfig.copy( + legacy = + l2NetworkGasPricingServiceConfig.legacy.copy( + transactionCostCalculatorConfig = + l2NetworkGasPricingServiceConfig.legacy.transactionCostCalculatorConfig?.copy( + compressedTxSize = 350, + expectedGas = 29400 + ) + ) + ), + traces = tracesConfig.copy( + switchToLineaBesu = true, + blobCompressorVersion = BlobCompressorVersion.V1_0_1, + expectedTracesApiVersionV2 = "v0.8.0-rc8", + conflationV2 = tracesConfig.conflation.copy( + endpoints = listOf(URI("http://traces-node-v2:8545/").toURL()), + requestLimitPerEndpoint = 1U ), - l1DynamicGasPriceCapService = it.l1DynamicGasPriceCapService.copy( - gasPriceCapCalculation = it.l1DynamicGasPriceCapService.gasPriceCapCalculation.copy( - timeOfDayMultipliers = timeOfDayMultipliers.get()?.gasPriceCapTimeOfDayMultipliers + countersV2 = TracesConfig.FunctionalityEndpoint( + listOf( + URI("http://traces-node-v2:8545/").toURL() + ), + requestLimitPerEndpoint = 1U, + requestRetry = RequestRetryConfigTomlFriendly( + backoffDelay = Duration.parse("PT1S"), + failuresWarningThreshold = 2 ) ) - ) - - val expectedConfig = - coordinatorConfig.copy( - zkTraces = zkTracesConfig.copy(ethApi = URI("http://traces-node-v2:8545").toURL()), - l2NetworkGasPricingService = l2NetworkGasPricingServiceConfig.copy( - legacy = - l2NetworkGasPricingServiceConfig.legacy.copy( - transactionCostCalculatorConfig = - l2NetworkGasPricingServiceConfig.legacy.transactionCostCalculatorConfig?.copy( - compressedTxSize = 350, - expectedGas = 29400 - ) - ) + ), + proversConfig = proversConfig.copy( + proverA = proversConfig.proverA.copy( + execution = proversConfig.proverA.execution.copy( + requestsDirectory = Path.of("/data/prover/v3/execution/requests"), + responsesDirectory = Path.of("/data/prover/v3/execution/responses") ), - traces = tracesConfig.copy( - switchToLineaBesu = true, - blobCompressorVersion = BlobCompressorVersion.V1_0_1, - expectedTracesApiVersionV2 = "v0.8.0-rc8", - conflationV2 = tracesConfig.conflation.copy( - endpoints = listOf(URI("http://traces-node-v2:8545/").toURL()), - requestLimitPerEndpoint = 1U - ), - countersV2 = TracesConfig.FunctionalityEndpoint( - listOf( - URI("http://traces-node-v2:8545/").toURL() - ), - requestLimitPerEndpoint = 1U, - requestRetry = RequestRetryConfigTomlFriendly( - backoffDelay = Duration.parse("PT1S"), - failuresWarningThreshold = 2 - ) - ) + blobCompression = proversConfig.proverA.blobCompression.copy( + requestsDirectory = Path.of("/data/prover/v3/compression/requests"), + responsesDirectory = Path.of("/data/prover/v3/compression/responses") ), - proversConfig = proversConfig.copy( - proverA = proversConfig.proverA.copy( - execution = proversConfig.proverA.execution.copy( - requestsDirectory = Path.of("/data/prover/v3/execution/requests"), - responsesDirectory = Path.of("/data/prover/v3/execution/responses") - ), - blobCompression = proversConfig.proverA.blobCompression.copy( - requestsDirectory = Path.of("/data/prover/v3/compression/requests"), - responsesDirectory = Path.of("/data/prover/v3/compression/responses") - ), - proofAggregation = proversConfig.proverA.proofAggregation.copy( - requestsDirectory = Path.of("/data/prover/v3/aggregation/requests"), - responsesDirectory = Path.of("/data/prover/v3/aggregation/responses") - ) - ) + proofAggregation = proversConfig.proverA.proofAggregation.copy( + requestsDirectory = Path.of("/data/prover/v3/aggregation/requests"), + responsesDirectory = Path.of("/data/prover/v3/aggregation/responses") ) ) + ) + ) - assertEquals(expectedConfig, configs.reified()) - } + assertThat(config).isEqualTo(expectedConfig) } @Test fun invalidConfigReturnsErrorResult() { - val configs = - CoordinatorAppCli.loadConfigsOrError( - listOf( - File("../../config/coordinator/coordinator-docker.config.toml"), - File("../../config/coordinator/coordinator-docker-web3signer-override.config.toml") - ) - ) + val configsResult = loadConfigsOrError( + configFiles = listOf(pathToResource("configs/coordinator.config.toml")) + ) - assertThat(configs.getError()).contains("'extraField': Missing from config") + assertThat(configsResult.getError()).contains("'extraField': Missing from config") } @Test @@ -930,8 +561,7 @@ class CoordinatorConfigTest { } @Test - fun testValidAggregationAndConflationByTargetBlockNumberWhenL2InclusiveBlockNumberToStopAndFlushAggregationSpecified - () { + fun testValidAggrAndConflationByTargetBlockNumberWhenL2InclusiveBlockNumberToStopAndFlushAggregationSpecified() { val aggregationConfigWithoutSwithBlockNumber = aggregationConfig.copy( _targetEndBlocks = listOf(10L, 100L) ) diff --git a/coordinator/app/src/test/kotlin/net/consensys/zkevm/coordinator/app/config/ExpectedGasPriceMultipliers.kt b/coordinator/app/src/test/kotlin/net/consensys/zkevm/coordinator/app/config/ExpectedGasPriceMultipliers.kt new file mode 100644 index 000000000..d872e96a1 --- /dev/null +++ b/coordinator/app/src/test/kotlin/net/consensys/zkevm/coordinator/app/config/ExpectedGasPriceMultipliers.kt @@ -0,0 +1,172 @@ +package net.consensys.zkevm.coordinator.app.config + +val expectedTimeOfDayMultipliers = mapOf( + "SUNDAY_0" to 1.7489178377946066, + "SUNDAY_1" to 1.7494632175198737, + "SUNDAY_2" to 1.75, + "SUNDAY_3" to 1.733166295438555, + "SUNDAY_4" to 1.6993775444542885, + "SUNDAY_5" to 1.6350086618091364, + "SUNDAY_6" to 1.5627740860151331, + "SUNDAY_7" to 1.4831149222064164, + "SUNDAY_8" to 1.4101476768256929, + "SUNDAY_9" to 1.370085278922007, + "SUNDAY_10" to 1.3516015544068651, + "SUNDAY_11" to 1.3482404546676368, + "SUNDAY_12" to 1.3580905751578942, + "SUNDAY_13" to 1.3775497419563296, + "SUNDAY_14" to 1.3700255667542938, + "SUNDAY_15" to 1.2642948506461285, + "SUNDAY_16" to 1.2794806131912935, + "SUNDAY_17" to 1.2750892256476676, + "SUNDAY_18" to 1.2919720208955585, + "SUNDAY_19" to 1.317984990098603, + "SUNDAY_20" to 1.4433501639513178, + "SUNDAY_21" to 1.4705921238901998, + "SUNDAY_22" to 1.515043370430801, + "SUNDAY_23" to 1.5556742617266397, + "MONDAY_0" to 1.5381562278760164, + "MONDAY_1" to 1.5423761828433993, + "MONDAY_2" to 1.539015963719092, + "MONDAY_3" to 1.487676153648977, + "MONDAY_4" to 1.430973985132037, + "MONDAY_5" to 1.4656765439056292, + "MONDAY_6" to 1.4484298622828233, + "MONDAY_7" to 1.4459076216659752, + "MONDAY_8" to 1.4899061835032241, + "MONDAY_9" to 1.5249733712852067, + "MONDAY_10" to 1.511367489481033, + "MONDAY_11" to 1.4225695658047797, + "MONDAY_12" to 1.2887291896624584, + "MONDAY_13" to 1.1460926897291355, + "MONDAY_14" to 1.0004897955233254, + "MONDAY_15" to 0.8694664537368378, + "MONDAY_16" to 0.8270273375962802, + "MONDAY_17" to 0.7868289022833883, + "MONDAY_18" to 0.7780303121746551, + "MONDAY_19" to 0.7756215256634205, + "MONDAY_20" to 0.7984895728860915, + "MONDAY_21" to 0.8918589268832423, + "MONDAY_22" to 0.9967716668541272, + "MONDAY_23" to 1.0973334887144106, + "TUESDAY_0" to 1.2233064209957951, + "TUESDAY_1" to 1.3238883432855082, + "TUESDAY_2" to 1.3874518307497257, + "TUESDAY_3" to 1.463621147171298, + "TUESDAY_4" to 1.4975989065490154, + "TUESDAY_5" to 1.481679186141442, + "TUESDAY_6" to 1.452778387763161, + "TUESDAY_7" to 1.3414858185569951, + "TUESDAY_8" to 1.2869454637983988, + "TUESDAY_9" to 1.249347290389873, + "TUESDAY_10" to 1.196488297386161, + "TUESDAY_11" to 1.1136140507034202, + "TUESDAY_12" to 0.9867528660797885, + "TUESDAY_13" to 0.8018989158195754, + "TUESDAY_14" to 0.6173048748109258, + "TUESDAY_15" to 0.46718586671750373, + "TUESDAY_16" to 0.4103633833041902, + "TUESDAY_17" to 0.4871260756989506, + "TUESDAY_18" to 0.5667378483016126, + "TUESDAY_19" to 0.6464203510900723, + "TUESDAY_20" to 0.7780268325299871, + "TUESDAY_21" to 0.8995921101255763, + "TUESDAY_22" to 1.0077600114996088, + "TUESDAY_23" to 1.1109769960680498, + "WEDNESDAY_0" to 1.2097668746150059, + "WEDNESDAY_1" to 1.2631002319009361, + "WEDNESDAY_2" to 1.2912775191940549, + "WEDNESDAY_3" to 1.3229785939630059, + "WEDNESDAY_4" to 1.3428607301494424, + "WEDNESDAY_5" to 1.3750788517823973, + "WEDNESDAY_6" to 1.3752344527256497, + "WEDNESDAY_7" to 1.3505490078766218, + "WEDNESDAY_8" to 1.2598503219367945, + "WEDNESDAY_9" to 1.2051668977452374, + "WEDNESDAY_10" to 1.0320896222195326, + "WEDNESDAY_11" to 0.8900138031631949, + "WEDNESDAY_12" to 0.6341155208698448, + "WEDNESDAY_13" to 0.48337590254714624, + "WEDNESDAY_14" to 0.2903189399226416, + "WEDNESDAY_15" to 0.25, + "WEDNESDAY_16" to 0.25711039485046006, + "WEDNESDAY_17" to 0.37307641907591793, + "WEDNESDAY_18" to 0.45280799454961196, + "WEDNESDAY_19" to 0.5631397823847637, + "WEDNESDAY_20" to 0.6285005244224133, + "WEDNESDAY_21" to 0.6671897537279405, + "WEDNESDAY_22" to 0.7268406397452634, + "WEDNESDAY_23" to 0.8068904097486369, + "THURSDAY_0" to 0.9021601102971811, + "THURSDAY_1" to 1.023741688964238, + "THURSDAY_2" to 1.1340689935096755, + "THURSDAY_3" to 1.2530130345819006, + "THURSDAY_4" to 1.3163421664973542, + "THURSDAY_5" to 1.3536343767230727, + "THURSDAY_6" to 1.3432290485306728, + "THURSDAY_7" to 1.2864983218982178, + "THURSDAY_8" to 1.2320488534113174, + "THURSDAY_9" to 1.1984530721079034, + "THURSDAY_10" to 1.0877338251341975, + "THURSDAY_11" to 0.9999324929016475, + "THURSDAY_12" to 0.87536726762619, + "THURSDAY_13" to 0.6560822412167919, + "THURSDAY_14" to 0.44836474861432074, + "THURSDAY_15" to 0.36145134935025247, + "THURSDAY_16" to 0.2695997829759713, + "THURSDAY_17" to 0.2898426312618241, + "THURSDAY_18" to 0.3970093434340387, + "THURSDAY_19" to 0.5193273246848977, + "THURSDAY_20" to 0.6426415257034419, + "THURSDAY_21" to 0.800685718218497, + "THURSDAY_22" to 0.9215516833839711, + "THURSDAY_23" to 1.053701659160912, + "FRIDAY_0" to 1.149649788723893, + "FRIDAY_1" to 1.2046315447861193, + "FRIDAY_2" to 1.2724031281576726, + "FRIDAY_3" to 1.3525693456352732, + "FRIDAY_4" to 1.3746126314960814, + "FRIDAY_5" to 1.3744591862592468, + "FRIDAY_6" to 1.3297812543035683, + "FRIDAY_7" to 1.2762064429631657, + "FRIDAY_8" to 1.235662409263294, + "FRIDAY_9" to 1.2171558028785991, + "FRIDAY_10" to 1.182722399785398, + "FRIDAY_11" to 1.137345538963285, + "FRIDAY_12" to 0.9999308422620752, + "FRIDAY_13" to 0.8055000309055653, + "FRIDAY_14" to 0.5667135273493851, + "FRIDAY_15" to 0.4081529603000651, + "FRIDAY_16" to 0.3987031354907009, + "FRIDAY_17" to 0.5030075499003412, + "FRIDAY_18" to 0.6518159532641841, + "FRIDAY_19" to 0.8733483414970974, + "FRIDAY_20" to 1.0496224913080463, + "FRIDAY_21" to 1.1820684558591705, + "FRIDAY_22" to 1.2561688567574458, + "FRIDAY_23" to 1.3204704912328773, + "SATURDAY_0" to 1.3832230236620218, + "SATURDAY_1" to 1.4632908341022142, + "SATURDAY_2" to 1.5019230781315296, + "SATURDAY_3" to 1.5437332506007084, + "SATURDAY_4" to 1.5934153179751855, + "SATURDAY_5" to 1.6245578072557723, + "SATURDAY_6" to 1.6294919789890665, + "SATURDAY_7" to 1.6027665451672717, + "SATURDAY_8" to 1.6068061069158674, + "SATURDAY_9" to 1.624257927970777, + "SATURDAY_10" to 1.5996112411089, + "SATURDAY_11" to 1.5659672993092648, + "SATURDAY_12" to 1.5333537902522736, + "SATURDAY_13" to 1.445292929996356, + "SATURDAY_14" to 1.2966021477035259, + "SATURDAY_15" to 1.250999408961155, + "SATURDAY_16" to 1.2535364828163025, + "SATURDAY_17" to 1.2736456128871074, + "SATURDAY_18" to 1.3348268054897328, + "SATURDAY_19" to 1.4571388900094875, + "SATURDAY_20" to 1.5073787902995706, + "SATURDAY_21" to 1.5605139580010123, + "SATURDAY_22" to 1.5885303316932382, + "SATURDAY_23" to 1.6169891066719597 +) diff --git a/coordinator/app/src/test/kotlin/net/consensys/zkevm/coordinator/app/config/ExpectedTracesLimitsV1.kt b/coordinator/app/src/test/kotlin/net/consensys/zkevm/coordinator/app/config/ExpectedTracesLimitsV1.kt new file mode 100644 index 000000000..f9ac7b943 --- /dev/null +++ b/coordinator/app/src/test/kotlin/net/consensys/zkevm/coordinator/app/config/ExpectedTracesLimitsV1.kt @@ -0,0 +1,48 @@ +package net.consensys.zkevm.coordinator.app.config + +import net.consensys.linea.traces.TracesCountersV1 +import net.consensys.linea.traces.TracingModuleV1 + +val expectedTracesCountersV1 = TracesCountersV1( + mapOf( + // EVM Arithmetization Limits + TracingModuleV1.ADD to 1U, + TracingModuleV1.BIN to 2U, + TracingModuleV1.BIN_RT to 3U, + TracingModuleV1.EC_DATA to 4U, + TracingModuleV1.EXT to 5U, + TracingModuleV1.HUB to 6U, + TracingModuleV1.INSTRUCTION_DECODER to 7U, + TracingModuleV1.MMIO to 8U, + TracingModuleV1.MMU to 9U, + TracingModuleV1.MMU_ID to 10U, + TracingModuleV1.MOD to 11U, + TracingModuleV1.MUL to 12U, + TracingModuleV1.MXP to 13U, + TracingModuleV1.PHONEY_RLP to 14U, + TracingModuleV1.PUB_HASH to 15U, + TracingModuleV1.PUB_HASH_INFO to 16U, + TracingModuleV1.PUB_LOG to 17U, + TracingModuleV1.PUB_LOG_INFO to 18U, + TracingModuleV1.RLP to 19U, + TracingModuleV1.ROM to 20U, + TracingModuleV1.SHF to 21U, + TracingModuleV1.SHF_RT to 22U, + TracingModuleV1.TX_RLP to 23U, + TracingModuleV1.WCP to 24U, + // Block Limits + TracingModuleV1.BLOCK_TX to 25U, + TracingModuleV1.BLOCK_L2L1LOGS to 26U, + TracingModuleV1.BLOCK_KECCAK to 27U, + // Precompile Limits + TracingModuleV1.PRECOMPILE_ECRECOVER to 28U, + TracingModuleV1.PRECOMPILE_SHA2 to 29U, + TracingModuleV1.PRECOMPILE_RIPEMD to 30U, + TracingModuleV1.PRECOMPILE_IDENTITY to 31U, + TracingModuleV1.PRECOMPILE_MODEXP to 32U, + TracingModuleV1.PRECOMPILE_ECADD to 32U, + TracingModuleV1.PRECOMPILE_ECMUL to 34U, + TracingModuleV1.PRECOMPILE_ECPAIRING to 35U, + TracingModuleV1.PRECOMPILE_BLAKE2F to 36U + ) +) diff --git a/coordinator/app/src/test/kotlin/net/consensys/zkevm/coordinator/app/config/ExpectedTracesLimitsV2.kt b/coordinator/app/src/test/kotlin/net/consensys/zkevm/coordinator/app/config/ExpectedTracesLimitsV2.kt new file mode 100644 index 000000000..82f6447f9 --- /dev/null +++ b/coordinator/app/src/test/kotlin/net/consensys/zkevm/coordinator/app/config/ExpectedTracesLimitsV2.kt @@ -0,0 +1,60 @@ +package net.consensys.zkevm.coordinator.app.config + +import net.consensys.linea.traces.TracesCountersV2 +import net.consensys.linea.traces.TracingModuleV2 + +val expectedTracesLimitsV2 = TracesCountersV2( + mapOf( + TracingModuleV2.ADD to 1u, + TracingModuleV2.BIN to 2u, + TracingModuleV2.BLAKE_MODEXP_DATA to 3u, + TracingModuleV2.BLOCK_DATA to 4u, + TracingModuleV2.BLOCK_HASH to 5u, + TracingModuleV2.EC_DATA to 6u, + TracingModuleV2.EUC to 7u, + TracingModuleV2.EXP to 8u, + TracingModuleV2.EXT to 9u, + TracingModuleV2.GAS to 10u, + TracingModuleV2.HUB to 11u, + TracingModuleV2.LOG_DATA to 12u, + TracingModuleV2.LOG_INFO to 13u, + TracingModuleV2.MMIO to 14u, + TracingModuleV2.MMU to 15u, + TracingModuleV2.MOD to 16u, + TracingModuleV2.MUL to 18u, + TracingModuleV2.MXP to 19u, + TracingModuleV2.OOB to 20u, + TracingModuleV2.RLP_ADDR to 21u, + TracingModuleV2.RLP_TXN to 22u, + TracingModuleV2.RLP_TXN_RCPT to 23u, + TracingModuleV2.ROM to 24u, + TracingModuleV2.ROM_LEX to 25u, + TracingModuleV2.SHAKIRA_DATA to 26u, + TracingModuleV2.SHF to 27u, + TracingModuleV2.STP to 28u, + TracingModuleV2.TRM to 29u, + TracingModuleV2.TXN_DATA to 30u, + TracingModuleV2.WCP to 31u, + // Reference table limits, set to UInt.MAX_VALUE + TracingModuleV2.BIN_REFERENCE_TABLE to 32u, + TracingModuleV2.INSTRUCTION_DECODER to 33u, + TracingModuleV2.SHF_REFERENCE_TABLE to 34u, + // Precompiles limits + TracingModuleV2.PRECOMPILE_BLAKE_EFFECTIVE_CALLS to 35u, + TracingModuleV2.PRECOMPILE_BLAKE_ROUNDS to 36u, + TracingModuleV2.PRECOMPILE_ECADD_EFFECTIVE_CALLS to 37u, + TracingModuleV2.PRECOMPILE_ECMUL_EFFECTIVE_CALLS to 38u, + TracingModuleV2.PRECOMPILE_ECPAIRING_FINAL_EXPONENTIATIONS to 39u, + TracingModuleV2.PRECOMPILE_ECPAIRING_G2_MEMBERSHIP_CALLS to 40u, + TracingModuleV2.PRECOMPILE_ECPAIRING_MILLER_LOOPS to 41u, + TracingModuleV2.PRECOMPILE_ECRECOVER_EFFECTIVE_CALLS to 42u, + TracingModuleV2.PRECOMPILE_MODEXP_EFFECTIVE_CALLS to 43u, + TracingModuleV2.PRECOMPILE_RIPEMD_BLOCKS to 44u, + TracingModuleV2.PRECOMPILE_SHA2_BLOCKS to 45u, + // Block limits + TracingModuleV2.BLOCK_KECCAK to 46u, + TracingModuleV2.BLOCK_L1_SIZE to 47u, + TracingModuleV2.BLOCK_L2_L1_LOGS to 48u, + TracingModuleV2.BLOCK_TRANSACTIONS to 49u + ) +) diff --git a/coordinator/app/src/test/resources/configs/coordinator-traces-v2-override.config.toml b/coordinator/app/src/test/resources/configs/coordinator-traces-v2-override.config.toml new file mode 100644 index 000000000..c9e01f473 --- /dev/null +++ b/coordinator/app/src/test/resources/configs/coordinator-traces-v2-override.config.toml @@ -0,0 +1,40 @@ +[prover] +[prover.execution] +fs-requests-directory = "/data/prover/v3/execution/requests" +fs-responses-directory = "/data/prover/v3/execution/responses" +[prover.blob-compression] +fs-requests-directory = "/data/prover/v3/compression/requests" +fs-responses-directory = "/data/prover/v3/compression/responses" +[prover.proof-aggregation] +fs-requests-directory = "/data/prover/v3/aggregation/requests" +fs-responses-directory = "/data/prover/v3/aggregation/responses" + +[zk-traces] +eth-api="http://traces-node-v2:8545" + +[traces] +switch-to-linea-besu=true +blob-compressor-version="V1_0_1" +expected-traces-api-version-v2="v0.8.0-rc8" +[traces.counters-v2] +endpoints=["http://traces-node-v2:8545/"] +request-limit-per-endpoint=1 +request-retry.backoff-delay="PT1S" +request-retry.failures-warning-threshold=2 +[traces.conflation-v2] +endpoints=["http://traces-node-v2:8545/"] +request-limit-per-endpoint=1 +request-retry.backoff-delay="PT1S" +request-retry.failures-warning-threshold=2 + +[l2-network-gas-pricing.json-rpc-pricing-propagation] +geth-gas-price-update-recipients=[ + "http://l2-node:8545/" +] + +[l2-network-gas-pricing.legacy.sample-transaction-gas-pricing] +plain-transfer-cost-multiplier=1.0 +# Ratio of 350 / 29400 is based on data from Mainnet. Only 0.3% of transactions are less profitable than this +# Meaning 99.7% of transactions will be includable if priced using eth_gasPrice +compressed-tx-size=350 +expected-gas=29400 diff --git a/coordinator/app/src/test/resources/configs/coordinator-web3signer-override.config.toml b/coordinator/app/src/test/resources/configs/coordinator-web3signer-override.config.toml new file mode 100644 index 000000000..b5fd4ef35 --- /dev/null +++ b/coordinator/app/src/test/resources/configs/coordinator-web3signer-override.config.toml @@ -0,0 +1,13 @@ +[finalization-signer] +# Web3j/Web3signer +type="Web3Signer" + +[data-submission-signer] +# Web3j/Web3signer +type="Web3Signer" + +[l2-signer] +# Web3j/Web3signer +type="Web3Signer" + + diff --git a/coordinator/app/src/test/resources/configs/coordinator.config.toml b/coordinator/app/src/test/resources/configs/coordinator.config.toml new file mode 100644 index 000000000..62ce6851f --- /dev/null +++ b/coordinator/app/src/test/resources/configs/coordinator.config.toml @@ -0,0 +1,292 @@ +testL1Disabled=false + +duplicated-logs-debounce-time="PT15S" + +eip4844-switch-l2-block-number=0 + +[prover] +fs-inprogress-request-writing-suffix = ".inprogress_coordinator_writing" +fs-inprogress-proving-suffix-pattern = ".*\\.inprogress\\.prover.*" +fs-polling-interval = "PT1S" +fs-polling-timeout = "PT10M" +[prover.execution] +fs-requests-directory = "/data/prover/v2/execution/requests" +fs-responses-directory = "/data/prover/v2/execution/responses" +[prover.blob-compression] +fs-requests-directory = "/data/prover/v2/compression/requests" +fs-responses-directory = "/data/prover/v2/compression/responses" +[prover.proof-aggregation] +fs-requests-directory = "/data/prover/v2/aggregation/requests" +fs-responses-directory = "/data/prover/v2/aggregation/responses" +#[prover.new] +#switch-block-number-inclusive=1000 +#[prover.new.execution] +#fs-requests-directory = "/data/prover/v3/execution/requests" +#fs-responses-directory = "/data/prover/v3/execution/responses" +#[prover.new.blob-compression] +#fs-requests-directory = "/data/prover/v3/compression/requests" +#fs-responses-directory = "/data/prover/v3/compression/responses" +#[prover.new.proof-aggregation] +#fs-requests-directory = "/data/prover/v3/aggregation/requests" +#fs-responses-directory = "/data/prover/v3/aggregation/responses" + +[blob-compression] +blob-size-limit=102400 # 100KB +handler-polling-interval="PT1S" +# default batches limit is aggregation-proofs-limit -1 +# batches-limit must be less than or equal to aggregation-proofs-limit-1 +batches-limit=1 + +[zk-traces] +eth-api="http://traces-node:8545" +new-block-polling-interval="PT1S" + +[traces] +switch-to-linea-besu=false +blob-compressor-version="V0_1_0" +raw-execution-traces-version="0.2.0" +expected-traces-api-version="0.2.0" +[traces.counters] +endpoints=["http://traces-api:8080/"] +request-limit-per-endpoint=2 +request-retry.backoff-delay="PT1S" +request-retry.failures-warning-threshold=2 +[traces.conflation] +endpoints=["http://traces-api:8080/"] +request-limit-per-endpoint=2 +request-retry.backoff-delay="PT1S" +request-retry.failures-warning-threshold=2 + + +[traces.file-manager] +traces-file-extension="json.gz" +raw-traces-directory="/data/traces/raw" +non-canonical-raw-traces-directory="/data/traces/raw-non-canonical" +create-non-canonical-directory=true +polling-interval="PT1S" +traces-file-creation-wait-timeout="PT2M" + +[state-manager] +version="2.3.0" +endpoints=["http://shomei:8888/"] +request-limit-per-endpoint=2 +request-retry.backoff-delay="PT2S" +request-retry.failures-warning-threshold=2 + +[type2-state-proof-provider] +endpoints=["http://shomei-frontend:8888/"] +request-retry.backoff-delay="PT1S" +request-retry.failures-warning-threshold=2 + +[api] +observability_port=9545 + +[l1] +rpc-endpoint="http://l1-el-node:8545" +zk-evm-contract-address="0xCf7Ed3AccA5a467e9e704C703E8D87F634fB0Fc9" +finalization-polling-interval="PT6S" +l1-query-block-tag="latest" +gas-limit=10000000 +fee-history-block-count=10 +fee-history-reward-percentile=15 +# Global caps of maxFeePerGas, maxFeePerBlobGas, and maxPriorityFeePerGas +# for L1 transactions regardless of L1 dynamic gas price cap is enabled or not +max-fee-per-gas-cap=100000000000 +max-fee-per-blob-gas-cap=100000000000 +max-priority-fee-per-gas-cap=20000000000 +# The multiplier of global caps for L1 finalization transaction +# E.g. if set as 2.0, it means the global caps of finalization txn +# will always be 2 times higher than that of blob submission txn +gas-price-cap-multiplier-for-finalization=2.0 +# blocks are 2s, this may catch in between blocks +send-message-event-polling-interval="PT1S" +# 10 blocks worth at 2s per block +max-event-scraping-time="PT5S" +# An optional config to define the L1 block time with default as PT12S +block-time="PT1S" # set the same as local L1 block time +block-range-loop-limit=500 +max-messages-to-collect=1000 +finalized-block-tag="latest" +# reset this once we know what to do on dev/UAT +earliest-block=0 +genesis-state-root-hash="0x072ead6777750dc20232d1cee8dc9a395c2d350df4bbaa5096c6f59b214dcecd" +# shnarf for contract V5 +# Keccak256(parentShnarf="0x00...00", snarkHash="0x00...00", +# parentStateRootHash="0x072ead6777750dc20232d1cee8dc9a395c2d350df4bbaa5096c6f59b214dcecd", +# evaludationClaim="0x00...00", evaludationPoint="0x00...00") +genesis-shnarf-v5="0x47452a1b9ebadfe02bdd02f580fa1eba17680d57eec968a591644d05d78ee84f" + +[l2] +rpc-endpoint="http://sequencer:8545" +message-service-address="0xe537D669CA013d86EBeF1D64e40fC74CADC91987" +gas-limit=10000000 +max-fee-per-gas-cap=100000000000 +fee-history-block-count=4 +fee-history-reward-percentile=15 +last-hash-search-window=25 +anchoring-receipt-polling-interval="PT01S" +max-receipt-retries=120 +# Number of children blocks to wait before considering a won't be reverted and elegible for conflation. +# this a workaround to mitigate Geth fork issues with Clique PoA +# Coordinator will consider block as finalized after being included in the chain wtih children blocks-to-finalization +# Recommended: Geth sequencer minimum of 2, Besu sequencer minimum of 1, 0 is safe localy +blocks-to-finalization=0 + +[blob-submission] +disabled=true +db-polling-interval="PT1S" +max-blobs-to-return=100 +proof-submission-delay="PT1S" +max-blobs-to-submit-per-tick=10 +# These lower and upper bounds will be effective only if L1 dynamic +# gas price cap is disabled or during fallback when there's insufficient +# cached fee history data to compute dynamic gas price caps +priority-fee-per-gas-upper-bound=2000000000 # 2 GWEI +priority-fee-per-gas-lower-bound=200000000 # 0.2 GWEI + +[aggregation-finalization] +disabled=false +db-polling-interval="PT1S" +max-aggregations-to-finalize-per-tick=1 +proof-submission-delay="PT1S" + +[proof-aggregation] +aggregation-proofs-limit=3 +aggregation-deadline="PT10S" +aggregation-coordinator-polling-interval="PT2S" +deadline-check-interval="PT8S" +target-end-blocks=[] + +[finalization-signer] +# Web3j/Web3signer +type="Web3j" + +[finalization-signer.web3j] +private-key="0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d" + +[finalization-signer.web3signer] +endpoint="http://web3signer:9000" +max-pool-size=10 +keep-alive=true +public-key="ba5734d8f7091719471e7f7ed6b9df170dc70cc661ca05e688601ad984f068b0d67351e5f06073092499336ab0839ef8a521afd334e53807205fa2f08eec74f4" + +[data-submission-signer] +# Web3j/Web3signer +type="Web3j" + +# The account with this private key is in genesis file +[data-submission-signer.web3j] +private-key="0x5de4111afa1a4b94908f83103eb1f1706367c2e68ca870fc3fb9a804cdab365a" + +[data-submission-signer.web3signer] +endpoint="http://web3signer:9000" +max-pool-size=10 +keep-alive=true +public-key="9d9031e97dd78ff8c15aa86939de9b1e791066a0224e331bc962a2099a7b1f0464b8bbafe1535f2301c72c2cb3535b172da30b02686ab0393d348614f157fbdb" + +[l2-signer] +# Web3j/Web3signer +type="Web3j" + +[l2-signer.web3j] +private-key="0x4d01ae6487860981699236a58b68f807ee5f17b12df5740b85cf4c4653be0f55" + +[l2-signer.web3signer] +endpoint="http://web3signer:9000" +max-pool-size=10 +keep-alive=true +public-key="4a788ad6fa008beed58de6418369717d7492f37d173d70e2c26d9737e2c6eeae929452ef8602a19410844db3e200a0e73f5208fd76259a8766b73953fc3e7023" + +[message-anchoring-service] +disabled=false +polling-interval="PT1S" +max-messages-to-anchor=100 + +[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://l2-node:8545/" +] +besu-gas-price-update-recipients = [] + +[l1-dynamic-gas-price-cap-service] +disabled=false +[l1-dynamic-gas-price-cap-service.gas-price-cap-calculation] +adjustment-constant=25 +blob-adjustment-constant=25 +finalization-target-max-delay="PT30S" +gas-fee-percentile-window="PT1M" +gas-fee-percentile-window-leeway="PT10S" +gas-fee-percentile=10 +gas-price-caps-check-coefficient=0.9 +# The lower bound of the "historic base fee per blob gas" used in +# the L1 dynamic gas price cap equation +historic-base-fee-per-blob-gas-lower-bound=100000000 # 0.1 GWEI +# An optional config to replace the "historic average reward" used in +# the L1 dynamic gas price cap equation +historic-avg-reward-constant=100000000 # 0.1 GWEI +[l1-dynamic-gas-price-cap-service.fee-history-fetcher] +fetch-interval="PT1S" +max-block-count=1000 +reward-percentiles=[10,20,30,40,50,60,70,80,90,100] +num-of-blocks-before-latest=4 +[l1-dynamic-gas-price-cap-service.fee-history-storage] +storage-period="PT2M" + +[conflation] +blocks-limit=2 +conflation-deadline="PT6S" # =3*l2_block_time +conflation-deadline-check-interval="PT3S" +conflation-deadline-last-block-confirmation-delay="PT2S" # recommended: at least 2 * blockInterval + +# This is to prevent inflight trasactions that may change Smart contract state while coordinator is restarted. +# Queries SMC for last finalised block, and keeps polling until this number of blocks observe the same state. +# If state is updated meanwhile, it resets counter and restarts the polling. +consistent-number-of-blocks-on-l1-to-wait=1 +fetch-blocks-limit=4000 + +[database] +host="postgres" +port="5432" +username="postgres" +password="postgres" +schema="linea_coordinator" +read_pool_size=10 +read_pipelining_limit=10 +transactional_pool_size=10 + +[persistence-retry] +#max-retries = 10 commented as can be null +backoff-delay = "PT1S" diff --git a/coordinator/app/src/test/resources/configs/gas-price-cap-time-of-day-multipliers.toml b/coordinator/app/src/test/resources/configs/gas-price-cap-time-of-day-multipliers.toml new file mode 100644 index 000000000..36155bd6b --- /dev/null +++ b/coordinator/app/src/test/resources/configs/gas-price-cap-time-of-day-multipliers.toml @@ -0,0 +1,184 @@ +## +# Time of day multipliers for dynamic gas price cap calculation: +# +# TDM stands for "Time of Day Mutliplier" and has a range of values between 0.25 - 1.75. +# +# When we expect the L1 gas price to be low, for example on a Saturday night, the TDM will be at it's highest because +# we want to increase the rate at which we increase the threshold to try and settle within this time window. +# The value will be at it's lowest during peak L1 gas price times, for example, on a Tuesday afternoon, because we +# know it is likely to be expensive during this window. +# +# The values for the TDM based on the 90D of L1 gas price real world data. It is expected that every few months +# we will update this table with the latest data to account for any notable changes in the trends of L1 gas prices. +# It does not account for public holidays yet. +## + +[gas-price-cap-time-of-day-multipliers] +SUNDAY_0 = 1.7489178377946066 +SUNDAY_1 = 1.7494632175198737 +SUNDAY_2 = 1.75 +SUNDAY_3 = 1.733166295438555 +SUNDAY_4 = 1.6993775444542885 +SUNDAY_5 = 1.6350086618091364 +SUNDAY_6 = 1.5627740860151331 +SUNDAY_7 = 1.4831149222064164 +SUNDAY_8 = 1.4101476768256929 +SUNDAY_9 = 1.370085278922007 +SUNDAY_10 = 1.3516015544068651 +SUNDAY_11 = 1.3482404546676368 +SUNDAY_12 = 1.3580905751578942 +SUNDAY_13 = 1.3775497419563296 +SUNDAY_14 = 1.3700255667542938 +SUNDAY_15 = 1.2642948506461285 +SUNDAY_16 = 1.2794806131912935 +SUNDAY_17 = 1.2750892256476676 +SUNDAY_18 = 1.2919720208955585 +SUNDAY_19 = 1.317984990098603 +SUNDAY_20 = 1.4433501639513178 +SUNDAY_21 = 1.4705921238901998 +SUNDAY_22 = 1.515043370430801 +SUNDAY_23 = 1.5556742617266397 +MONDAY_0 = 1.5381562278760164 +MONDAY_1 = 1.5423761828433993 +MONDAY_2 = 1.539015963719092 +MONDAY_3 = 1.487676153648977 +MONDAY_4 = 1.430973985132037 +MONDAY_5 = 1.4656765439056292 +MONDAY_6 = 1.4484298622828233 +MONDAY_7 = 1.4459076216659752 +MONDAY_8 = 1.4899061835032241 +MONDAY_9 = 1.5249733712852067 +MONDAY_10 = 1.511367489481033 +MONDAY_11 = 1.4225695658047797 +MONDAY_12 = 1.2887291896624584 +MONDAY_13 = 1.1460926897291355 +MONDAY_14 = 1.0004897955233254 +MONDAY_15 = 0.8694664537368378 +MONDAY_16 = 0.8270273375962802 +MONDAY_17 = 0.7868289022833883 +MONDAY_18 = 0.7780303121746551 +MONDAY_19 = 0.7756215256634205 +MONDAY_20 = 0.7984895728860915 +MONDAY_21 = 0.8918589268832423 +MONDAY_22 = 0.9967716668541272 +MONDAY_23 = 1.0973334887144106 +TUESDAY_0 = 1.2233064209957951 +TUESDAY_1 = 1.3238883432855082 +TUESDAY_2 = 1.3874518307497257 +TUESDAY_3 = 1.463621147171298 +TUESDAY_4 = 1.4975989065490154 +TUESDAY_5 = 1.481679186141442 +TUESDAY_6 = 1.452778387763161 +TUESDAY_7 = 1.3414858185569951 +TUESDAY_8 = 1.2869454637983988 +TUESDAY_9 = 1.249347290389873 +TUESDAY_10 = 1.196488297386161 +TUESDAY_11 = 1.1136140507034202 +TUESDAY_12 = 0.9867528660797885 +TUESDAY_13 = 0.8018989158195754 +TUESDAY_14 = 0.6173048748109258 +TUESDAY_15 = 0.46718586671750373 +TUESDAY_16 = 0.4103633833041902 +TUESDAY_17 = 0.4871260756989506 +TUESDAY_18 = 0.5667378483016126 +TUESDAY_19 = 0.6464203510900723 +TUESDAY_20 = 0.7780268325299871 +TUESDAY_21 = 0.8995921101255763 +TUESDAY_22 = 1.0077600114996088 +TUESDAY_23 = 1.1109769960680498 +WEDNESDAY_0 = 1.2097668746150059 +WEDNESDAY_1 = 1.2631002319009361 +WEDNESDAY_2 = 1.2912775191940549 +WEDNESDAY_3 = 1.3229785939630059 +WEDNESDAY_4 = 1.3428607301494424 +WEDNESDAY_5 = 1.3750788517823973 +WEDNESDAY_6 = 1.3752344527256497 +WEDNESDAY_7 = 1.3505490078766218 +WEDNESDAY_8 = 1.2598503219367945 +WEDNESDAY_9 = 1.2051668977452374 +WEDNESDAY_10 = 1.0320896222195326 +WEDNESDAY_11 = 0.8900138031631949 +WEDNESDAY_12 = 0.6341155208698448 +WEDNESDAY_13 = 0.48337590254714624 +WEDNESDAY_14 = 0.2903189399226416 +WEDNESDAY_15 = 0.25 +WEDNESDAY_16 = 0.25711039485046006 +WEDNESDAY_17 = 0.37307641907591793 +WEDNESDAY_18 = 0.45280799454961196 +WEDNESDAY_19 = 0.5631397823847637 +WEDNESDAY_20 = 0.6285005244224133 +WEDNESDAY_21 = 0.6671897537279405 +WEDNESDAY_22 = 0.7268406397452634 +WEDNESDAY_23 = 0.8068904097486369 +THURSDAY_0 = 0.9021601102971811 +THURSDAY_1 = 1.023741688964238 +THURSDAY_2 = 1.1340689935096755 +THURSDAY_3 = 1.2530130345819006 +THURSDAY_4 = 1.3163421664973542 +THURSDAY_5 = 1.3536343767230727 +THURSDAY_6 = 1.3432290485306728 +THURSDAY_7 = 1.2864983218982178 +THURSDAY_8 = 1.2320488534113174 +THURSDAY_9 = 1.1984530721079034 +THURSDAY_10 = 1.0877338251341975 +THURSDAY_11 = 0.9999324929016475 +THURSDAY_12 = 0.87536726762619 +THURSDAY_13 = 0.6560822412167919 +THURSDAY_14 = 0.44836474861432074 +THURSDAY_15 = 0.36145134935025247 +THURSDAY_16 = 0.2695997829759713 +THURSDAY_17 = 0.2898426312618241 +THURSDAY_18 = 0.3970093434340387 +THURSDAY_19 = 0.5193273246848977 +THURSDAY_20 = 0.6426415257034419 +THURSDAY_21 = 0.800685718218497 +THURSDAY_22 = 0.9215516833839711 +THURSDAY_23 = 1.053701659160912 +FRIDAY_0 = 1.149649788723893 +FRIDAY_1 = 1.2046315447861193 +FRIDAY_2 = 1.2724031281576726 +FRIDAY_3 = 1.3525693456352732 +FRIDAY_4 = 1.3746126314960814 +FRIDAY_5 = 1.3744591862592468 +FRIDAY_6 = 1.3297812543035683 +FRIDAY_7 = 1.2762064429631657 +FRIDAY_8 = 1.235662409263294 +FRIDAY_9 = 1.2171558028785991 +FRIDAY_10 = 1.182722399785398 +FRIDAY_11 = 1.137345538963285 +FRIDAY_12 = 0.9999308422620752 +FRIDAY_13 = 0.8055000309055653 +FRIDAY_14 = 0.5667135273493851 +FRIDAY_15 = 0.4081529603000651 +FRIDAY_16 = 0.3987031354907009 +FRIDAY_17 = 0.5030075499003412 +FRIDAY_18 = 0.6518159532641841 +FRIDAY_19 = 0.8733483414970974 +FRIDAY_20 = 1.0496224913080463 +FRIDAY_21 = 1.1820684558591705 +FRIDAY_22 = 1.2561688567574458 +FRIDAY_23 = 1.3204704912328773 +SATURDAY_0 = 1.3832230236620218 +SATURDAY_1 = 1.4632908341022142 +SATURDAY_2 = 1.5019230781315296 +SATURDAY_3 = 1.5437332506007084 +SATURDAY_4 = 1.5934153179751855 +SATURDAY_5 = 1.6245578072557723 +SATURDAY_6 = 1.6294919789890665 +SATURDAY_7 = 1.6027665451672717 +SATURDAY_8 = 1.6068061069158674 +SATURDAY_9 = 1.624257927970777 +SATURDAY_10 = 1.5996112411089 +SATURDAY_11 = 1.5659672993092648 +SATURDAY_12 = 1.5333537902522736 +SATURDAY_13 = 1.445292929996356 +SATURDAY_14 = 1.2966021477035259 +SATURDAY_15 = 1.250999408961155 +SATURDAY_16 = 1.2535364828163025 +SATURDAY_17 = 1.2736456128871074 +SATURDAY_18 = 1.3348268054897328 +SATURDAY_19 = 1.4571388900094875 +SATURDAY_20 = 1.5073787902995706 +SATURDAY_21 = 1.5605139580010123 +SATURDAY_22 = 1.5885303316932382 +SATURDAY_23 = 1.6169891066719597 diff --git a/coordinator/app/src/test/resources/configs/smart-contract-errors.toml b/coordinator/app/src/test/resources/configs/smart-contract-errors.toml new file mode 100644 index 000000000..1de93403e --- /dev/null +++ b/coordinator/app/src/test/resources/configs/smart-contract-errors.toml @@ -0,0 +1,10 @@ +## +# Smart contract error codes from: +# https://www.notion.so/consensys/Smart-Contracts-Error-Code-Registry-bb4bd68f8ddf4b0ba90000d1136e42ef +## + +[smart-contract-errors] +# L1 Linea Rollup +"0f06cd15" = "DataAlreadySubmitted" +"c01eab56" = "EmptySubmissionData" +"abefa5e8" = "DataStartingBlockDoesNotMatch" diff --git a/coordinator/app/src/test/resources/configs/traces-limits-v1.toml b/coordinator/app/src/test/resources/configs/traces-limits-v1.toml new file mode 100644 index 000000000..e7c727a80 --- /dev/null +++ b/coordinator/app/src/test/resources/configs/traces-limits-v1.toml @@ -0,0 +1,40 @@ +[traces-limits] +# EVM Arithmetization Limits +ADD = 1 +BIN = 2 +BIN_RT = 3 +EC_DATA = 4 +EXT = 5 +HUB = 6 +INSTRUCTION_DECODER = 7 +MMIO = 8 +MMU = 9 +MMU_ID = 10 +MOD = 11 +MUL = 12 +MXP = 13 +PHONEY_RLP = 14 +PUB_HASH = 15 +PUB_HASH_INFO = 16 +PUB_LOG = 17 +PUB_LOG_INFO = 18 +RLP = 19 +ROM = 20 +SHF = 21 +SHF_RT = 22 +TX_RLP = 23 +WCP = 24 +# Block Limits +BLOCK_TX = 25 +BLOCK_L2L1LOGS = 26 +BLOCK_KECCAK = 27 +# Precompile Limits +PRECOMPILE_ECRECOVER = 28 +PRECOMPILE_SHA2 = 29 +PRECOMPILE_RIPEMD = 30 +PRECOMPILE_IDENTITY = 31 +PRECOMPILE_MODEXP = 32 +PRECOMPILE_ECADD = 32 +PRECOMPILE_ECMUL = 34 +PRECOMPILE_ECPAIRING = 35 +PRECOMPILE_BLAKE2F = 36 diff --git a/coordinator/app/src/test/resources/configs/traces-limits-v2.toml b/coordinator/app/src/test/resources/configs/traces-limits-v2.toml new file mode 100644 index 000000000..5ece38b4b --- /dev/null +++ b/coordinator/app/src/test/resources/configs/traces-limits-v2.toml @@ -0,0 +1,53 @@ +[traces-limits] +# Arithmetization module limits +ADD = 1 +BIN = 2 +BLAKE_MODEXP_DATA = 3 +BLOCK_DATA = 4 +BLOCK_HASH = 5 +EC_DATA = 6 +EUC = 7 +EXP = 8 +EXT = 9 +GAS = 10 +HUB = 11 +LOG_DATA = 12 +LOG_INFO = 13 +MMIO = 14 +MMU = 15 +MOD = 16 +MUL = 18 +MXP = 19 +OOB = 20 +RLP_ADDR = 21 +RLP_TXN = 22 +RLP_TXN_RCPT = 23 +ROM = 24 +ROM_LEX = 25 +SHAKIRA_DATA = 26 +SHF = 27 +STP = 28 +TRM = 29 +TXN_DATA = 30 +WCP = 31 +# Reference table limits, set to UInt.MAX_VALUE +BIN_REFERENCE_TABLE = 32 +INSTRUCTION_DECODER = 33 +SHF_REFERENCE_TABLE = 34 +# Precompiles limits +PRECOMPILE_BLAKE_EFFECTIVE_CALLS = 35 +PRECOMPILE_BLAKE_ROUNDS = 36 +PRECOMPILE_ECADD_EFFECTIVE_CALLS = 37 +PRECOMPILE_ECMUL_EFFECTIVE_CALLS = 38 +PRECOMPILE_ECPAIRING_FINAL_EXPONENTIATIONS = 39 +PRECOMPILE_ECPAIRING_G2_MEMBERSHIP_CALLS = 40 +PRECOMPILE_ECPAIRING_MILLER_LOOPS = 41 +PRECOMPILE_ECRECOVER_EFFECTIVE_CALLS = 42 +PRECOMPILE_MODEXP_EFFECTIVE_CALLS = 43 +PRECOMPILE_RIPEMD_BLOCKS = 44 +PRECOMPILE_SHA2_BLOCKS = 45 +# Block limits +BLOCK_KECCAK = 46 +BLOCK_L1_SIZE = 47 +BLOCK_L2_L1_LOGS = 48 +BLOCK_TRANSACTIONS = 49 From d29cdd4030100339e4f9b4ee45869e3a82e063f6 Mon Sep 17 00:00:00 2001 From: jonesho <81145364+jonesho@users.noreply.github.com> Date: Wed, 15 Jan 2025 19:13:08 +0800 Subject: [PATCH 6/9] =?UTF-8?q?feat:=20added=20async=20retryer=20for=20cur?= =?UTF-8?q?rentL2BlockNumber=20in=20case=20the=20contra=E2=80=A6=20(#425)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: added async retryer for currentL2BlockNumber in case the contract variable is not initialized yet * feat: revise the use of async retry * feat: use LineaRollupSmartContractClientReadOnly client for last finalized block * feat: use LineaRollupSmartContractClientReadOnly client in FinalizationUpdatePoller * feat: avoid making contract version call during Web3JLineaRollupSmartContractClientReadOnly class init --- .../zkevm/coordinator/app/L1DependentApp.kt | 24 ++----- .../app/LastFinalizedBlockProvider.kt | 65 ++++++++----------- .../L1BasedLastFinalizedBlockProviderTest.kt | 40 +++++------- .../staticcap/FeeHistoryFetcherImpl.kt | 2 +- finalized-tag-updater/build.gradle | 2 +- .../linea/FinalizationUpdatePoller.kt | 49 +++++++------- .../LineaL1FinalizationUpdaterService.kt | 22 +++---- ...JLineaRollupSmartContractClientReadOnly.kt | 7 +- 8 files changed, 87 insertions(+), 124 deletions(-) diff --git a/coordinator/app/src/main/kotlin/net/consensys/zkevm/coordinator/app/L1DependentApp.kt b/coordinator/app/src/main/kotlin/net/consensys/zkevm/coordinator/app/L1DependentApp.kt index 9986f7d07..3dff8e2fb 100644 --- a/coordinator/app/src/main/kotlin/net/consensys/zkevm/coordinator/app/L1DependentApp.kt +++ b/coordinator/app/src/main/kotlin/net/consensys/zkevm/coordinator/app/L1DependentApp.kt @@ -9,7 +9,6 @@ import kotlinx.datetime.Clock import linea.encoding.BlockRLPEncoder import net.consensys.linea.BlockNumberAndHash import net.consensys.linea.blob.ShnarfCalculatorVersion -import net.consensys.linea.contract.LineaRollupAsyncFriendly import net.consensys.linea.contract.Web3JL2MessageService import net.consensys.linea.contract.Web3JL2MessageServiceLogsClient import net.consensys.linea.contract.Web3JLogsClient @@ -220,20 +219,19 @@ class L1DependentApp( ) ) - private val l1FinalizationMonitor = run { - // To avoid setDefaultBlockParameter clashes - val contractClient: LineaRollupSmartContractClientReadOnly = Web3JLineaRollupSmartContractClientReadOnly( - contractAddress = configs.l1.zkEvmContractAddress, - web3j = l1Web3jClient - ) + private val lineaRollupClient: LineaRollupSmartContractClientReadOnly = Web3JLineaRollupSmartContractClientReadOnly( + contractAddress = configs.l1.zkEvmContractAddress, + web3j = l1Web3jClient + ) + private val l1FinalizationMonitor = run { FinalizationMonitorImpl( config = FinalizationMonitorImpl.Config( pollingInterval = configs.l1.finalizationPollingInterval.toKotlinDuration(), l1QueryBlockTag = configs.l1.l1QueryBlockTag ), - contract = contractClient, + contract = lineaRollupClient, l2Client = l2Web3jClient, vertx = vertx ) @@ -922,17 +920,9 @@ class L1DependentApp( } private fun lastFinalizedBlock(): SafeFuture { - val zkEvmClient: LineaRollupAsyncFriendly = instantiateZkEvmContractClient( - configs.l1, - finalizationTransactionManager, - feesFetcher, - l1MinPriorityFeeCalculator, - l1Web3jClient, - smartContractErrors - ) val l1BasedLastFinalizedBlockProvider = L1BasedLastFinalizedBlockProvider( vertx, - zkEvmClient, + lineaRollupClient, configs.conflation.consistentNumberOfBlocksOnL1ToWait.toUInt() ) return l1BasedLastFinalizedBlockProvider.getLastFinalizedBlock() diff --git a/coordinator/app/src/main/kotlin/net/consensys/zkevm/coordinator/app/LastFinalizedBlockProvider.kt b/coordinator/app/src/main/kotlin/net/consensys/zkevm/coordinator/app/LastFinalizedBlockProvider.kt index 74987b5d9..cefdeff19 100644 --- a/coordinator/app/src/main/kotlin/net/consensys/zkevm/coordinator/app/LastFinalizedBlockProvider.kt +++ b/coordinator/app/src/main/kotlin/net/consensys/zkevm/coordinator/app/LastFinalizedBlockProvider.kt @@ -1,14 +1,12 @@ package net.consensys.zkevm.coordinator.app -import build.linea.contract.LineaRollupV5 +import build.linea.contract.l1.LineaRollupSmartContractClientReadOnly import io.vertx.core.Vertx +import net.consensys.linea.BlockParameter import net.consensys.linea.async.AsyncRetryer -import net.consensys.toULong import org.apache.logging.log4j.LogManager import org.apache.logging.log4j.Logger -import org.web3j.protocol.core.DefaultBlockParameterName import tech.pegasys.teku.infrastructure.async.SafeFuture -import java.math.BigInteger import java.util.concurrent.atomic.AtomicInteger import java.util.concurrent.atomic.AtomicReference import kotlin.time.Duration @@ -26,7 +24,7 @@ interface LastFinalizedBlockProvider { */ class L1BasedLastFinalizedBlockProvider( private val vertx: Vertx, - private val lineaRollupSmartContractWeb3jClient: LineaRollupV5, + private val lineaRollupSmartContractClient: LineaRollupSmartContractClientReadOnly, private val consistentNumberOfBlocksOnL1: UInt, private val numberOfRetries: UInt = Int.MAX_VALUE.toUInt(), private val pollingInterval: Duration = 2.seconds @@ -34,42 +32,33 @@ class L1BasedLastFinalizedBlockProvider( private val log: Logger = LogManager.getLogger(this::class.java) override fun getLastFinalizedBlock(): SafeFuture { - lineaRollupSmartContractWeb3jClient.setDefaultBlockParameter(DefaultBlockParameterName.LATEST) - - return SafeFuture.of(lineaRollupSmartContractWeb3jClient.currentL2BlockNumber().sendAsync()) - .thenCompose { blockNumber -> + val lastObservedBlock = AtomicReference(null) + val numberOfObservations = AtomicInteger(1) + val isConsistentEnough = { lastPolledBlockNumber: ULong -> + if (lastPolledBlockNumber == lastObservedBlock.get()) { + numberOfObservations.incrementAndGet().toUInt() >= consistentNumberOfBlocksOnL1 + } else { log.info( - "Rollup lastFinalizedBlockNumber={} waiting {} blocks for confirmation for no updates", - blockNumber, + "Rollup finalized block updated from {} to {}, waiting {} blocks for confirmation", + lastObservedBlock.get(), + lastPolledBlockNumber, consistentNumberOfBlocksOnL1 ) - val lastObservedBlock = AtomicReference(blockNumber) - val numberOfObservations = AtomicInteger(1) - val isConsistentEnough = { lasPolledBlockNumber: BigInteger -> - if (lasPolledBlockNumber == lastObservedBlock.get()) { - numberOfObservations.incrementAndGet().toUInt() >= consistentNumberOfBlocksOnL1 - } else { - log.info( - "Rollup finalized block updated from {} to {}, waiting {} blocks for confirmation", - blockNumber, - lasPolledBlockNumber, - consistentNumberOfBlocksOnL1 - ) - numberOfObservations.set(1) - lastObservedBlock.set(lasPolledBlockNumber) - false - } - } - - AsyncRetryer.retry( - vertx, - maxRetries = numberOfRetries.toInt(), - backoffDelay = pollingInterval, - stopRetriesPredicate = isConsistentEnough - ) { - SafeFuture.of(lineaRollupSmartContractWeb3jClient.currentL2BlockNumber().sendAsync()) - } + numberOfObservations.set(1) + lastObservedBlock.set(lastPolledBlockNumber) + false } - .thenApply { it.toULong() } + } + + return AsyncRetryer.retry( + vertx, + maxRetries = numberOfRetries.toInt(), + backoffDelay = pollingInterval, + stopRetriesPredicate = isConsistentEnough + ) { + lineaRollupSmartContractClient.finalizedL2BlockNumber( + blockParameter = BlockParameter.Tag.LATEST + ) + } } } diff --git a/coordinator/app/src/test/kotlin/net/consensys/zkevm/coordinator/app/L1BasedLastFinalizedBlockProviderTest.kt b/coordinator/app/src/test/kotlin/net/consensys/zkevm/coordinator/app/L1BasedLastFinalizedBlockProviderTest.kt index 6632e7e3a..e9a655e99 100644 --- a/coordinator/app/src/test/kotlin/net/consensys/zkevm/coordinator/app/L1BasedLastFinalizedBlockProviderTest.kt +++ b/coordinator/app/src/test/kotlin/net/consensys/zkevm/coordinator/app/L1BasedLastFinalizedBlockProviderTest.kt @@ -1,42 +1,39 @@ package net.consensys.zkevm.coordinator.app -import build.linea.contract.LineaRollupV5 +import build.linea.contract.l1.LineaRollupSmartContractClientReadOnly import io.vertx.core.Vertx +import net.consensys.linea.BlockParameter import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test -import org.mockito.kotlin.doReturn +import org.mockito.Mockito +import org.mockito.kotlin.eq import org.mockito.kotlin.mock import org.mockito.kotlin.whenever -import org.web3j.protocol.core.RemoteFunctionCall -import java.math.BigInteger -import java.util.concurrent.CompletableFuture +import tech.pegasys.teku.infrastructure.async.SafeFuture import kotlin.time.Duration.Companion.milliseconds class L1BasedLastFinalizedBlockProviderTest { - private lateinit var lineaRollupSmartContractWeb3jClient: LineaRollupV5 + private lateinit var lineaRollupClient: LineaRollupSmartContractClientReadOnly @BeforeEach fun beforeEach() { - lineaRollupSmartContractWeb3jClient = mock() + lineaRollupClient = + mock(defaultAnswer = Mockito.RETURNS_DEEP_STUBS) } @Test fun `shall wait number of blocks before returning for consistency`() { - val replies = listOf( - mockRemoteFnCallWithBlockNumber(100), - mockRemoteFnCallWithBlockNumber(100), - mockRemoteFnCallWithBlockNumber(101), - mockRemoteFnCallWithBlockNumber(101), - mockRemoteFnCallWithBlockNumber(101), - mockRemoteFnCallWithBlockNumber(101) - ) - whenever(lineaRollupSmartContractWeb3jClient.currentL2BlockNumber()) - .thenReturn(replies[0], *replies.subList(1, replies.size).toTypedArray()) + val replies = listOf(100UL, 100UL, 101UL, 101UL, 101UL, 101UL) + whenever(lineaRollupClient.finalizedL2BlockNumber(eq(BlockParameter.Tag.LATEST))) + .thenReturn( + SafeFuture.completedFuture(replies[0]), + *replies.subList(1, replies.size).map { SafeFuture.completedFuture(it) }.toTypedArray() + ) val resumerCalculator = L1BasedLastFinalizedBlockProvider( Vertx.vertx(), - lineaRollupSmartContractWeb3jClient, + lineaRollupClient, consistentNumberOfBlocksOnL1 = 3u, numberOfRetries = 50u, pollingInterval = 10.milliseconds @@ -44,11 +41,4 @@ class L1BasedLastFinalizedBlockProviderTest { assertThat(resumerCalculator.getLastFinalizedBlock().get()).isEqualTo(101.toULong()) } - - private fun mockRemoteFnCallWithBlockNumber(blockNumber: Long): RemoteFunctionCall { - return mock>() { - on { send() } doReturn (BigInteger.valueOf(blockNumber)) - on { sendAsync() } doReturn (CompletableFuture.completedFuture(BigInteger.valueOf(blockNumber))) - } - } } diff --git a/coordinator/ethereum/gas-pricing/static-cap/src/main/kotlin/net/consensys/linea/ethereum/gaspricing/staticcap/FeeHistoryFetcherImpl.kt b/coordinator/ethereum/gas-pricing/static-cap/src/main/kotlin/net/consensys/linea/ethereum/gaspricing/staticcap/FeeHistoryFetcherImpl.kt index a2ee341a2..147fc03d8 100644 --- a/coordinator/ethereum/gas-pricing/static-cap/src/main/kotlin/net/consensys/linea/ethereum/gaspricing/staticcap/FeeHistoryFetcherImpl.kt +++ b/coordinator/ethereum/gas-pricing/static-cap/src/main/kotlin/net/consensys/linea/ethereum/gaspricing/staticcap/FeeHistoryFetcherImpl.kt @@ -31,7 +31,7 @@ class FeeHistoryFetcherImpl( } private var cacheIsValidForBlockNumber: BigInteger = BigInteger.ZERO - private var feesCache: FeeHistory = getRecentFees().get() + private lateinit var feesCache: FeeHistory private fun getRecentFees(): SafeFuture { val blockNumberFuture = web3jClient.ethBlockNumber().sendAsync() diff --git a/finalized-tag-updater/build.gradle b/finalized-tag-updater/build.gradle index 93f922a19..ad44e7f66 100644 --- a/finalized-tag-updater/build.gradle +++ b/finalized-tag-updater/build.gradle @@ -40,7 +40,7 @@ dependencies { implementation project(':jvm-libs:linea:core:long-running-service') implementation project(':jvm-libs:generic:extensions:futures') implementation project(':jvm-libs:linea:web3j-extensions') - implementation 'build.linea:l1-rollup-contract-client:6.0.0-rc2' + implementation project(':jvm-libs:linea:clients:linea-l1-contract-client') implementation ("org.web3j:core:${libs.versions.web3j.get()}") { exclude group: 'org.slf4j', module: 'slf4j-nop' } diff --git a/finalized-tag-updater/src/main/kotlin/net/consensys/linea/FinalizationUpdatePoller.kt b/finalized-tag-updater/src/main/kotlin/net/consensys/linea/FinalizationUpdatePoller.kt index c67889061..57cffeca6 100644 --- a/finalized-tag-updater/src/main/kotlin/net/consensys/linea/FinalizationUpdatePoller.kt +++ b/finalized-tag-updater/src/main/kotlin/net/consensys/linea/FinalizationUpdatePoller.kt @@ -1,14 +1,13 @@ package net.consensys.zkevm.ethereum.finalization -import build.linea.contract.LineaRollupV5 +import build.linea.contract.l1.Web3JLineaRollupSmartContractClientReadOnly import io.vertx.core.Vertx +import net.consensys.linea.BlockParameter +import net.consensys.linea.async.AsyncRetryer import net.consensys.linea.async.toSafeFuture -import net.consensys.toULong import net.consensys.zkevm.PeriodicPollingService import org.apache.logging.log4j.LogManager import org.apache.logging.log4j.Logger -import org.web3j.protocol.core.DefaultBlockParameter -import org.web3j.protocol.core.DefaultBlockParameterName import tech.pegasys.teku.infrastructure.async.SafeFuture import java.util.concurrent.CompletableFuture import java.util.concurrent.atomic.AtomicReference @@ -17,24 +16,19 @@ import kotlin.time.Duration.Companion.seconds data class FinalizationUpdatePollerConfig( val pollingInterval: Duration = 12.seconds, - val blockTag: String + val blockTag: BlockParameter ) { init { require(pollingInterval >= 0.seconds) { "pollingInterval must be greater than 0" } - - require(DefaultBlockParameterName.fromString(blockTag) != null) { - "Invalid blockTag='$blockTag', " + - "valid values: ${DefaultBlockParameterName.values().joinToString(", ")}" - } } } class FinalizationUpdatePoller( - vertx: Vertx, - config: FinalizationUpdatePollerConfig, - private val lineaRollup: LineaRollupV5, + private val vertx: Vertx, + private val config: FinalizationUpdatePollerConfig, + private val lineaRollup: Web3JLineaRollupSmartContractClientReadOnly, private val finalizationHandler: (ULong) -> CompletableFuture<*>, private val log: Logger = LogManager.getLogger(FinalizationUpdatePoller::class.java) ) : PeriodicPollingService( @@ -44,22 +38,23 @@ class FinalizationUpdatePoller( ) { private val lastFinalizationRef: AtomicReference = AtomicReference(null) - init { - lineaRollup.setDefaultBlockParameter(DefaultBlockParameter.valueOf(config.blockTag)) - } - override fun action(): SafeFuture<*> { - return lineaRollup.currentL2BlockNumber().sendAsync() - .thenCompose { lineaFinalizedBlockNumber -> - val prevFinalizedBlockNumber = lastFinalizationRef.get() - lastFinalizationRef.set(lineaFinalizedBlockNumber.toULong()) - if (prevFinalizedBlockNumber != lineaFinalizedBlockNumber.toULong()) { - finalizationHandler(lineaFinalizedBlockNumber.toULong()).thenApply { Unit } - } else { - CompletableFuture.completedFuture(Unit) + return AsyncRetryer.retry( + vertx, + backoffDelay = config.pollingInterval + ) { + lineaRollup.finalizedL2BlockNumber(config.blockTag) + .thenCompose { lineaFinalizedBlockNumber -> + val prevFinalizedBlockNumber = lastFinalizationRef.get() + lastFinalizationRef.set(lineaFinalizedBlockNumber.toULong()) + if (prevFinalizedBlockNumber != lineaFinalizedBlockNumber.toULong()) { + finalizationHandler(lineaFinalizedBlockNumber.toULong()).thenApply { Unit } + } else { + CompletableFuture.completedFuture(Unit) + } } - } - .toSafeFuture() + .toSafeFuture() + } } override fun handleError(error: Throwable) { diff --git a/finalized-tag-updater/src/main/kotlin/net/consensys/linea/LineaL1FinalizationUpdaterService.kt b/finalized-tag-updater/src/main/kotlin/net/consensys/linea/LineaL1FinalizationUpdaterService.kt index a1585ea9a..75674a236 100644 --- a/finalized-tag-updater/src/main/kotlin/net/consensys/linea/LineaL1FinalizationUpdaterService.kt +++ b/finalized-tag-updater/src/main/kotlin/net/consensys/linea/LineaL1FinalizationUpdaterService.kt @@ -1,6 +1,6 @@ package net.consensys.linea -import build.linea.contract.LineaRollupV5 +import build.linea.contract.l1.Web3JLineaRollupSmartContractClientReadOnly import io.vertx.core.Vertx import net.consensys.linea.consensus.EngineBlockTagUpdater import net.consensys.linea.web3j.okHttpClientBuilder @@ -8,15 +8,11 @@ import net.consensys.zkevm.LongRunningService import net.consensys.zkevm.ethereum.finalization.FinalizationUpdatePoller import net.consensys.zkevm.ethereum.finalization.FinalizationUpdatePollerConfig import org.apache.logging.log4j.LogManager -import org.apache.tuweni.bytes.Bytes import org.hyperledger.besu.plugin.services.BlockchainService import org.slf4j.Logger import org.slf4j.LoggerFactory -import org.web3j.crypto.Credentials import org.web3j.protocol.Web3j import org.web3j.protocol.http.HttpService -import org.web3j.tx.gas.StaticGasProvider -import java.math.BigInteger import java.util.concurrent.CompletableFuture class LineaBesuEngineBlockTagUpdater(private val blockchainService: BlockchainService) : EngineBlockTagUpdater { @@ -27,7 +23,11 @@ class LineaBesuEngineBlockTagUpdater(private val blockchainService: BlockchainSe if (!finalizedBlock.isEmpty) { try { val blockHash = finalizedBlock.get().blockHeader.blockHash - log.info("Linea safe/finalized block update: blockNumber={} blockHash={}", finalizedBlockNumber, blockHash) + log.info( + "Linea safe/finalized block update: blockNumber={} blockHash={}", + finalizedBlockNumber, + blockHash + ) blockchainService.setSafeBlock(blockHash) blockchainService.setFinalizedBlock(blockHash) return true @@ -86,18 +86,16 @@ class LineaL1FinalizationUpdaterService( okHttpClientBuilder(LogManager.getLogger("clients.l1")).build() ) ) - private val lineaRollup = LineaRollupV5.load( - config.l1SmartContractAddress.toHexString(), - web3j, - Credentials.create(Bytes.random(64).toHexString()), - StaticGasProvider(BigInteger.valueOf(50000000000L), BigInteger.valueOf(60000000L)) + private val lineaRollup = Web3JLineaRollupSmartContractClientReadOnly( + contractAddress = config.l1SmartContractAddress.toHexString(), + web3j = web3j ) private val updater = LineaL1FinalizationUpdater(engineBlockTagUpdater) private val poller = FinalizationUpdatePoller( vertx, FinalizationUpdatePollerConfig( pollingInterval = config.l1PollingInterval, - blockTag = "finalized" + blockTag = BlockParameter.Tag.FINALIZED ), lineaRollup, updater::handleL1Finalization, diff --git a/jvm-libs/linea/clients/linea-l1-contract-client/src/main/kotlin/build/linea/contract/l1/Web3JLineaRollupSmartContractClientReadOnly.kt b/jvm-libs/linea/clients/linea-l1-contract-client/src/main/kotlin/build/linea/contract/l1/Web3JLineaRollupSmartContractClientReadOnly.kt index 0d74736ef..34c05faef 100644 --- a/jvm-libs/linea/clients/linea-l1-contract-client/src/main/kotlin/build/linea/contract/l1/Web3JLineaRollupSmartContractClientReadOnly.kt +++ b/jvm-libs/linea/clients/linea-l1-contract-client/src/main/kotlin/build/linea/contract/l1/Web3JLineaRollupSmartContractClientReadOnly.kt @@ -63,8 +63,7 @@ open class Web3JLineaRollupSmartContractClientReadOnly( } as T } - protected val smartContractVersionCache: AtomicReference = - AtomicReference(fetchSmartContractVersion().get()) + private val smartContractVersionCache = AtomicReference(null) private fun getSmartContractVersion(): SafeFuture { return if (smartContractVersionCache.get() == LineaContractVersion.V6) { @@ -73,7 +72,9 @@ open class Web3JLineaRollupSmartContractClientReadOnly( } else { fetchSmartContractVersion() .thenPeek { contractLatestVersion -> - if (contractLatestVersion != smartContractVersionCache.get()) { + if (smartContractVersionCache.get() != null && + contractLatestVersion != smartContractVersionCache.get() + ) { log.info( "Smart contract upgraded: prevVersion={} upgradedVersion={}", smartContractVersionCache.get(), From fe967c703b9e5f43098a4961dd4c2e6d5e3e5480 Mon Sep 17 00:00:00 2001 From: Pedro Novais <1478752+jpnovais@users.noreply.github.com> Date: Thu, 16 Jan 2025 10:16:39 +0000 Subject: [PATCH 7/9] State recover part 4 (#324) * statereover: adds working StateRecoverApp, besu-plugin and Integration tests --------- Signed-off-by: Pedro Novais <1478752+jpnovais@users.noreply.github.com> Co-authored-by: jonesho <81145364+jonesho@users.noreply.github.com> --- Makefile | 22 +- build.gradle | 5 +- .../coordinator-docker.config.toml | 10 +- .../zkevm/coordinator/app/L1DependentApp.kt | 2 +- .../coordinator/app/SwitchProviderImplTest.kt | 2 +- .../FileBasedExecutionProverClientV2.kt | 2 +- .../smart-contract-client/build.gradle | 3 +- .../contract/Web3JContractAsyncHelper.kt | 6 +- .../Web3JL2MessageServiceLogsClient.kt | 1 + .../BlobAndAggregationFinalizationIntTest.kt | 3 +- .../ethereum/submission/SwitchProviderImpl.kt | 2 +- .../zkevm/ethereum/AccountManager.kt | 2 +- docker/compose.yml | 102 ++++ docker/config/linea-local-dev-genesis.json | 147 ------ docker/config/shomei/log4j.xml | 2 +- docker/config/traces-node-v2/log4j.xml | 2 +- .../traces-node-v2/traces-node-v2-config.toml | 2 +- .../zkbesu-shomei/log4j-staterecovery.xml | 53 ++ docker/config/zkbesu-shomei/log4j.xml | 2 +- docker/linea-sepolia/genesis.json | 4 +- docker/scripts/file-downloader.sh | 25 - gradle/libs.versions.toml | 4 +- .../kotlin/net/consensys/TypingsExtensions.kt | 10 + .../linea/jsonrpc/TestingJsonRpcServer.kt | 2 +- .../kotlin/linea/logging/TimeMeasureLogger.kt | 38 ++ .../logging/JsonRpcRequestResponseLogger.kt | 35 +- .../logging/MinimalInLineJsonRpcLoggerTest.kt | 7 +- .../s11n/jackson/InstantAsHexNumberSerDe.kt | 21 + .../linea/s11n/jackson/InstantISO8601SerDe.kt | 1 - .../jackson/InstantAsHexNumberSerDeTest.kt | 56 +++ jvm-libs/linea/besu-libs/build.gradle | 24 +- .../linea/besu-rlp-and-mappers/build.gradle | 3 + jvm-libs/linea/blob-compressor/build.gradle | 4 + .../main/kotlin/linea/blob/BlobCompressor.kt | 6 + .../linea/blob/GoBackedBlobCompressorTest.kt | 12 +- ...iveCompressorAndShnarfCalculatorIntTest.kt | 10 +- .../nativecompressor/CompressorTestData.kt | 32 +- .../TestDataGeneratorHelper.kt | 70 +++ .../src/testFixtures/resources/blocks_rlp.bin | Bin 0 -> 42062 bytes .../src/testFixtures/resources/rlp_blocks.bin | Bin 57530 -> 0 bytes .../blob/GoNativeBlobDecompressorTest.kt | 2 +- .../src/main/kotlin/linea/EthLogsSearcher.kt | 32 ++ .../main/kotlin/linea/domain/RetryConfig.kt | 32 ++ .../kotlin/linea/domain/RetryConfigTest.kt | 58 +++ .../linea/testing/filesystem/Files.kt | 2 +- jvm-libs/linea/web3j-extensions/build.gradle | 8 +- .../build/linea/web3j}/Web3JLogsClient.kt | 2 +- .../main/kotlin/linea/web3j/SearchCursor.kt | 87 ++++ .../kotlin/linea/web3j/Web3JLogsSearcher.kt | 209 ++++++++ .../linea/web3j}/Web3JLogsClientIntTest.kt | 2 +- .../build/linea/web3j}/Web3JLogsClientTest.kt | 2 +- .../kotlin/linea/web3j/SearchCursorTest.kt | 191 +++++++ .../linea/web3j/ULongRangesHelperTest.kt | 117 +++++ .../linea/web3j/Web3JLogsSearcherIntTest.kt | 472 ++++++++++++++++++ .../src/test}/resources/log4j2.xml | 8 +- settings.gradle | 6 +- .../appcore/clients-interfaces/build.gradle | 1 + .../clients/ExecutionLayerClient.kt | 12 - .../staterecover}/BlobFetcher.kt | 2 +- .../staterecover/ExecutionLayerClient.kt | 16 + .../staterecover/RecoveryStatusPersistence.kt | 81 +++ .../staterecover/TransactionDetailsClient.kt | 7 + .../FileRecoveryStatusPersistenceTest.kt | 87 ++++ .../TransactionL1RecoveredData.kt | 74 --- .../staterecover/BlockFromL1RecoveredData.kt} | 71 ++- .../TransactionFromL1RecoveredData.kt | 103 ++++ state-recover/appcore/logic/build.gradle | 27 + .../BlobDecompressorAndDeserializer.kt | 144 ++++++ .../linea/staterecover/BlockImporter.kt | 77 +++ .../LineaSubmissionEventsClient.kt | 6 +- .../LineaSubmissionEventsClientImpl.kt} | 157 +++--- .../linea/staterecover/StateRecoverApp.kt | 192 +++++++ .../staterecover/StateSynchronizerService.kt | 163 ++++++ .../BlobDecompressorAndDeserializerV1Test.kt | 137 +++++ state-recover/besu-plugin/build.gradle | 71 +++ .../clients/ExecutionLayerInProcessClient.kt | 110 ++++ .../staterecover/plugin/AppConfigurator.kt | 93 ++++ .../staterecover/plugin/BlockContextData.kt | 13 + .../staterecover/plugin/BlockImporter.kt | 122 +++++ .../plugin/LineaStateRecoverPlugin.kt | 127 +++++ .../staterecover/plugin/PluginOptions.kt | 107 ++++ .../plugin/RecoveryModeManager.kt | 103 ++++ .../staterecover/plugin/TransactionMapper.kt | 75 +++ .../org.hyperledger.besu.plugin.BesuPlugin | 1 + .../clients/blobscan-client/build.gradle | 2 +- .../clients/blobscan/BlobScanClient.kt | 12 +- .../clients/blobscan/VertxRestClient.kt | 54 +- .../clients/blobscan/BlobScanClientTest.kt | 2 +- state-recover/clients/eth-api/build.gradle | 11 + .../clients/VertxTransactionDetailsClient.kt | 50 ++ .../clients/el/ExecutionLayerJsonRpcClient.kt | 62 ++- .../el/ExecutionLayerJsonRpcClientTest.kt | 153 +++++- state-recover/test-cases/build.gradle | 82 +++ .../LineaSubmissionEventsClientIntTest.kt | 30 +- .../staterecover/StateRecoverAppIntTest.kt | 207 ++++++++ ...ecoverAppWithFakeExecutionClientIntTest.kt | 298 +++++++++++ ...RecoveryManualReplayToLocalStackIntTest.kt | 152 ++++++ .../src/integrationTest/resources/log4j2.xml | 30 ++ .../test/FakeExecutionLayerClient.kt | 73 +++ ...keStateManagerClientBasedOnBlobsRecords.kt | 91 ++++ ...erSepoliaWithFakeExecutionClientIntTest.kt | 173 +++++++ .../src/test/resources/vertx-options.json | 15 + ...e872c798b03287eb-getZkAggregatedProof.json | 1 + ...4efd1ec39e60dee1-getZkAggregatedProof.json | 1 + ...b0ed37bf8560eb30-getZkAggregatedProof.json | 1 + ...018ba10e05f52759-getZkAggregatedProof.json | 1 + ...69a1f0981e66fb78-getZkAggregatedProof.json | 1 + ...69175cc9976f4fa4-getZkAggregatedProof.json | 1 + ...41b2e59ca659669a-getZkAggregatedProof.json | 1 + ...df3d6da896186a1e-getZkAggregatedProof.json | 1 + ...bfb166d316bd4825-getZkAggregatedProof.json | 1 + ...759ffca6bd3fed3c-getZkAggregatedProof.json | 1 + ...b9cf5bc245e8982c-getZkAggregatedProof.json | 1 + ...d7ecf32710e3be87-getZkAggregatedProof.json | 1 + ...d6f19734f5e0c88c-getZkAggregatedProof.json | 1 + ...b63279b2ba7f0f2c-getZkAggregatedProof.json | 1 + ...97356d8baedc3e65-getZkAggregatedProof.json | 1 + ...ca536dedd6d4e2ba-getZkAggregatedProof.json | 1 + ...1c8a3f7d977-getZkBlobCompressionProof.json | 1 + ...11f7aefd9e7-getZkBlobCompressionProof.json | 1 + ...945eff7044c-getZkBlobCompressionProof.json | 1 + ...40c8f48b837-getZkBlobCompressionProof.json | 1 + ...7d3a32358c7-getZkBlobCompressionProof.json | 1 + ...f2f3f6bbe5b-getZkBlobCompressionProof.json | 1 + ...3bd9afc921d-getZkBlobCompressionProof.json | 1 + ...e50dddd3f8c-getZkBlobCompressionProof.json | 1 + ...914f2246831-getZkBlobCompressionProof.json | 1 + ...e151d4e2ee8-getZkBlobCompressionProof.json | 1 + ...c5ce4210446-getZkBlobCompressionProof.json | 1 + ...4c83a91b025-getZkBlobCompressionProof.json | 1 + ...4941cf04695-getZkBlobCompressionProof.json | 1 + ...df7e88387da-getZkBlobCompressionProof.json | 1 + ...83f6f2b8061-getZkBlobCompressionProof.json | 1 + ...eea9a7d39cb-getZkBlobCompressionProof.json | 1 + ...f758482aed7-getZkBlobCompressionProof.json | 1 + 135 files changed, 5124 insertions(+), 549 deletions(-) delete mode 100644 docker/config/linea-local-dev-genesis.json create mode 100644 docker/config/zkbesu-shomei/log4j-staterecovery.xml delete mode 100644 docker/scripts/file-downloader.sh create mode 100644 jvm-libs/generic/logging/src/main/kotlin/linea/logging/TimeMeasureLogger.kt create mode 100644 jvm-libs/generic/serialization/jackson/src/main/kotlin/build/linea/s11n/jackson/InstantAsHexNumberSerDe.kt create mode 100644 jvm-libs/generic/serialization/jackson/src/test/kotlin/build/linea/s11n/jackson/InstantAsHexNumberSerDeTest.kt create mode 100644 jvm-libs/linea/blob-compressor/src/testFixtures/kotlin/net/consensys/linea/nativecompressor/TestDataGeneratorHelper.kt create mode 100644 jvm-libs/linea/blob-compressor/src/testFixtures/resources/blocks_rlp.bin delete mode 100644 jvm-libs/linea/blob-compressor/src/testFixtures/resources/rlp_blocks.bin create mode 100644 jvm-libs/linea/clients/interfaces/src/main/kotlin/linea/EthLogsSearcher.kt create mode 100644 jvm-libs/linea/core/domain-models/src/main/kotlin/linea/domain/RetryConfig.kt create mode 100644 jvm-libs/linea/core/domain-models/src/test/kotlin/linea/domain/RetryConfigTest.kt rename {coordinator/clients/smart-contract-client/src/main/kotlin/net/consensys/linea/contract => jvm-libs/linea/web3j-extensions/src/main/kotlin/build/linea/web3j}/Web3JLogsClient.kt (98%) create mode 100644 jvm-libs/linea/web3j-extensions/src/main/kotlin/linea/web3j/SearchCursor.kt create mode 100644 jvm-libs/linea/web3j-extensions/src/main/kotlin/linea/web3j/Web3JLogsSearcher.kt rename {coordinator/clients/smart-contract-client/src/test/kotlin/net/consensys/linea/contract => jvm-libs/linea/web3j-extensions/src/test/kotlin/build/linea/web3j}/Web3JLogsClientIntTest.kt (99%) rename {coordinator/clients/smart-contract-client/src/test/kotlin/net/consensys/linea/contract => jvm-libs/linea/web3j-extensions/src/test/kotlin/build/linea/web3j}/Web3JLogsClientTest.kt (99%) create mode 100644 jvm-libs/linea/web3j-extensions/src/test/kotlin/linea/web3j/SearchCursorTest.kt create mode 100644 jvm-libs/linea/web3j-extensions/src/test/kotlin/linea/web3j/ULongRangesHelperTest.kt create mode 100644 jvm-libs/linea/web3j-extensions/src/test/kotlin/linea/web3j/Web3JLogsSearcherIntTest.kt rename {state-recover/clients/smartcontract/src/integrationTest => jvm-libs/linea/web3j-extensions/src/test}/resources/log4j2.xml (64%) delete mode 100644 state-recover/appcore/clients-interfaces/src/main/kotlin/build/linea/staterecover/clients/ExecutionLayerClient.kt rename state-recover/appcore/clients-interfaces/src/main/kotlin/{build/linea/staterecover/clients => linea/staterecover}/BlobFetcher.kt (81%) create mode 100644 state-recover/appcore/clients-interfaces/src/main/kotlin/linea/staterecover/ExecutionLayerClient.kt create mode 100644 state-recover/appcore/clients-interfaces/src/main/kotlin/linea/staterecover/RecoveryStatusPersistence.kt create mode 100644 state-recover/appcore/clients-interfaces/src/main/kotlin/linea/staterecover/TransactionDetailsClient.kt create mode 100644 state-recover/appcore/clients-interfaces/src/test/kotlin/linea/staterecover/FileRecoveryStatusPersistenceTest.kt delete mode 100644 state-recover/appcore/domain-models/src/main/kotlin/build/linea/staterecover/TransactionL1RecoveredData.kt rename state-recover/appcore/domain-models/src/main/kotlin/{build/linea/staterecover/BlockL1RecoveredData.kt => linea/staterecover/BlockFromL1RecoveredData.kt} (68%) create mode 100644 state-recover/appcore/domain-models/src/main/kotlin/linea/staterecover/TransactionFromL1RecoveredData.kt create mode 100644 state-recover/appcore/logic/build.gradle create mode 100644 state-recover/appcore/logic/src/main/kotlin/linea/staterecover/BlobDecompressorAndDeserializer.kt create mode 100644 state-recover/appcore/logic/src/main/kotlin/linea/staterecover/BlockImporter.kt rename state-recover/appcore/{clients-interfaces/src/main/kotlin/build/linea/staterecover/clients => logic/src/main/kotlin/linea/staterecover}/LineaSubmissionEventsClient.kt (94%) rename state-recover/{clients/smartcontract/src/main/kotlin/linea/build/staterecover/clients/smartcontract/LineaSubmissionEventsClientWeb3jIpml.kt => appcore/logic/src/main/kotlin/linea/staterecover/LineaSubmissionEventsClientImpl.kt} (54%) create mode 100644 state-recover/appcore/logic/src/main/kotlin/linea/staterecover/StateRecoverApp.kt create mode 100644 state-recover/appcore/logic/src/main/kotlin/linea/staterecover/StateSynchronizerService.kt create mode 100644 state-recover/appcore/logic/src/test/kotlin/linea/staterecover/BlobDecompressorAndDeserializerV1Test.kt create mode 100644 state-recover/besu-plugin/build.gradle create mode 100644 state-recover/besu-plugin/src/main/kotlin/linea/staterecover/clients/ExecutionLayerInProcessClient.kt create mode 100644 state-recover/besu-plugin/src/main/kotlin/linea/staterecover/plugin/AppConfigurator.kt create mode 100644 state-recover/besu-plugin/src/main/kotlin/linea/staterecover/plugin/BlockContextData.kt create mode 100644 state-recover/besu-plugin/src/main/kotlin/linea/staterecover/plugin/BlockImporter.kt create mode 100644 state-recover/besu-plugin/src/main/kotlin/linea/staterecover/plugin/LineaStateRecoverPlugin.kt create mode 100644 state-recover/besu-plugin/src/main/kotlin/linea/staterecover/plugin/PluginOptions.kt create mode 100644 state-recover/besu-plugin/src/main/kotlin/linea/staterecover/plugin/RecoveryModeManager.kt create mode 100644 state-recover/besu-plugin/src/main/kotlin/linea/staterecover/plugin/TransactionMapper.kt create mode 100644 state-recover/besu-plugin/src/main/resources/META-INF/services/org.hyperledger.besu.plugin.BesuPlugin rename state-recover/clients/blobscan-client/src/main/kotlin/{build => }/linea/staterecover/clients/blobscan/BlobScanClient.kt (82%) rename state-recover/clients/blobscan-client/src/main/kotlin/{build => }/linea/staterecover/clients/blobscan/VertxRestClient.kt (52%) rename state-recover/clients/blobscan-client/src/test/kotlin/{build => }/linea/staterecover/clients/blobscan/BlobScanClientTest.kt (99%) create mode 100644 state-recover/clients/eth-api/build.gradle create mode 100644 state-recover/clients/eth-api/src/main/kotlin/linea/build/staterecover/clients/VertxTransactionDetailsClient.kt create mode 100644 state-recover/test-cases/build.gradle rename state-recover/{clients/smartcontract/src/integrationTest/kotlin/linea/build/staterecover/clients/smartcontract => test-cases/src/integrationTest/kotlin/linea/staterecover}/LineaSubmissionEventsClientIntTest.kt (88%) create mode 100644 state-recover/test-cases/src/integrationTest/kotlin/linea/staterecover/StateRecoverAppIntTest.kt create mode 100644 state-recover/test-cases/src/integrationTest/kotlin/linea/staterecover/StateRecoverAppWithFakeExecutionClientIntTest.kt create mode 100644 state-recover/test-cases/src/integrationTest/kotlin/linea/staterecover/StateRecoveryManualReplayToLocalStackIntTest.kt create mode 100644 state-recover/test-cases/src/integrationTest/resources/log4j2.xml create mode 100644 state-recover/test-cases/src/main/kotlin/linea/staterecover/test/FakeExecutionLayerClient.kt create mode 100644 state-recover/test-cases/src/main/kotlin/linea/staterecover/test/FakeStateManagerClientBasedOnBlobsRecords.kt create mode 100644 state-recover/test-cases/src/test/kotlin/linea/staterecover/StateRecoverSepoliaWithFakeExecutionClientIntTest.kt create mode 100644 state-recover/test-cases/src/test/resources/vertx-options.json create mode 100644 testdata/coordinator/prover/v3/aggregation/responses/1-3-c582331fee9d97bf39b11a6681579c5478097d4af5eb2c97e872c798b03287eb-getZkAggregatedProof.json create mode 100644 testdata/coordinator/prover/v3/aggregation/responses/11-13-523fe0caa8ea09a3787268f8bc8cfdbf9005d1e527ed656c4efd1ec39e60dee1-getZkAggregatedProof.json create mode 100644 testdata/coordinator/prover/v3/aggregation/responses/14-16-193b46cfdb687e208772c266f87c91e78a3edb1e02de9888b0ed37bf8560eb30-getZkAggregatedProof.json create mode 100644 testdata/coordinator/prover/v3/aggregation/responses/17-19-b615854a9075e73fdbdb0f22367d8e48c36997b28857712f018ba10e05f52759-getZkAggregatedProof.json create mode 100644 testdata/coordinator/prover/v3/aggregation/responses/20-22-9e033347194ecf686585d4ddc81a602edc9afa61c9d8437c69a1f0981e66fb78-getZkAggregatedProof.json create mode 100644 testdata/coordinator/prover/v3/aggregation/responses/23-25-1cdd5b5dd6cf38f123b1de80eb1d86ce47ba28a9689930db69175cc9976f4fa4-getZkAggregatedProof.json create mode 100644 testdata/coordinator/prover/v3/aggregation/responses/26-28-655573aeabb826867531dedc1510fd1c7540e871ce2da96641b2e59ca659669a-getZkAggregatedProof.json create mode 100644 testdata/coordinator/prover/v3/aggregation/responses/29-31-411b174b8760f03354ec0ae215a6caae21472b0788600ab1df3d6da896186a1e-getZkAggregatedProof.json create mode 100644 testdata/coordinator/prover/v3/aggregation/responses/32-34-bb1a9a83d812c5a46ade32842936de46f693f72c2a2f314abfb166d316bd4825-getZkAggregatedProof.json create mode 100644 testdata/coordinator/prover/v3/aggregation/responses/35-37-061a9f803c029a06b7b594602ea76d6cf6d9737c25ee5215759ffca6bd3fed3c-getZkAggregatedProof.json create mode 100644 testdata/coordinator/prover/v3/aggregation/responses/38-40-5239c241ba71475fe11f8a4dfc04addf97c874a9bc2a371bb9cf5bc245e8982c-getZkAggregatedProof.json create mode 100644 testdata/coordinator/prover/v3/aggregation/responses/4-6-ef72701818f1320dce22734cac21e65af315dd84dbb57e4ad7ecf32710e3be87-getZkAggregatedProof.json create mode 100644 testdata/coordinator/prover/v3/aggregation/responses/41-43-c9a80177215ac57e589cf92189846270b286b70bd3845e8ed6f19734f5e0c88c-getZkAggregatedProof.json create mode 100644 testdata/coordinator/prover/v3/aggregation/responses/44-46-78d88bad483bfe5a8f9e8fd1d3af3cb034d6248aa279b764b63279b2ba7f0f2c-getZkAggregatedProof.json create mode 100644 testdata/coordinator/prover/v3/aggregation/responses/7-7-aa133bea94f49f4edbfe7488b1a7394ed2559243139ca15097356d8baedc3e65-getZkAggregatedProof.json create mode 100644 testdata/coordinator/prover/v3/aggregation/responses/8-10-487dc52c1e22d32a1c38917b99ed120ddffdcb5effa6c5ecca536dedd6d4e2ba-getZkAggregatedProof.json create mode 100644 testdata/coordinator/prover/v3/compression/responses/1-3-c185fbadf462de3a6c8517cbac3ba7402a14e939e1d77e3a515ca1c8a3f7d977-getZkBlobCompressionProof.json create mode 100644 testdata/coordinator/prover/v3/compression/responses/11-13-e5f194ad53779deb52c2455e216ca447a842026238fd8143cbb7911f7aefd9e7-getZkBlobCompressionProof.json create mode 100644 testdata/coordinator/prover/v3/compression/responses/14-16-8de7b2d25ebb3dd54040cc30cbe3a6333053816812bb33dca470e945eff7044c-getZkBlobCompressionProof.json create mode 100644 testdata/coordinator/prover/v3/compression/responses/17-19-343fef4cdcb6d0ab0db8ea7da91820c8d21a80135608b990c0b4f40c8f48b837-getZkBlobCompressionProof.json create mode 100644 testdata/coordinator/prover/v3/compression/responses/20-22-aea706d4657966f8e30e918e1097ffa0da19513b0be56a243cabd7d3a32358c7-getZkBlobCompressionProof.json create mode 100644 testdata/coordinator/prover/v3/compression/responses/23-25-268a263e550eb02c8196d4b9e3cc06a55d87018f2e20ed7304da5f2f3f6bbe5b-getZkBlobCompressionProof.json create mode 100644 testdata/coordinator/prover/v3/compression/responses/26-28-06851ec1f1ba875ffd3a08fa5b2f0d88ac9426c9ccd852973abe73bd9afc921d-getZkBlobCompressionProof.json create mode 100644 testdata/coordinator/prover/v3/compression/responses/29-31-0602578e3a61f2be5afdd3ee34c6ac99e1e36a50450c75ef9dd78e50dddd3f8c-getZkBlobCompressionProof.json create mode 100644 testdata/coordinator/prover/v3/compression/responses/32-34-a646621c48d374488e214c7e02a64d431ae0712f3bc817a3d5943914f2246831-getZkBlobCompressionProof.json create mode 100644 testdata/coordinator/prover/v3/compression/responses/35-37-86dc4abc4be5dfa0ddf8f4b8b98783973bbcd82b5ceff8d39361fe151d4e2ee8-getZkBlobCompressionProof.json create mode 100644 testdata/coordinator/prover/v3/compression/responses/38-40-dec8e24af04a4aa184d63b3f68066b7633c2099aa042bcb37a234c5ce4210446-getZkBlobCompressionProof.json create mode 100644 testdata/coordinator/prover/v3/compression/responses/4-6-513ed85de5604294e15b683fb22532c07a25531d93f402f17bb4a4c83a91b025-getZkBlobCompressionProof.json create mode 100644 testdata/coordinator/prover/v3/compression/responses/41-43-67b48d2e3c30f21caaffe8677e9c8a84f43ae1e7ee936f0f8c03c4941cf04695-getZkBlobCompressionProof.json create mode 100644 testdata/coordinator/prover/v3/compression/responses/44-46-e3c210adb4a5b495db0a285094885c32b74bd6cc85bbe0e0b5a6cdf7e88387da-getZkBlobCompressionProof.json create mode 100644 testdata/coordinator/prover/v3/compression/responses/47-47-dc73dc616fccf89ba4b33ba446a9b73b5a1836142e0b1be933b7283f6f2b8061-getZkBlobCompressionProof.json create mode 100644 testdata/coordinator/prover/v3/compression/responses/7-7-7db9a7cbfd21211ecd77d8791894eca4478be04c38002a415dce9eea9a7d39cb-getZkBlobCompressionProof.json create mode 100644 testdata/coordinator/prover/v3/compression/responses/8-10-e6a7703511076e3789cc25059b468940b2e91df262f11b95b9005f758482aed7-getZkBlobCompressionProof.json diff --git a/Makefile b/Makefile index 0621cca0b..5e8251a43 100644 --- a/Makefile +++ b/Makefile @@ -158,10 +158,12 @@ deploy-l2-evm-opcode-tester: RPC_URL=http:\\localhost:8545/ \ npx ts-node local-deployments-artifacts/deployLondonEvmTestingFramework.ts -execute-all-opcodes: + +evm-opcode-tester-execute-all-opcodes: OPCODE_TEST_CONTRACT_ADDRESS:=0x997FC3aF1F193Cbdc013060076c67A13e218980e +evm-opcode-tester-execute-all-opcodes: # WARNING: FOR LOCAL DEV ONLY - DO NOT REUSE THESE KEYS ELSEWHERE cd contracts/; \ - OPCODE_TEST_CONTRACT_ADDRESS=0x997FC3aF1F193Cbdc013060076c67A13e218980e \ + OPCODE_TEST_CONTRACT_ADDRESS=$(OPCODE_TEST_CONTRACT_ADDRESS) \ NUMBER_OF_RUNS=3 \ PRIVATE_KEY=0x1dd171cec7e2995408b5513004e8207fe88d6820aeff0d82463b3e41df251aae \ RPC_URL=http:\\localhost:8545/ \ @@ -216,11 +218,17 @@ deploy-contracts-minimal: cd .. && \ $(MAKE) -j6 deploy-linea-rollup-v$(L1_CONTRACT_VERSION) deploy-l2messageservice -start-all-staterecover: L1_CONTRACT_VERSION:=6 -start-all-staterecover: COMPOSE_PROFILES:=l1,l2,staterecover -start-all-staterecover: - L1_GENESIS_TIME=$(get_future_time) make start-whole-environment COMPOSE_PROFILES=$(COMPOSE_PROFILES) - make deploy-contracts-minimal L1_CONTRACT_VERSION=$(L1_CONTRACT_VERSION) +fresh-start-all-staterecover: COMPOSE_PROFILES:=l1,l2,staterecover +fresh-start-all-staterecover: L1_CONTRACT_VERSION:=6 +fresh-start-all-staterecover: + make clean-environment + L1_GENESIS_TIME=$(get_future_time) make start-whole-environment-traces-v2 COMPOSE_PROFILES=$(COMPOSE_PROFILES) + $(MAKE) deploy-contracts-minimal L1_CONTRACT_VERSION=$(L1_CONTRACT_VERSION) + +fresh-start-staterecover-for-replay-only: COMPOSE_PROFILES:=l1,staterecover +fresh-start-staterecover-for-replay-only: + make clean-environment + L1_GENESIS_TIME=$(get_future_time) make start-whole-environment-traces-v2 COMPOSE_PROFILES=$(COMPOSE_PROFILES) testnet-start-l2: docker compose -f docker/compose.yml -f docker/compose-testnet-sync.overrides.yml --profile l2 up -d diff --git a/build.gradle b/build.gradle index 46307076e..059745aa2 100644 --- a/build.gradle +++ b/build.gradle @@ -87,7 +87,7 @@ allprojects { systemProperty("L1_RPC_URL", "http://localhost:8445") systemProperty("L2_RPC_URL", "http://localhost:8545") systemProperty("L1_GENESIS", "docker/config/l1-node/el/genesis.json") - systemProperty("L2_GENESIS", "docker/config/linea-local-dev-genesis.json") + systemProperty("L2_GENESIS", "docker/config/linea-local-dev-genesis-PoA.json") systemProperties["junit.jupiter.execution.timeout.default"] = "5 m" // 5 minutes systemProperties["junit.jupiter.execution.parallel.enabled"] = true @@ -203,7 +203,8 @@ dockerCompose { "staterecover" ] useComposeFiles = [ - "${project.rootDir.path}/docker/compose.yml" + "${project.rootDir.path}/docker/compose.yml", + "${project.rootDir.path}/docker/compose-local-dev-traces-v2.overrides.yml" ] waitForHealthyStateTimeout = Duration.ofMinutes(3) waitForTcpPorts = false diff --git a/config/coordinator/coordinator-docker.config.toml b/config/coordinator/coordinator-docker.config.toml index 62ce6851f..781bb0b67 100644 --- a/config/coordinator/coordinator-docker.config.toml +++ b/config/coordinator/coordinator-docker.config.toml @@ -126,8 +126,8 @@ fee-history-reward-percentile=15 last-hash-search-window=25 anchoring-receipt-polling-interval="PT01S" max-receipt-retries=120 -# Number of children blocks to wait before considering a won't be reverted and elegible for conflation. -# this a workaround to mitigate Geth fork issues with Clique PoA +# Number of children blocks to wait before considering they won't be reverted and elegible for conflation. +# this is a workaround to mitigate Geth fork issues with Clique PoA # Coordinator will consider block as finalized after being included in the chain wtih children blocks-to-finalization # Recommended: Geth sequencer minimum of 2, Besu sequencer minimum of 1, 0 is safe localy blocks-to-finalization=0 @@ -155,7 +155,7 @@ aggregation-proofs-limit=3 aggregation-deadline="PT10S" aggregation-coordinator-polling-interval="PT2S" deadline-check-interval="PT8S" -target-end-blocks=[] +#target-end-blocks=[33, 90, 93] [finalization-signer] # Web3j/Web3signer @@ -266,8 +266,8 @@ num-of-blocks-before-latest=4 storage-period="PT2M" [conflation] -blocks-limit=2 -conflation-deadline="PT6S" # =3*l2_block_time +blocks-limit=3 +conflation-deadline="PT6S" conflation-deadline-check-interval="PT3S" conflation-deadline-last-block-confirmation-delay="PT2S" # recommended: at least 2 * blockInterval diff --git a/coordinator/app/src/main/kotlin/net/consensys/zkevm/coordinator/app/L1DependentApp.kt b/coordinator/app/src/main/kotlin/net/consensys/zkevm/coordinator/app/L1DependentApp.kt index 3dff8e2fb..4b286a997 100644 --- a/coordinator/app/src/main/kotlin/net/consensys/zkevm/coordinator/app/L1DependentApp.kt +++ b/coordinator/app/src/main/kotlin/net/consensys/zkevm/coordinator/app/L1DependentApp.kt @@ -4,6 +4,7 @@ import build.linea.clients.StateManagerClientV1 import build.linea.clients.StateManagerV1JsonRpcClient import build.linea.contract.l1.LineaRollupSmartContractClientReadOnly import build.linea.contract.l1.Web3JLineaRollupSmartContractClientReadOnly +import build.linea.web3j.Web3JLogsClient import io.vertx.core.Vertx import kotlinx.datetime.Clock import linea.encoding.BlockRLPEncoder @@ -11,7 +12,6 @@ import net.consensys.linea.BlockNumberAndHash import net.consensys.linea.blob.ShnarfCalculatorVersion import net.consensys.linea.contract.Web3JL2MessageService import net.consensys.linea.contract.Web3JL2MessageServiceLogsClient -import net.consensys.linea.contract.Web3JLogsClient import net.consensys.linea.contract.l1.GenesisStateProvider import net.consensys.linea.ethereum.gaspricing.BoundableFeeCalculator import net.consensys.linea.ethereum.gaspricing.FeesCalculator diff --git a/coordinator/app/src/test/kotlin/net/consensys/zkevm/coordinator/app/SwitchProviderImplTest.kt b/coordinator/app/src/test/kotlin/net/consensys/zkevm/coordinator/app/SwitchProviderImplTest.kt index 03c3d81ab..8e6b0d012 100644 --- a/coordinator/app/src/test/kotlin/net/consensys/zkevm/coordinator/app/SwitchProviderImplTest.kt +++ b/coordinator/app/src/test/kotlin/net/consensys/zkevm/coordinator/app/SwitchProviderImplTest.kt @@ -2,12 +2,12 @@ package net.consensys.zkevm.coordinator.app +import build.linea.web3j.Web3JLogsClient import io.vertx.junit5.Timeout import io.vertx.junit5.VertxExtension import io.vertx.junit5.VertxTestContext import net.consensys.linea.contract.EIP1559GasProvider import net.consensys.linea.contract.L2MessageService -import net.consensys.linea.contract.Web3JLogsClient import net.consensys.toULong import net.consensys.zkevm.ethereum.coordination.conflation.upgrade.SwitchProvider import net.consensys.zkevm.ethereum.signing.ECKeypairSigner diff --git a/coordinator/clients/prover-client/file-based-client/src/main/kotlin/net/consensys/zkevm/coordinator/clients/prover/FileBasedExecutionProverClientV2.kt b/coordinator/clients/prover-client/file-based-client/src/main/kotlin/net/consensys/zkevm/coordinator/clients/prover/FileBasedExecutionProverClientV2.kt index c1f34bd22..294c577b4 100644 --- a/coordinator/clients/prover-client/file-based-client/src/main/kotlin/net/consensys/zkevm/coordinator/clients/prover/FileBasedExecutionProverClientV2.kt +++ b/coordinator/clients/prover-client/file-based-client/src/main/kotlin/net/consensys/zkevm/coordinator/clients/prover/FileBasedExecutionProverClientV2.kt @@ -57,7 +57,7 @@ internal class ExecutionProofRequestDataDecorator( return SafeFuture.collectAll(bridgeLogsSfList.stream()) .thenCombine( - getBlockStateRootHash(request.blocks.first().number.toULong() - 1UL) + getBlockStateRootHash(request.blocks.first().number - 1UL) ) { blocksAndBridgeLogs, previousKeccakStateRootHash -> BatchExecutionProofRequestDto( zkParentStateRootHash = request.type2StateData.zkParentStateRootHash.encodeHex(), diff --git a/coordinator/clients/smart-contract-client/build.gradle b/coordinator/clients/smart-contract-client/build.gradle index f1418d28b..5851971dd 100644 --- a/coordinator/clients/smart-contract-client/build.gradle +++ b/coordinator/clients/smart-contract-client/build.gradle @@ -4,7 +4,7 @@ plugins { dependencies { implementation project(":jvm-libs:generic:extensions:kotlin") - implementation project(':jvm-libs:linea:web3j-extensions') + api project(':jvm-libs:linea:web3j-extensions') api project(':jvm-libs:linea:clients:linea-l1-contract-client') api 'build.linea:l2-message-service-contract-client:0.0.1' @@ -15,5 +15,4 @@ dependencies { implementation project(path: ':coordinator:core') implementation project(path: ':coordinator:ethereum:common') testImplementation "io.vertx:vertx-junit5" - testImplementation "com.github.tomakehurst:wiremock-jre8:${libs.versions.wiremock.get()}" } diff --git a/coordinator/clients/smart-contract-client/src/main/kotlin/net/consensys/linea/contract/Web3JContractAsyncHelper.kt b/coordinator/clients/smart-contract-client/src/main/kotlin/net/consensys/linea/contract/Web3JContractAsyncHelper.kt index 2dbf36d8b..f90df0c54 100644 --- a/coordinator/clients/smart-contract-client/src/main/kotlin/net/consensys/linea/contract/Web3JContractAsyncHelper.kt +++ b/coordinator/clients/smart-contract-client/src/main/kotlin/net/consensys/linea/contract/Web3JContractAsyncHelper.kt @@ -254,7 +254,7 @@ class Web3JContractAsyncHelper( dynamicMaxFeePerGas: ULong?, dynamicMaxFeePerBlobGas: ULong? = null ) { - val withBlob = maxFeePerBlobGas != null && dynamicMaxFeePerBlobGas != null + val withBlob = maxFeePerBlobGas != null || dynamicMaxFeePerBlobGas != null log.info( "$logMessagePrefix gas price caps: " + "blobCarrying=$withBlob " + @@ -263,8 +263,8 @@ class Web3JContractAsyncHelper( "maxFeePerGas=${maxFeePerGas.toGWei()} GWei, " + "dynamicMaxFeePerGas=${dynamicMaxFeePerGas?.toGWei()} GWei, " + if (withBlob) { - "maxFeePerBlobGas=${maxFeePerBlobGas!!.toGWei()} GWei, " + - "dynamicMaxFeePerBlobGas=${dynamicMaxFeePerBlobGas!!.toGWei()} GWei" + "maxFeePerBlobGas=${maxFeePerBlobGas?.toGWei()} GWei, " + + "dynamicMaxFeePerBlobGas=${dynamicMaxFeePerBlobGas?.toGWei()} GWei" } else { "" } diff --git a/coordinator/clients/smart-contract-client/src/main/kotlin/net/consensys/linea/contract/Web3JL2MessageServiceLogsClient.kt b/coordinator/clients/smart-contract-client/src/main/kotlin/net/consensys/linea/contract/Web3JL2MessageServiceLogsClient.kt index c41bb8b4e..ee174c634 100644 --- a/coordinator/clients/smart-contract-client/src/main/kotlin/net/consensys/linea/contract/Web3JL2MessageServiceLogsClient.kt +++ b/coordinator/clients/smart-contract-client/src/main/kotlin/net/consensys/linea/contract/Web3JL2MessageServiceLogsClient.kt @@ -1,5 +1,6 @@ package net.consensys.linea.contract +import build.linea.web3j.Web3JLogsClient import net.consensys.toULong import net.consensys.zkevm.coordinator.clients.L2MessageServiceLogsClient import net.consensys.zkevm.domain.BridgeLogsData diff --git a/coordinator/ethereum/blob-submitter/src/integrationTest/kotlin/net/consensys/zkevm/ethereum/finalization/BlobAndAggregationFinalizationIntTest.kt b/coordinator/ethereum/blob-submitter/src/integrationTest/kotlin/net/consensys/zkevm/ethereum/finalization/BlobAndAggregationFinalizationIntTest.kt index 51733bbd5..88876b55e 100644 --- a/coordinator/ethereum/blob-submitter/src/integrationTest/kotlin/net/consensys/zkevm/ethereum/finalization/BlobAndAggregationFinalizationIntTest.kt +++ b/coordinator/ethereum/blob-submitter/src/integrationTest/kotlin/net/consensys/zkevm/ethereum/finalization/BlobAndAggregationFinalizationIntTest.kt @@ -185,7 +185,8 @@ class BlobAndAggregationFinalizationIntTest : CleanDbTestSuiteParallel() { val blobsEndTime = blobs.last().endBlockTime val endTime = if (aggEndTime > blobsEndTime) aggEndTime else blobsEndTime - fakeClock.setTimeTo(endTime.plus(10.seconds)) + // submission do the cutoff by minutes, so we need to add 1 minute to the end time + fakeClock.setTimeTo(endTime.plus(1.minutes)) blobSubmissionCoordinator.start() aggregationFinalizationCoordinator.start() diff --git a/coordinator/ethereum/blob-submitter/src/main/kotlin/net/consensys/zkevm/ethereum/submission/SwitchProviderImpl.kt b/coordinator/ethereum/blob-submitter/src/main/kotlin/net/consensys/zkevm/ethereum/submission/SwitchProviderImpl.kt index 666f0b600..9dae2b93b 100644 --- a/coordinator/ethereum/blob-submitter/src/main/kotlin/net/consensys/zkevm/ethereum/submission/SwitchProviderImpl.kt +++ b/coordinator/ethereum/blob-submitter/src/main/kotlin/net/consensys/zkevm/ethereum/submission/SwitchProviderImpl.kt @@ -2,8 +2,8 @@ package net.consensys.zkevm.ethereum.submission +import build.linea.web3j.Web3JLogsClient import net.consensys.linea.contract.L2MessageService -import net.consensys.linea.contract.Web3JLogsClient import net.consensys.toULong import net.consensys.zkevm.ethereum.coordination.conflation.upgrade.SwitchProvider import org.apache.logging.log4j.LogManager diff --git a/coordinator/ethereum/test-utils/src/main/kotlin/net/consensys/zkevm/ethereum/AccountManager.kt b/coordinator/ethereum/test-utils/src/main/kotlin/net/consensys/zkevm/ethereum/AccountManager.kt index 36611739f..dc7c94229 100644 --- a/coordinator/ethereum/test-utils/src/main/kotlin/net/consensys/zkevm/ethereum/AccountManager.kt +++ b/coordinator/ethereum/test-utils/src/main/kotlin/net/consensys/zkevm/ethereum/AccountManager.kt @@ -228,7 +228,7 @@ object L1AccountManager : AccountManager by WhaleBasedAccountManager( object L2AccountManager : AccountManager by WhaleBasedAccountManager( web3jClient = Web3jClientManager.l2Client, - genesisFile = getPathTo(System.getProperty("L2_GENESIS", "docker/config/linea-local-dev-genesis.json")), + genesisFile = getPathTo(System.getProperty("L2_GENESIS", "docker/config/linea-local-dev-genesis-PoA.json")), log = LogManager.getLogger(L2AccountManager::class.java) ) diff --git a/docker/compose.yml b/docker/compose.yml index 3084a9f20..d9ce8ac3f 100644 --- a/docker/compose.yml +++ b/docker/compose.yml @@ -408,6 +408,11 @@ services: condition: service_healthy l1-node-genesis-generator: condition: service_completed_successfully + healthcheck: + test: ["CMD-SHELL", "curl -f http://localhost:4000/eth/v1/node/health || exit 1"] + interval: 1s + timeout: 1s + retries: 120 command: [ "--config-file=/config/config-file.yaml" ] volumes: - ./config/l1-node/cl/teku.key:/config/keys/teku.key:ro @@ -644,6 +649,10 @@ services: condition: service_healthy redis: condition: service_healthy + l1-cl-node: + condition: service_healthy + l1-el-node: + condition: service_healthy blobscan-indexer: container_name: blobscan-indexer @@ -662,6 +671,10 @@ services: condition: service_healthy blobscan-api: condition: service_started + l1-cl-node: + condition: service_healthy + l1-el-node: + condition: service_healthy redis: container_name: redis @@ -684,6 +697,95 @@ services: l1network: ipv4_address: 10.10.10.205 + zkbesu-shomei-sr: + image: consensys/linea-besu-package:${SEQUENCER_TAG:-devnet-811f30b} + hostname: zkbesu-shomei-sr + container_name: zkbesu-shomei-sr + profiles: [ "external-to-monorepo", "staterecover" ] + privileged: true +# restart: none + user: root + ports: + - "9145:8545" # http + - "9146:8546" # websockets + - "9150:8550" + - "10545:9545" + healthcheck: + test: [ "CMD-SHELL", "bash -c \"[ -f /tmp/pid ]\"" ] + interval: 1s + timeout: 1s + retries: 120 + restart: "no" + networks: + l1network: + ipv4_address: 10.10.10.206 + linea: + ipv4_address: 11.11.11.116 + environment: + LOG4J_CONFIGURATION_FILE: /var/lib/besu/log4j.xml + L1_ROLLUP_CONTRACT_ADDRESS: ${L1_ROLLUP_CONTRACT_ADDRESS:-0xCf7Ed3AccA5a467e9e704C703E8D87F634fB0Fc9} + entrypoint: + - /bin/bash + - -c + - | + chown -R besu:besu /opt/besu/plugins && \ + ls -lh /opt/besu/plugins && \ + sed -i '/^CLASSPATH/c\CLASSPATH=/opt/besu/lib/\*' /opt/besu/bin/besu && \ + /opt/besu/bin/besu \ + --config-file=/var/lib/besu/zkbesu-config.toml \ + --genesis-file=/var/lib/besu/genesis.json \ + --plugins=BesuShomeiRpcPlugin,ZkTrieLogPlugin,LineaStateRecoverPlugin \ + --rpc-http-api=ADMIN,DEBUG,NET,ETH,WEB3,PLUGINS,MINER,SHOMEI \ + --Xbonsai-limit-trie-logs-enabled=false \ + --plugin-shomei-http-host="11.11.11.117" \ + --plugin-shomei-http-port=8888 \ + --plugin-staterecovery-l1-rpc-endpoint=http://l1-el-node:8545 \ + --plugin-staterecovery-shomei-endpoint=http://shomei-sr:8888 \ + --plugin-staterecovery-blobscan-endpoint=http://blobscan-api:4001 \ + --plugin-staterecovery-linea-sequencer-beneficiary-address=0x6d976c9b8ceee705d4fe8699b44e5eb58242f484 \ + --plugin-staterecovery-overriding-recovery-start-block-number=1 \ + --plugin-staterecovery-l1-polling-interval=PT1S + volumes: + - ./config/zkbesu-shomei/zkbesu-config.toml:/var/lib/besu/zkbesu-config.toml:ro + - ./config/zkbesu-shomei/log4j-staterecovery.xml:/var/lib/besu/log4j.xml:ro + - ./config/linea-local-dev-genesis-PoA-besu.json/:/var/lib/besu/genesis.json:ro + - ../state-recover/besu-plugin/build/libs/linea-staterecover-plugin-0.0.1-rc2.jar:/opt/besu/lib/linea-staterecover-plugin-0.0.1-rc2.jar + - ../state-recover/besu-plugin/build/libs/linea-staterecover-plugin-0.0.1-rc2.jar:/opt/besu/plugins/linea-staterecover-plugin-0.0.1-rc2.jar + + shomei-sr: + image: consensys/linea-shomei:2.3.0 + hostname: shomei-sr + container_name: shomei-sr + profiles: [ "external-to-monorepo", "staterecover" ] + depends_on: + zkbesu-shomei-sr: + condition: service_started + privileged: true + user: root + ports: + - "8890:8888" + healthcheck: + test: [ "CMD-SHELL", "bash -c \"[ -f /data/shomei/LOCK ]\"" ] + interval: 1s + timeout: 1s + retries: 60 + networks: + linea: + ipv4_address: 11.11.11.117 + environment: + LOG4J_CONFIGURATION_FILE: /log4j.xml + command: + - --besu-rpc-http-host=11.11.11.116 + - --besu-rpc-http-port=8545 + - --rpc-http-host=11.11.11.117 + - --rpc-http-host-allow-list=* + - --rpc-http-port=8888 + - --min-confirmations-before-importing=0 + - --trace-start-block-number=0 + volumes: + - ./config/shomei/log4j.xml:/log4j.xml:ro + # - ../tmp/local/shomei:/data/shomei/:z + ######################## # Observability stack ######################## diff --git a/docker/config/linea-local-dev-genesis.json b/docker/config/linea-local-dev-genesis.json deleted file mode 100644 index b4d149078..000000000 --- a/docker/config/linea-local-dev-genesis.json +++ /dev/null @@ -1,147 +0,0 @@ -{ - "@WARNING": "THIS FILE IS FOR LOCAL DEVELOPMENT ONLY! DO NOT REUSE ELSEWHERE", - "config": { - "chainId": 1337, - "homesteadBlock": 0, - "eip150Block": 0, - "eip155Block": 0, - "eip158Block": 0, - "byzantiumBlock": 0, - "constantinopleBlock": 0, - "petersburgBlock": 0, - "istanbulBlock": 0, - "berlinBlock": 0, - "londonBlock": 0, - "parisBlock": 0, - "terminalTotalDifficulty": 0, - "clique": { - "period": 2, - "epoch": 30000 - } - }, - "coinbase": "0x0000000000000000000000000000000000000000", - "difficulty": "0x1", - "extraData": "0x00000000000000000000000000000000000000000000000000000000000000005064f2bafb300be5ea73aed3f4835e1a0256a5b30000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "gasLimit": "0xa00000", - "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", - "nonce": "0x0", - "timestamp": "0x645580D1", - "@WARNING": "FOR LOCAL DEV ONLY - DO NOT REUSE THESE KEYS ELSEWHERE", - "alloc": { - "1b9abeec3215d8ade8a33607f2cf0f4f60e5f0d0": { - "privateKey": "0x1dd171cec7e2995408b5513004e8207fe88d6820aeff0d82463b3e41df251aae", - "comment": "Contract deployer account", - "balance": "90000000000000000000000" - }, - "fe3b557e8fb62b89f4916b721be55ceb828dbd73": { - "privateKey": "8f2a55949038a9610f50fb23b5883af3b4ecb3c3bb792cbcefbd1542c692be63", - "comment": "account 1, can be used as end user", - "balance": "90000000000000000000001" - }, - "627306090abaB3A6e1400e9345bC60c78a8BEf57": { - "privateKey": "c87509a1c067bbde78beb793e6fa76530b6382a4c0241e5e4a9ec0a0f44dc0d3", - "comment": "account 2, can be used as end user", - "balance": "90000000000000000000002" - }, - "f17f52151EbEF6C7334FAD080c5704D77216b732": { - "privateKey": "ae6ae8e5ccbfb04590405997ee2d52d2b330726137b875053c36d94e974d162f", - "comment": "account 3, can be used as end user", - "balance": "90000000000000000000003" - }, - "6d26dcc30a1693043aefa35ed9171c16da53f275": { - "privateKey": "0x47629fbb4a7ad7772b4d1cc92f26b325577b70f1ed5940e1859b92d690f8a2bf", - "comment": "account 4, can be used as end user", - "balance": "90000000000000000000004" - }, - "e00cad48944330a60bbaedfbf2e0ac97e9762a1e": { - "privateKey": "0x4f78823f38639b9ef15392eb8024ace1d7b991ea820b0dd36a15d14d1a6785", - "comment": "account 5, can be used as end user", - "balance": "90000000000000000000005" - }, - "2257ae433e214df824eb2ade79d2b305ca61a4f4": { - "privateKey": "0x327456c797d6300e11051c0c19b9dbe480fe57cdfcb8033d313e80c7c2e10369", - "comment": "account 6, can be used as end user", - "balance": "90000000000000000000006" - }, - "0d4278da2f55cf21a014b7fee0a2cb799ce17ede": { - "privateKey": "0x9ffda2814ee771e0af8018aeea65f9eabd47ea9f2a5b628a4571adeafea692d1", - "comment": "account 7, can be used as end user", - "balance": "90000000000000000000007" - }, - "994f4c82683f666d13d03a131078f1b94777790c": { - "privateKey": "0xcd3a170ec22b2f3e4aee76356df0c34712db8c24f8d836bce1e4a79299c87053", - "comment": "account 8, can be used as end user", - "balance": "90000000000000000000008" - }, - "9d14ef14d4c90436a062efd7dc8354a7ded9712e": { - "privateKey": "0x4a954bb197f7a27a5427f29180fbfd0b32ee0344b4f85c8184ca593cf152866a", - "comment": "account 9, can be used as end user", - "balance": "90000000000000000000009" - }, - "29a6b94168f04956c6fd1a2c3fdd1f6f7c468148": { - "privateKey": "0x745dda33b5d813bda7f52d646a56498c1539290f59d064b13161f84a1f0a7b4b", - "comment": "account 10, can be used as end user", - "balance": "900000000000000000000010" - }, - "dca74800d7ce103a5e6a3f6028ab0963c46e7422": { - "privateKey": "0x75b9700016469b0d7f12c0d6a0225cd9a59818a4bd1437cf9583ca0ffa1d111a", - "comment": "account 11, can be used as end user", - "balance": "900000000000000000000011" - }, - "9ad149426800dc9e65754a5ceab6bc1f41cc92a7": { - "privateKey": "0xe08f03f96ff2f4e107a50da222e281db39cd528c8c35e25a17f0a71a4d279da5", - "comment": "account 12, can be used as end user", - "balance": "900000000000000000000012" - }, - "b3c150df38e91149e260c3233f3121810d4d2976": { - "privateKey": "0x7303d2fadd895018075cbe76d8a700bc65b4a1b8641b97d660533f0e029e3954", - "comment": "account 13, can be used as end user", - "balance": "900000000000000000000013" - }, - "42232eab8cfd6b489efe79d3bdcc12f07a9fbac6": { - "privateKey": "0xc5453712de35e7dc2c599b5f86df5d4f0de442d86a2865cfe557acd6d131aa6f", - "comment": "account 14, can be used as end user", - "balance": "900000000000000000000014" - }, - "30b080749e44112c3e679c5e4117dd2d884ec7da": { - "privateKey": "0xa8cc1b4bf5cd228cfe63c1b73a5515721e72b487cf8b82a285023aa0ed1ef839", - "comment": "account 15, can be used as end user", - "balance": "900000000000000000000015" - }, - "82f93ea98b24441dc3e0b2413cc1cbb02f33d7e5": { - "privateKey": "0x8c1c8a65947b79ef919261364e9044d89ffe26fb764d8cd72db0446d6cf56664", - "comment": "account 16, can be used as end user", - "balance": "900000000000000000000016" - }, - "bae3c3fcd73ccf7755ec8a10664f218ad6bbc775": { - "privateKey": "0xb35972d9380d1be620a2c61da77f68f127ef248ec55e1bc6033d20a7e13ef3fa", - "comment": "account 17, can be used as end user", - "balance": "900000000000000000000017" - }, - "54d450f4d728da50f1271a1700b42657940324aa": { - "privateKey": "0x234d87442cf7d43841fbe280febcdfabfb646added67bc19f7e42a5483f614c4", - "comment": "account 18, can be used as end user", - "balance": "900000000000000000000018" - }, - "d42e308fc964b71e18126df469c21b0d7bcb86cc": { - "privateKey": "0x4d01ae6487860981699236a58b68f807ee5f17b12df5740b85cf4c4653be0f55", - "comment": "Message anchorer account", - "balance": "900000000000000000000019" - }, - "c8c92fe825d8930b9357c006e0af160dfa727a62": { - "privateKey": "0xfcf854e0a0bc6fd7e97d7050e61a362c915cecd6767a32267b22e8b7af572e58", - "comment": "account 20, can be used as end user", - "balance": "900000000000000000000020" - }, - "8cdcc370846c9f669489227465f80e6cc4ecd050": { - "privateKey": "0xb17202c37cce9498e6f7dcdc1abd207802d09b5eee96677ea219ac867a198b91", - "comment": "Account used for smart contract deployment on L1 and L2", - "balance": "90000000000000000000000" - }, - "d0584d4d37157f7105a4b41ed8ecbdfafdb2547f": { - "privateKey": "0x202454d1b4e72c41ebf58150030f649648d3cf5590297fb6718e27039ed9c86d", - "comment": "Operator account", - "balance": "90000000000000000000000" - } - } -} diff --git a/docker/config/shomei/log4j.xml b/docker/config/shomei/log4j.xml index 15df621c1..46bc5b2f8 100644 --- a/docker/config/shomei/log4j.xml +++ b/docker/config/shomei/log4j.xml @@ -6,7 +6,7 @@ - + diff --git a/docker/config/traces-node-v2/log4j.xml b/docker/config/traces-node-v2/log4j.xml index 4fce5c508..f7d311869 100644 --- a/docker/config/traces-node-v2/log4j.xml +++ b/docker/config/traces-node-v2/log4j.xml @@ -25,7 +25,7 @@ - + diff --git a/docker/config/traces-node-v2/traces-node-v2-config.toml b/docker/config/traces-node-v2/traces-node-v2-config.toml index a38c5d8e7..09ca48cd2 100644 --- a/docker/config/traces-node-v2/traces-node-v2-config.toml +++ b/docker/config/traces-node-v2/traces-node-v2-config.toml @@ -38,7 +38,7 @@ data-storage-format="BONSAI" # plugins plugins=["TracerReadinessPlugin","TracesEndpointServicePlugin","LineCountsEndpointServicePlugin","CaptureEndpointServicePlugin"] plugin-linea-conflated-trace-generation-traces-output-path="/data/traces/v2/conflated" -plugin-linea-rpc-concurrent-requests-limit=1 +plugin-linea-rpc-concurrent-requests-limit=2 plugin-linea-tracer-readiness-server-host="0.0.0.0" plugin-linea-tracer-readiness-server-port=8548 plugin-linea-tracer-readiness-max-blocks-behind=5 diff --git a/docker/config/zkbesu-shomei/log4j-staterecovery.xml b/docker/config/zkbesu-shomei/log4j-staterecovery.xml new file mode 100644 index 000000000..6e5ada67a --- /dev/null +++ b/docker/config/zkbesu-shomei/log4j-staterecovery.xml @@ -0,0 +1,53 @@ + + + + INFO + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docker/config/zkbesu-shomei/log4j.xml b/docker/config/zkbesu-shomei/log4j.xml index 56c746fb5..144906b8d 100644 --- a/docker/config/zkbesu-shomei/log4j.xml +++ b/docker/config/zkbesu-shomei/log4j.xml @@ -1,7 +1,7 @@ - WARN + INFO diff --git a/docker/linea-sepolia/genesis.json b/docker/linea-sepolia/genesis.json index 037bd7a2c..09f520d32 100644 --- a/docker/linea-sepolia/genesis.json +++ b/docker/linea-sepolia/genesis.json @@ -19,7 +19,7 @@ "nonce": "0x0", "timestamp": "0x6391BFF3", "extraData": "0x00000000000000000000000000000000000000000000000000000000000000004D517Aef039A48b3B6bF921e210b7551C8E371070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "gasLimit": "0x1C9C380", + "gasLimit": "0x3a2c940", "difficulty": "0x1", "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", "coinbase": "0x0000000000000000000000000000000000000000", @@ -814,4 +814,4 @@ "number": "0x0", "gasUsed": "0x0", "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000" - } \ No newline at end of file + } diff --git a/docker/scripts/file-downloader.sh b/docker/scripts/file-downloader.sh deleted file mode 100644 index 1de52d8e7..000000000 --- a/docker/scripts/file-downloader.sh +++ /dev/null @@ -1,25 +0,0 @@ -#!/usr/bin/env bash - -if [ $# -lt 2 ]; then - echo "Usage: $0 file_url destination_folder" - echo "Example: $0 https://example.com/somefile.txt /path/to/destination/" - exit -fi - -check_and_download_file() { - local file_url="$1" - local directory="$2" - local filename="${file_url##*/}" # Extracts the filename from the URL - - # Check if the file exists in the directory - if [[ ! -f "$directory/$filename" ]]; then - # File does not exist, download it - echo "Downloading $file_url ..." - wget "$file_url" -P "$directory" - echo "Download complete!" - else - echo "File $filename already exists in $directory." - fi -} -echo "$0 $1 $2" -check_and_download_file "$1" "$2" diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 670b1201d..509df13fd 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -9,6 +9,7 @@ jreleaser = { group = "org.jreleaser", name = "jreleaser-gradle-plugin", version [versions] besu = "24.12.2" +bouncycastle = "1.79" caffeine = "3.1.6" hoplite = "2.7.5" jackson = "2.18.0" @@ -19,7 +20,7 @@ ktlint = "0.47.0" log4j = "2.20.0" micrometer = "1.8.4" netty = "4.1.92.Final" -picoli = "4.7.1" +picoli = "4.7.6" restassured = "5.3.0" teku = "23.1.1" tuweni = "2.4.2" @@ -28,5 +29,6 @@ vertx = "4.5.0" web3j = "4.12.2" wiremock = "3.0.1" jsonUnit = "3.4.1" +slf4j="1.7.36" blobCompressor = "0.0.4" blobShnarfCalculator = "0.0.4" diff --git a/jvm-libs/generic/extensions/kotlin/src/main/kotlin/net/consensys/TypingsExtensions.kt b/jvm-libs/generic/extensions/kotlin/src/main/kotlin/net/consensys/TypingsExtensions.kt index 650de984b..5114a4429 100644 --- a/jvm-libs/generic/extensions/kotlin/src/main/kotlin/net/consensys/TypingsExtensions.kt +++ b/jvm-libs/generic/extensions/kotlin/src/main/kotlin/net/consensys/TypingsExtensions.kt @@ -66,6 +66,16 @@ fun ULong.toGWei(): Double = this.toDouble().toGWei() */ fun ULong.Companion.fromHexString(value: String): ULong = value.removePrefix("0x").toULong(16) +fun ULongRange.intersection(other: ULongRange): ULongRange { + val start = maxOf(this.first, other.first) + val end = minOf(this.last, other.last) + return if (start <= end) { + start..end + } else { + ULongRange.EMPTY + } +} + fun > ClosedRange.toIntervalString(): String { val size = if (start <= endInclusive) { this.endInclusive.toString().toBigDecimal() - this.start.toString().toBigDecimal() + 1.toBigDecimal() diff --git a/jvm-libs/generic/json-rpc/src/testFixtures/kotlin/linea/jsonrpc/TestingJsonRpcServer.kt b/jvm-libs/generic/json-rpc/src/testFixtures/kotlin/linea/jsonrpc/TestingJsonRpcServer.kt index 64921a6b7..44e9591b2 100644 --- a/jvm-libs/generic/json-rpc/src/testFixtures/kotlin/linea/jsonrpc/TestingJsonRpcServer.kt +++ b/jvm-libs/generic/json-rpc/src/testFixtures/kotlin/linea/jsonrpc/TestingJsonRpcServer.kt @@ -31,7 +31,7 @@ open class TestingJsonRpcServer( port: Int = 0, val apiPath: String = "/", val recordRequestsResponses: Boolean = false, - val serverName: String = "FakeJsonRpcServer", + val serverName: String = "TestingJsonRpcServer", loggerName: String = serverName, val vertx: Vertx = Vertx.vertx(), val responseObjectMapper: ObjectMapper = jacksonObjectMapper(), diff --git a/jvm-libs/generic/logging/src/main/kotlin/linea/logging/TimeMeasureLogger.kt b/jvm-libs/generic/logging/src/main/kotlin/linea/logging/TimeMeasureLogger.kt new file mode 100644 index 000000000..72ddf85dd --- /dev/null +++ b/jvm-libs/generic/logging/src/main/kotlin/linea/logging/TimeMeasureLogger.kt @@ -0,0 +1,38 @@ +package linea.logging + +import org.apache.logging.log4j.Level +import org.apache.logging.log4j.Logger +import kotlin.time.measureTime + +/** + * This is more for debugging purposes, to measure the time taken by a certain action and log it. + * For production code, consider using metrics. + */ +fun measureTimeAndLog( + logger: Logger, + logLevel: Level = Level.DEBUG, + logMessageProvider: (duration: kotlin.time.Duration, result: T) -> String, + action: () -> T +): T { + var value: T + val duration = measureTime { + value = action() + } + if (logger.isEnabled(logLevel)) { + logger.log(logLevel, logMessageProvider(duration, value)) + } + return value +} + +class MeasureLogger( + private val logger: Logger, + private val logLevel: Level = Level.DEBUG +) { + fun measureTimeAndLog( + logLevel: Level = this.logLevel, + logMessageProvider: (duration: kotlin.time.Duration, result: T) -> String, + action: () -> T + ): T { + return measureTimeAndLog(logger, logLevel, logMessageProvider, action) + } +} diff --git a/jvm-libs/generic/logging/src/main/kotlin/net/consensys/linea/logging/JsonRpcRequestResponseLogger.kt b/jvm-libs/generic/logging/src/main/kotlin/net/consensys/linea/logging/JsonRpcRequestResponseLogger.kt index c47ecf817..f761174cb 100644 --- a/jvm-libs/generic/logging/src/main/kotlin/net/consensys/linea/logging/JsonRpcRequestResponseLogger.kt +++ b/jvm-libs/generic/logging/src/main/kotlin/net/consensys/linea/logging/JsonRpcRequestResponseLogger.kt @@ -26,12 +26,11 @@ class MinimalInLineJsonRpcLogger( ) : JsonRpcRequestResponseLogger { private fun logRequestOnLevel(level: Level, endpoint: String, jsonBody: String, throwable: Throwable?) { - val message = if (throwable == null) { - "--> {} {}" + if (throwable == null) { + logger.log(level, "--> {} {}", endpoint, jsonBody) } else { - "--> {} {} failed with error={}" + logger.log(level, "--> {} {} failed with error={}", endpoint, jsonBody, throwable.message, throwable) } - logger.log(level, message, endpoint, jsonBody, throwable?.message, throwable) } override fun logRequest(endpoint: String, jsonBody: String, throwable: Throwable?) { @@ -54,19 +53,23 @@ class MinimalInLineJsonRpcLogger( logRequestOnLevel(logLevel, maskedEndpoint, requestBody, null) } - val message = if (failureCause == null) { - "<-- {} {} {}" + if (failureCause == null) { + logger.log( + logLevel, + "<-- {} {} {}", + maskedEndpoint, + responseStatusCode, + responseBody + ) } else { - "<-- {} {} {} failed with error={}" + logger.log( + logLevel, + "<-- {} {} {} failed with error={}", + maskedEndpoint, + responseStatusCode, + responseBody, + failureCause.message + ) } - - logger.log( - logLevel, - message, - maskedEndpoint, - responseStatusCode, - responseBody, - failureCause?.message - ) } } diff --git a/jvm-libs/generic/logging/src/test/kotlin/net/consensys/linea/logging/MinimalInLineJsonRpcLoggerTest.kt b/jvm-libs/generic/logging/src/test/kotlin/net/consensys/linea/logging/MinimalInLineJsonRpcLoggerTest.kt index 680ab3111..dc3dd24b0 100644 --- a/jvm-libs/generic/logging/src/test/kotlin/net/consensys/linea/logging/MinimalInLineJsonRpcLoggerTest.kt +++ b/jvm-libs/generic/logging/src/test/kotlin/net/consensys/linea/logging/MinimalInLineJsonRpcLoggerTest.kt @@ -36,7 +36,7 @@ class MinimalInLineJsonRpcLoggerTest { fun `logRequest logs request with correct level and format`() { minimalInLineJsonRpcLogger.logRequest("testEndpoint", jsonRequestBody) - verify(logger).log(eq(Level.DEBUG), eq("--> {} {}"), eq("testEndpoint"), eq(jsonRequestBody), eq(null), eq(null)) + verify(logger).log(eq(Level.DEBUG), eq("--> {} {}"), eq("testEndpoint"), eq(jsonRequestBody)) } @Test @@ -63,8 +63,7 @@ class MinimalInLineJsonRpcLoggerTest { eq("<-- {} {} {}"), eq("testEndpoint"), eq(200), - eq(jsonSuccessResponse), - eq(null) + eq(jsonSuccessResponse) ) } @@ -73,7 +72,7 @@ class MinimalInLineJsonRpcLoggerTest { val exception = RuntimeException("Test exception") minimalInLineJsonRpcLogger.logResponse("testEndpoint", 500, jsonRequestBody, jsonErrorResponse, exception) - verify(logger).log(eq(Level.WARN), eq("--> {} {}"), eq("testEndpoint"), eq(jsonRequestBody), eq(null), eq(null)) + verify(logger).log(eq(Level.WARN), eq("--> {} {}"), eq("testEndpoint"), eq(jsonRequestBody)) verify(logger).log( eq(Level.WARN), eq("<-- {} {} {} failed with error={}"), diff --git a/jvm-libs/generic/serialization/jackson/src/main/kotlin/build/linea/s11n/jackson/InstantAsHexNumberSerDe.kt b/jvm-libs/generic/serialization/jackson/src/main/kotlin/build/linea/s11n/jackson/InstantAsHexNumberSerDe.kt new file mode 100644 index 000000000..533d0abb1 --- /dev/null +++ b/jvm-libs/generic/serialization/jackson/src/main/kotlin/build/linea/s11n/jackson/InstantAsHexNumberSerDe.kt @@ -0,0 +1,21 @@ +package build.linea.s11n.jackson + +import com.fasterxml.jackson.core.JsonGenerator +import com.fasterxml.jackson.core.JsonParser +import com.fasterxml.jackson.databind.DeserializationContext +import com.fasterxml.jackson.databind.JsonDeserializer +import com.fasterxml.jackson.databind.JsonSerializer +import com.fasterxml.jackson.databind.SerializerProvider +import kotlinx.datetime.Instant + +object InstantAsHexNumberSerializer : JsonSerializer() { + override fun serialize(value: Instant, gen: JsonGenerator, serializers: SerializerProvider) { + gen.writeString("0x${value.epochSeconds.toString(16)}") + } +} + +object InstantAsHexNumberDeserializer : JsonDeserializer() { + override fun deserialize(p: JsonParser, ctxt: DeserializationContext): Instant { + return Instant.fromEpochSeconds(p.text.replace("0x", "").toLong(16)) + } +} diff --git a/jvm-libs/generic/serialization/jackson/src/main/kotlin/build/linea/s11n/jackson/InstantISO8601SerDe.kt b/jvm-libs/generic/serialization/jackson/src/main/kotlin/build/linea/s11n/jackson/InstantISO8601SerDe.kt index 3c1d671ec..f16752206 100644 --- a/jvm-libs/generic/serialization/jackson/src/main/kotlin/build/linea/s11n/jackson/InstantISO8601SerDe.kt +++ b/jvm-libs/generic/serialization/jackson/src/main/kotlin/build/linea/s11n/jackson/InstantISO8601SerDe.kt @@ -14,7 +14,6 @@ object InstantISO8601Serializer : JsonSerializer() { } } -// To uncomment and add the tests when necessary object InstantISO8601Deserializer : JsonDeserializer() { override fun deserialize(p: JsonParser, ctxt: DeserializationContext): Instant { return Instant.parse(p.text) diff --git a/jvm-libs/generic/serialization/jackson/src/test/kotlin/build/linea/s11n/jackson/InstantAsHexNumberSerDeTest.kt b/jvm-libs/generic/serialization/jackson/src/test/kotlin/build/linea/s11n/jackson/InstantAsHexNumberSerDeTest.kt new file mode 100644 index 000000000..16b702b9b --- /dev/null +++ b/jvm-libs/generic/serialization/jackson/src/test/kotlin/build/linea/s11n/jackson/InstantAsHexNumberSerDeTest.kt @@ -0,0 +1,56 @@ +package build.linea.s11n.jackson + +import com.fasterxml.jackson.databind.ObjectMapper +import com.fasterxml.jackson.databind.module.SimpleModule +import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper +import kotlinx.datetime.Instant +import net.javacrumbs.jsonunit.assertj.JsonAssertions.assertThatJson +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test + +class InstantAsHexNumberSerDeTest { + private lateinit var objectMapper: ObjectMapper + + @BeforeEach + fun setUp() { + objectMapper = jacksonObjectMapper() + .registerModules( + SimpleModule().apply { + this.addSerializer(Instant::class.java, InstantAsHexNumberSerializer) + this.addDeserializer(Instant::class.java, InstantAsHexNumberDeserializer) + } + ) + } + + @Test + fun instantSerDeDeSerialization() { + data class SomeObject( + // Int + val instantNull: Instant? = null, + // 2021-01-02T09:00:45Z UTC, + val instantUTC: Instant = Instant.fromEpochSeconds(1609578045), + // 2021-07-01T08:00:45Z UTC + val instantUTCDST: Instant = Instant.fromEpochSeconds(1625126445), + // 2021-01-02T09:00:45+01:30 UTC+01:30, + val instantUTCPlus: Instant = Instant.fromEpochSeconds(1609572645), + // 2021-01-02T09:00:45-01:30" UTC-01:30 + val instantUTCMinus: Instant = Instant.fromEpochSeconds(1609583445) + ) + + val expectedJson = """ + { + "instantNull": null, + "instantUTC": "0x5ff0363d", + "instantUTCDST": "0x60dd762d", + "instantUTCPlus": "0x5ff02125", + "instantUTCMinus": "0x5ff04b55" + } + """.trimIndent() + + // assert serialization + assertThatJson(objectMapper.writeValueAsString(SomeObject())).isEqualTo(expectedJson) + + // assert deserialization + assertThatJson(objectMapper.readValue(expectedJson, SomeObject::class.java)).isEqualTo(SomeObject()) + } +} diff --git a/jvm-libs/linea/besu-libs/build.gradle b/jvm-libs/linea/besu-libs/build.gradle index e9b797c88..4c91d9662 100644 --- a/jvm-libs/linea/besu-libs/build.gradle +++ b/jvm-libs/linea/besu-libs/build.gradle @@ -3,27 +3,30 @@ plugins { id 'java-library' } -def besuArtifactGroup="org.hyperledger.besu" +//def besuArtifactGroup="org.hyperledger.besu" +//def besuVersion=libs.versions.besu.get() +def besuArtifactGroup="io.consensys.linea-besu" +def besuVersion="24.12-develop-2098dd2" dependencies { - api("${besuArtifactGroup}:besu-datatypes:${libs.versions.besu.get()}") { + api("${besuArtifactGroup}:besu-datatypes:${besuVersion}") { transitive = false } - api("${besuArtifactGroup}:evm:${libs.versions.besu.get()}") { + api("${besuArtifactGroup}:evm:${besuVersion}") { transitive = false } - api("${besuArtifactGroup}.internal:core:${libs.versions.besu.get()}") { + api("${besuArtifactGroup}.internal:core:${besuVersion}") { transitive = false } - api("${besuArtifactGroup}.internal:algorithms:${libs.versions.besu.get()}") { + api("${besuArtifactGroup}.internal:algorithms:${besuVersion}") { transitive = false } - api("${besuArtifactGroup}:plugin-api:${libs.versions.besu.get()}") { + api("${besuArtifactGroup}:plugin-api:${besuVersion}") { transitive = false } - api("${besuArtifactGroup}.internal:rlp:${libs.versions.besu.get()}") { + api("${besuArtifactGroup}.internal:rlp:${besuVersion}") { transitive = false } @@ -34,4 +37,11 @@ dependencies { api("io.tmio:tuweni-units:${libs.versions.tuweni.get()}") { transitive = false } + + implementation("org.bouncycastle:bcpkix-jdk18on:${libs.versions.bouncycastle.get()}") { + because "necessary for besu Transaction object that verifies signatures" + } + implementation("org.bouncycastle:bcprov-jdk18on:${libs.versions.bouncycastle.get()}") { + because "necessary for besu Transaction object that verifies signatures" + } } diff --git a/jvm-libs/linea/besu-rlp-and-mappers/build.gradle b/jvm-libs/linea/besu-rlp-and-mappers/build.gradle index 3e1576a6b..7e3bbea5c 100644 --- a/jvm-libs/linea/besu-rlp-and-mappers/build.gradle +++ b/jvm-libs/linea/besu-rlp-and-mappers/build.gradle @@ -7,5 +7,8 @@ dependencies { api(project(':jvm-libs:generic:extensions:futures')) api(project(':jvm-libs:linea:core:domain-models')) api(project(':jvm-libs:linea:besu-libs')) + implementation("org.slf4j:slf4j-api:${libs.versions.slf4j.get()}") { + because("Besu RLP uses SLF4J") + } api "io.vertx:vertx-core" } diff --git a/jvm-libs/linea/blob-compressor/build.gradle b/jvm-libs/linea/blob-compressor/build.gradle index 647c19cd8..68139ec08 100644 --- a/jvm-libs/linea/blob-compressor/build.gradle +++ b/jvm-libs/linea/blob-compressor/build.gradle @@ -11,7 +11,11 @@ dependencies { implementation project(":jvm-libs:generic:extensions:kotlin") implementation "org.apache.logging.log4j:log4j-api:${libs.versions.log4j.get()}" implementation "org.apache.logging.log4j:log4j-core:${libs.versions.log4j.get()}" + testImplementation project(":jvm-libs:linea:blob-shnarf-calculator") + testFixturesImplementation project(':jvm-libs:linea:besu-libs') + testFixturesImplementation project(':jvm-libs:linea:besu-rlp-and-mappers') + testFixturesImplementation(project(":jvm-libs:linea:testing:file-system")) } jar { diff --git a/jvm-libs/linea/blob-compressor/src/main/kotlin/linea/blob/BlobCompressor.kt b/jvm-libs/linea/blob-compressor/src/main/kotlin/linea/blob/BlobCompressor.kt index dc272c896..58f36cccf 100644 --- a/jvm-libs/linea/blob-compressor/src/main/kotlin/linea/blob/BlobCompressor.kt +++ b/jvm-libs/linea/blob-compressor/src/main/kotlin/linea/blob/BlobCompressor.kt @@ -24,6 +24,12 @@ interface BlobCompressor { fun getCompressedData(): ByteArray fun reset() + fun getCompressedDataAndReset(): ByteArray { + val compressedData = getCompressedData() + reset() + return compressedData + } + data class AppendResult( // returns false if last chunk would go over dataLimit. Does not append last block. val blockAppended: Boolean, diff --git a/jvm-libs/linea/blob-compressor/src/test/kotlin/linea/blob/GoBackedBlobCompressorTest.kt b/jvm-libs/linea/blob-compressor/src/test/kotlin/linea/blob/GoBackedBlobCompressorTest.kt index 83e3cd30d..faf20dd1b 100644 --- a/jvm-libs/linea/blob-compressor/src/test/kotlin/linea/blob/GoBackedBlobCompressorTest.kt +++ b/jvm-libs/linea/blob-compressor/src/test/kotlin/linea/blob/GoBackedBlobCompressorTest.kt @@ -12,7 +12,7 @@ import kotlin.random.Random @TestInstance(TestInstance.Lifecycle.PER_CLASS) class GoBackedBlobCompressorTest { companion object { - private const val DATA_LIMIT = 16 * 1024 + private const val DATA_LIMIT = 24 * 1024 private val TEST_DATA = CompressorTestData.blocksRlpEncoded private val compressor = GoBackedBlobCompressor.getInstance(BlobCompressorVersion.V0_1_0, DATA_LIMIT.toUInt()) } @@ -41,14 +41,20 @@ class GoBackedBlobCompressorTest { @Test fun `test compression data limit exceeded`() { - val blocks = TEST_DATA.iterator() + var blocks = TEST_DATA.iterator() var result = compressor.appendBlock(blocks.next()) - while (result.blockAppended && blocks.hasNext()) { + // at least one block should be appended + assertThat(result.blockAppended).isTrue() + while (result.blockAppended) { val blockRlp = blocks.next() val canAppend = compressor.canAppendBlock(blockRlp) result = compressor.appendBlock(blockRlp) // assert consistency between canAppendBlock and appendBlock assertThat(canAppend).isEqualTo(result.blockAppended) + if (!blocks.hasNext()) { + // recompress again, until the limit is reached + blocks = TEST_DATA.iterator() + } } assertThat(result.blockAppended).isFalse() assertThat(result.compressedSizeBefore).isGreaterThan(0) diff --git a/jvm-libs/linea/blob-compressor/src/test/kotlin/net/consensys/linea/blob/GoNativeCompressorAndShnarfCalculatorIntTest.kt b/jvm-libs/linea/blob-compressor/src/test/kotlin/net/consensys/linea/blob/GoNativeCompressorAndShnarfCalculatorIntTest.kt index 1f58c75b1..efcbb3bb9 100644 --- a/jvm-libs/linea/blob-compressor/src/test/kotlin/net/consensys/linea/blob/GoNativeCompressorAndShnarfCalculatorIntTest.kt +++ b/jvm-libs/linea/blob-compressor/src/test/kotlin/net/consensys/linea/blob/GoNativeCompressorAndShnarfCalculatorIntTest.kt @@ -12,7 +12,7 @@ import java.util.Base64 import kotlin.random.Random class GoNativeCompressorAndShnarfCalculatorIntTest { - private val DATA_LIMIT = 16 * 1024 + private val DATA_LIMIT = 128 * 1024 private lateinit var compressor: GoNativeBlobCompressor private lateinit var shnarfCalculator: GoNativeBlobShnarfCalculator @@ -44,7 +44,7 @@ class GoNativeCompressorAndShnarfCalculatorIntTest { @Test fun `compressed size estimation should be consistent with blob maker output`() { - testCompressedSizeSstimationIsConsistentWithBlobMakerOutput() + testCompressedSizeEstimationIsConsistentWithBlobMakerOutput() } } @@ -72,7 +72,7 @@ class GoNativeCompressorAndShnarfCalculatorIntTest { @Test fun `compressed size estimation should be consistent with blob maker output`() { - testCompressedSizeSstimationIsConsistentWithBlobMakerOutput() + testCompressedSizeEstimationIsConsistentWithBlobMakerOutput() } } @@ -201,7 +201,7 @@ class GoNativeCompressorAndShnarfCalculatorIntTest { resultAsserterFn(result) } - fun testCompressedSizeSstimationIsConsistentWithBlobMakerOutput() { + fun testCompressedSizeEstimationIsConsistentWithBlobMakerOutput() { val block = CompressorTestData.blocksRlpEncoded.first() // Write the block to the blob maker and get the effective compressed size @@ -225,6 +225,6 @@ class GoNativeCompressorAndShnarfCalculatorIntTest { // min compressed size should always be strictly bigger than the size returned // by the blob maker minus the header size - assertTrue((compressedSizeWithHeader - estimatedHeaderSizePacked) < compressedSize) + assertThat(compressedSizeWithHeader - estimatedHeaderSizePacked).isLessThanOrEqualTo(compressedSize) } } diff --git a/jvm-libs/linea/blob-compressor/src/testFixtures/kotlin/net/consensys/linea/nativecompressor/CompressorTestData.kt b/jvm-libs/linea/blob-compressor/src/testFixtures/kotlin/net/consensys/linea/nativecompressor/CompressorTestData.kt index e284425ef..92ffb697a 100644 --- a/jvm-libs/linea/blob-compressor/src/testFixtures/kotlin/net/consensys/linea/nativecompressor/CompressorTestData.kt +++ b/jvm-libs/linea/blob-compressor/src/testFixtures/kotlin/net/consensys/linea/nativecompressor/CompressorTestData.kt @@ -1,33 +1,13 @@ package net.consensys.linea.nativecompressor -import java.nio.ByteBuffer -import java.nio.ByteOrder +import linea.rlp.RLP object CompressorTestData { - val blocksRlpEncoded: Array = loadTestData() + val blocksRlpEncoded: List = RLP.decodeList(readResourcesFile("blocks_rlp.bin")) - private fun loadTestData(): Array { - val data = Thread.currentThread().getContextClassLoader().getResourceAsStream("rlp_blocks.bin")!!.readAllBytes() - - // first 4 bytes are the number of blocks - val numBlocks = ByteBuffer.wrap(data, 0, 4).order(ByteOrder.LITTLE_ENDIAN).int - - // the rest of the file is the blocks - // (we repeat them to fill more data) - val blocks = Array(numBlocks * 2) { ByteArray(0) } - - for (j in 0 until 2) { - var offset = 4 - for (i in 0 until numBlocks) { - // first 4 bytes are the length of the block - val blockLen = ByteBuffer.wrap(data, offset, 4).order(ByteOrder.LITTLE_ENDIAN).int - - // the rest of the block is the block - blocks[i + j * numBlocks] = ByteArray(blockLen) - System.arraycopy(data, offset + 4, blocks[i + j * numBlocks], 0, blockLen) - offset += 4 + blockLen - } - } - return blocks + private fun readResourcesFile(fileName: String): ByteArray { + return Thread.currentThread().getContextClassLoader().getResourceAsStream(fileName) + ?.readAllBytes() + ?: throw IllegalArgumentException("File not found in jar resources: file=$fileName") } } diff --git a/jvm-libs/linea/blob-compressor/src/testFixtures/kotlin/net/consensys/linea/nativecompressor/TestDataGeneratorHelper.kt b/jvm-libs/linea/blob-compressor/src/testFixtures/kotlin/net/consensys/linea/nativecompressor/TestDataGeneratorHelper.kt new file mode 100644 index 000000000..47d9729ce --- /dev/null +++ b/jvm-libs/linea/blob-compressor/src/testFixtures/kotlin/net/consensys/linea/nativecompressor/TestDataGeneratorHelper.kt @@ -0,0 +1,70 @@ +package net.consensys.linea.nativecompressor + +import io.vertx.core.json.JsonObject +import linea.rlp.RLP +import net.consensys.decodeHex +import net.consensys.encodeHex +import net.consensys.linea.testing.filesystem.getPathTo +import org.hyperledger.besu.ethereum.core.Block +import java.nio.file.Files +import java.nio.file.Path + +fun loadBlocksFromProverRequests( + proverExecutionRequestsFolder: Path +): List> { + val blocks = Files + .list(proverExecutionRequestsFolder) + .toList() + .map { file -> + JsonObject(Files.readString(file)) + .getJsonArray("blocksData") + .map { block -> + block as JsonObject + // block RLP encoded + val rlp = block.getString("rlp").decodeHex() + RLP.decodeBlockWithMainnetFunctions(rlp) to rlp + } + } + .toList() + .flatten() + return blocks + .sortedBy { it.first.header.number } + .also { + it.forEach { + println("block=${it.first.header} rlp=${it.second.encodeHex()}") + } + } +} + +fun generateEncodeBlocksToBinaryFromProverRequests( + proverExecutionRequestsFolder: Path, + outputFilePath: Path +) { + val blocks = loadBlocksFromProverRequests(proverExecutionRequestsFolder) + Files.write(outputFilePath, RLP.encodeList(blocks.map { it.second })) +} + +fun loadBlocksRlpEncoded( + binFile: Path +): List { + return RLP.decodeList(Files.readAllBytes(binFile)) +} + +fun main() { + val proverExecutionRequestsDir = getPathTo("tmp/local/prover/v3/execution/requests-done/") + val destFile = getPathTo("jvm-libs/linea/blob-compressor/src/testFixtures/resources") + .resolve("blocks_rlp.bin") + + generateEncodeBlocksToBinaryFromProverRequests( + proverExecutionRequestsDir, + destFile + ) + + // Just a visual indicator that it can read/decode again + println("\n\n") + loadBlocksRlpEncoded(destFile) + .map(RLP::decodeBlockWithMainnetFunctions) + .forEach { + println("block=$it") + } +} diff --git a/jvm-libs/linea/blob-compressor/src/testFixtures/resources/blocks_rlp.bin b/jvm-libs/linea/blob-compressor/src/testFixtures/resources/blocks_rlp.bin new file mode 100644 index 0000000000000000000000000000000000000000..dc13c4de8d66f252b0a5f78c07cd9b25c3fe8498 GIT binary patch literal 42062 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 literal 0 HcmV?d00001 diff --git a/jvm-libs/linea/blob-compressor/src/testFixtures/resources/rlp_blocks.bin b/jvm-libs/linea/blob-compressor/src/testFixtures/resources/rlp_blocks.bin deleted file mode 100644 index 82c04c3ff910b96015701321b0da8f673357e801..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 57530 zcmeFabyyuq7ypSn1b26Lx8Uwha3{D2cY+0Xzqq>-g1Zwu!GcQ&?zUuR@|)z9op-Xk ze`KGj=b^j$RCV3{azA~lPFK-j0|5cO0|NrO25Y$n(FO#qX~KtLSW6Im4le78)dvW( zc8pQ)P@K_0mI&g!w%P;WjmYjS_v^Tq2GyH2j7(!sA&cU~hdH4fWeeR4Ovj1GKehL7 z37~_y5=-~^dGCFB4jiWSnK?a7!EkN^f!OFn*i>)Blr=zdQB-lpcxW-o#D^yFnJvy+ z49~7TP9N^AfNPoFLt7lcO{0Xv%QB_Z(FvCbKj`AvS-y_?=!1_JQ5w||@41r=n}LCz zRQ#BLpAMnEGlBe`|Dm41xAH#?=^^eGl&YvHHd;gI2VX-5Qc=y4p0EtdQ|)-$Lz}?V7}M;hj_*t&-!J` z2eE>En}IiY*@?uyo&I0;zW>Gk%}n(z^I!JN&U-;+MawKsTC-d^D*2D4`+D>eHy5GL zn?$<6j|XDl{>ypa%rKBEeT{OdZC6zB0sL7aez=pgwcKm7>gI22V<@Q$C_vlq8yq*P zK~Rm2le88LwmxX_5_bydMvSI6)o@f=cS(|(O`#suKURyjzPk%)kX>lkf`2D#6Sg07 z3g#ac9eGF~CAhxN8#>r0(Iv_>DcGt9v5|k0`GwpamG9uqWh`nwr1~1@L=9;IAw+*KxNP)y5+gA*`P$f?}?4A!X8uD2758W zKWO&BSS3BQAj;z&sawGRAww}T*h%NS!xzBi+|${7QiJ+3NGj`=rZioD19CRZfeH|{ zUp^q1><9!Pwg`WR6uW}x{VBWxtENDMR-aEi^+S^(B3bSy=9+%-4vD9)=^9S-s{?~k zcoe3&;4oRKM0$72d)2~3svzl*>ZsY3%wi{`4J`bV4h(acAwUydWdBe!KrLp<1zX?qHbanq=vnS$EiwWON!fD)jKr6r;~O3)ozl z2&MBYB8X7>BN;L{*SNV7%vqlqDs1F_Fe|Ts*62!+|3IB5*tk?10tN>nB&JwJ&v-g( z4h;D5BL4m8I|l~6)^rPUb@k-FlmZPkfqZ}4_5J@i|^Zw zNHR}P#tfygL!dZCAK@4L*aLX@xjmKu?Ke+e-?iLK3TMY*;fulAOsSie_GxeyNBeyfulfs$XG`H% z;Jz9XZxTR?Ii*gs|ipEhWaL6{g)H(3y>hn={?4E!P{fCvaENB zQZN9|eBb9gSldc)R55A&ZUP{?m*HIWxz!{*346J>62w71K>9=1pf;y9Fr?vNc{u$y z@fyFN_=n}?%S01)Hw0_#P7sshEX+rOp2Tye8=P^BXPmPEx&Tm9LZrc-AoXXKE1`X` zyIrFbZ;$ahsaCjb&;6v!S69D@*Zc*=zYLj{?566wl+LbNPms;NmL2A-Wuat#zM5v` zOkYX$2%vdjNp`NJ27A~cNxTqpK<&4gSR+X)(QsF7Nq@2P=JA{O7r&f%V8DEu%jcTu zRBe*$ZU78sJ=yoy z^3~{^&c0HZ29w89l6zQ#1j!{a3w~kODES@Yzr_+FUtjY+8*Ac|t>IATj|2%5fiKRCz?KZlP0a90@{D6cHUn_ewS8Txvz&sY60goYS8Z*jx@KcNd-|vQ% zHG(c=ZPXTRhqd6{``1|F&#~a2qjdp+Kl9(pe~TqRe~S;E3JHHV|2F*pZN&a$fchE% zdNgYNZ>9gbK}7r(OCYj7l@a~k$kPY^*bL#HAN6Mo z0)&6&pFaL6`BMBCOCbMsEOE+iHiu;ZVD5+9^&2XkZI#kEGA#;QXqTZQ&g|umwlfh&C$h~?DC80s7+@8cenK2B~74pd$I?#W8g{XmZnE-Hq$K33JS8S zRm45*H}N{Zpm=aS1?#JV7=CY$i$uJ3?<<+r(BGU%z8Q z!y#JV;qx?YZK-3(RSsR}^(U($h8^HMo2z~i>}_DOvculEazha^Le zmR5V!>6VL#6jbxcSLrl|sso43C*_Rnvt(+qD1eS?r*iI{xsaE@YeUog<>a0Rl3p-l zW?*=R;^pp^?yO}uK9M1_cyzsypF9O`fjn1GIUEfsq#DO5G~4ASSc3v0U};= zunwisoQoxa_uDU7<{P`l2h}4U<)KDEbSbc(ReTd~@C%Bc61G`8n0 zJ4nHtYcCR0@a|~P*XtS)@sJX+Ie+`&jea@pz5qBuj*)kD&!>T4DGW44qSkEAcq&Ma z&{Qisw-kA;NbmsgPPo`}rBvZswSFl&e!x(k{>~TJ#pZEQsrXHL^g34G#2f#D;@{rO zQ2R8<$1%)+tT~{ASca zvDJEcLqR8Ck9+rr0Fj7T$1g*|;7Atmt z3{31g=c=^GW)*M64)+HB$xwnDOV9l*Vh*O>wBuu5pJvcah~iS*CY_}zOd(^^Xr&#X zU3xia1_@+90`2832ocRv`=qRGt<)9}^gGT?=ty#Y0D=EhHm5K||HqVKd7ZEV1VSW# z`%H}%NcB`wNrmTYuKyBBe0}Kue z{W<7=iY=ZB1iqhP_^qKoYCrA3ems5(3k3cw{Nv#NSb%>EAAV~MjPSSo@7MM1jHf8# zse!NQkKNbeuc5`0lpj9_$d~fRPy+j}LkaIC#3rWl{7wsQ*RA_@&lE&$M?LCm>67;h zaclK&7RR5trWmqDi($um2Su?lQ=1;~04u+W4N1Ccc$F@ay)Fq1_>D~Dzlk^h1;wjDtwG~gm~a;l zF)4~xDTBvJ`ouFF^1xQpv?s;ur_%$(KEHdR1#?s|oA{T%oOobB`F77~@1~aaydFaB=<0i&*F_6g+oNBq3`Wyqme3`y0fK`WJCeWeN$7Lm4Xr6pJ%CCc+I0h>K=LOiE#Ej4GeQuEmcj1D)LM(`cf-`X=7;7ZkrD zM+M>Pz28^L$^&+*h)zLI3?gl|gy^Ri@{SO(XkP`ui05S8vNHi~C4H{S4%tKSlCF$E zll6Rpvs>T4JEha`n|P~VP(1VJgGUeZOv{nQE|K_@u9o#Mm(!M_EPdN%)DkQq@Q(m5 z(T^TIoFbw(oLQNh<>IYMjAsQjp5c}_Ko)+;hS!>{Zmw8lKN(B7uwX9R)yzy{7-ilbR@cXM zMl$w%Olnwk+2_x(7dy@YaO9>L)1yk$my+;WAHlL+7ZYlqMfje+56$@y$gpLM4qy>d zASP<{2f^GLktPVLzeHqj4;Lg+Kcezpni-QdJN}ng;HG0N;U5J8-&goE zPxxour_kZ+pdI*+n%{=>f7bo~Am{rpZ4!QW{D&%m?@YgEeW`woB?$gHme9Ee0W`1; zD4g8g4ixEj&o%mz268ohRCN)ZH0e@Z^x}-Z58Y1MaFSq9CoL7G@d|tSZpx=or4Aao zi5?>~=kjk&OMuNagH3~6gH1d=ssjDCMiX{o`adpl@@)n){(oVOCdeD+8`a&zWz%NplKFVZGu-*9w7W(`d#Tk)B(%LOoY zxHB)eZ8Tk?H8DhC1yzd>huc|t81)@GC12a4n0k8@1r}r1Y2k31!!W>&s_!Pt(>@!4 zP-SbO&dB}^+$XCBjl#ui00Sl)j_koy+o_Hr=`GxnMr|?7{pU1e3Pzy5Az?>_Z1wH< z*E~R;O@0bEBN7*8zR+wrSvQ|50L@exwb^Z4nmT4oFl8(nxuGR9q)3)nJz5XCY?ekc zDK|RoJdlp(32k$75(Z#xCKxzuF^SW!%vs&1Cp;+tO4;$xv`{xJDxrNXy zD-f%+RSw}Ii$-qjotItJ;t=F+C@AtSD1gVp-ukU5#ksRU@TBaIJU3js&*|j=#%hjI z=R)V5vVNq(6yKdf0XbOCUkVh$N`)$Fqax&t5Oa2{0>xG9#aT|*LF~dkwYuf0H)*Jv z_KIoI@NPZ(^1@2PSae#d?;FTA@=hy{VwB^$W;s@NV7%eDCJQ3Q;m1MF7`k#LkP$ z9vRs5*1XzL!+=JI>s_fs2}mLUSd1G1^P6cEjVYOz=9jOi53)d2wS0^XNvoX{KT-@< z)ggI;keBgU)Lr`zCmq|-mPg(uEmM5DV?-KGL`B5H01=jtqsL|1@#+YE=&-$rXmo^O zAZEt8r?~3~MID>2Hj1axgr4@KKQmEuOhk_qLICfj$WOX2)(@S@O@hGVKox%m`Vw|= ztkG5(M~E;@?r~+WMcLBD))Cx->`gZEBwrY`kgiHSQbRk&R2qYw7E^evGfcu5=-5Va zY_G}`y$0qkn@EN&+Q*bUaR?fGjrJ5nlP0F@cKXP@Npjxu+5tCkP>6>%O|c7phf`C40M{KpiY`w}$aRSC{kJ-x4XRHi)$BuSY; z=V4gcpeQ{g@+N*ipkHS$aU1|&;YgZQ z%E); zctEA3?$kX5ZS=XSD3Wlrsl9 z31T@2NC9BjI8fHA`rCC!Z8xS%Cvr~Bn}+6dGRb)LrXz4biDUoa`>*d!Uz#8Jru}Qa z!F7n*-j~I^SBsCuQ+(%$I#4z;<1%-spn6%*GzCh4On&H9)PjPsQYFO1M9=_^>HmoD z#AjO@c0TJzt>FB@>gV{j{~LV!0w(hL;o{g!ZMI~ug&?)fOuY;4OETHbPeNd6OQ8iKgfFn)xOwg+6b7Bw_>eL9WNvyTW6-XEXDtx?}yVbC=~9pt77qF0j=`7 znk0e?~8nLVW+uWXhlZ+u?8U{WN_yOXdU2q`joDUEv4Ji`Hsd7(EY<>@wQws~E0sjnVb$9WOXI=q-{ITkK=7Xl8^BLTeSZqR7wx|J>T)5+qL6SRl_&R4}LlZ3OGkc z7a6wFvx8Mp;L5^S2=qV6H+>!s``+wk@?nl1a|C(>8bzfgyh~2iZ zyV_?B%aU7Daf@70^GR50kO4OvU^RKnwI`hD5HQ8^m-LPDTc8*3YR)xcGpOyt$SPx2 z>q9$!&VM`pExv`ob<+6=gAgLpS2Z5%&m!mBOI{=?9c;bZixJo??YIGmngQQp+~C+H zKn_L%A^;g^q~=`N!T7u3UD)YRH! zfmr>apsn182UB70?HLZX6{vY_J|B-K=zvla8r%s;WwK&pl(T-$Plz^q^ zwQXd?>lEr|93%svZqUw%m@V9B=b&>z!+I-gNo>%S*?M{;d3h}GtQ^2T%%hTB%T!7YlKUwN_9SI$ zSwdAE>qMa{-SmY**-YT~eBaVBaBowHsm_fIW9n;MVZ&sz5P3QvyrBqmRk0lginC4RG!+tZQPF4Bb@V^g1Lm0(+L0 zI^W>Zd{$;+scb5ju>TL={{!C)Kk_Z`*L?dp3yh5kv@_dU9~O;qtOUl|Afh#PH5^+X z;H`&Ov`fMra2>pEE7Keg;SXKXzVb-pYfK*{{FtN!Zo>^tfF<~I{@eL)@a+ruXf(Ge zmXsEP{@Bk0rkiZF{YJzZVH@StKRR3m3CQXbKzR?ejIfI*$tP^W`P{DqCki+WdM~L= zPU>9IY;yGG@O!>pIb)I-1ydue+|L{wTjy4l*olNg?YPDF4y9Ao+C-{<(ti(#f3a#I z<*}5Rq-jO9GhX&dvNb@z;RahjosDj2P8R`W2pmvb>b-P_L|H#>4tG_p+Kx+jCBExh z`jQOAK+JLIAHM$wz8QbyTlBB_w(=Blj8AjHL)v*UQ|CI~b(H(ujIV|eMCnQv%|%=K zK_6pO6KO+$f1YmK{pv2tCMJgXaVYiUN6rIab28Av$e-ie0`2}u* zSBa%F*ghx^1bCKa&MtLNxoeQfybvpNxU}#hL3{~ zUhT={M%5Ti)O@ln1sh;A*n$Q)1+GC6dPzS}IInimEO$$vra6w_0dX^o>+D|!Ms0um zhwuM^Z>AslmilYH<)?UHk}j%WT}|U&sU~`w6^)FJIuJb9MD|w+A8U@#R76GxSku(q zd$rhb7#_fI*O+K640V(9@z6~mL)eFI%uk6lUvHSR0 zOCq~-fGao?6Bv$gtO43#DHzLaL+PKgAcast9AKz5TD|CCC%)uxIjM$_j8c8ix8RPD zDU;!q{#8`YDe6+S{@iFKt>uPU2>&)FHU<=L-cRzafOqNRNUZIpVvf!&ig&IWz!0$D zP6fM=0V5zXv#$CGcs|5*(=A1b!dkZp(O@U%gVkqu*svxKJh}&?VQNm^@ekks1K-R) z@-6?@d^0G|;Kd-3+3GdY-lJ1H5 zBeJo0rwdelUXN2=6N=wNrxX)DSW9gO9DS9P7pDPpE&@{Y*c1Aey2`JyVz+e+#i z^WfMT%~D$@lAn7%==Qhx9);%xmS#46t`{&N6SD)2pA6xl_a2vE>wQ?f!x9O`AppVL zsK9JXUxR6J-#(FqHc9H!`lyok+b&0bs@YkGl#B2AmJC9!M%Qgj80aIx!|odd@{Kh< z^@(2jD5hhGd&k6D@soVp>b*WWXevh3OH+b=16yo06}VWTbKN+Pu5L_^C3bcJz(wK- zNl;elbqhsFK4O+=%5R`z@F~ zR2I_6OEJdCQ6O91Y4hOoXd-; zd-!vFyZi|NK0h9ycHpL%c0J=tD z)4(WIOGjbaiJMm3ZT8Kl`L*#xR^Rh|@|-6h4TGq?-T_Y6^saM;<#u4Bgk^ z!jn69y$MoY1r`;%>vnj5>uQwy58wX--)ukft^3z}w>o-oej&_K5P%TbA(ptrX-N{4 znb=!^t97>AJg@Y|G!)OHcf{7cP*c;Q^n!AOW_X(C>yAuDet5uNbfS9Y^mBZB{4KsW zc6{`EgK#bf38Pw9QJoJ)>3J#VF9UhP%!OLbg5VYaTAPeQ#$0oH`w7gSKQebx7vjG` zg;k_R-!+S|;sw2j{hn`nae-&P&xqeCIy;m$EIDDMnBTng?RM0Dfq zV6k$;SL=R$i$DkR58wX--|Ro~ZS>cCF9-=%wJ{i-K2o9@t3s)R2drZnWC|v@!_22UPciwve`sle5raa5{!UW3uyrjv}~u8M@w6nqMqas ziRA5gEa!KTePccrXe{+|QxEj-`0uCJ6gPu4J}pqLeOhAW^(W#1u-@454Av!AMc56_ zw^N=42U-r}uSuMgpVlagEZ2^n{KcJ3_(>M7epu?guCM2e@t-bT|j zF9Q9ZsdTz&JkWoN6`d0*O)lBjU&~)SHE6q6QB%G_+~kP5&=lMds_e7l%uND{Rprid zWX?ZALrF^#V<;N$(J(6fNU%(8K7o<-urfHy(im+1RwgU+iaL>%vSA2;SH;2nbHCci zni^zF4gaGWo<)J%Jaytt z3wMTDt zX4kC8_RpI$rf1X2Bg$J@tFsvqgoHMZI?!d~+t11=QfxjG;SR)H&9K9DE*{=2l5-um zN7l^{;-%@=b@JT0fknEGlUcd9Sk0r504k)zPC;X}!HQpNof#+IicWq(j;(FXGp@mG z?ru0GpmPJl4u6R_-1y?ggK$!8;i$GJN9|j zoaDOXjT0`i9`87?krst!a(Z9R`&l}ZO~wzdFgI3+1>tbLin%_a!qH}lopxzH@br5| zqVEH2hv&cw_lUWp$x^E5>eKD<$MUzPwSfm4U>1)tVjSfYFI-VCQAo-H3h#W4I5+O; zdqFUOJv5f-@Kcc{+4)E315YL#7TBh-?v|Z1}Ne{Zia5AUzY| z728^SkJC#f4p|{?!`wYg`c4G=HfCRr&YX{}Tw!4w#Bo?f>_oGj9)?txT2#rnHgD}k z!ZxkZnTAP8tI&nn5K;C=-`EVTSYiokP0)x4oJS%@9DSJI4OGO|^YI^DHnYWdJaChq*zwOx|^6^xhmADPf8Wpm)?!wn=8Sgd0H%Mg?Fl>Gij|%Cb z+%Ux&6KxPtP&*u4U2W~&d&4f)qye1r$&Y5}(d~?4tE*ewhRpQR8`%;cc#6S+1~=uU zJ@lPE+w7#XO~NT>)N+0wqm<(Y8~%gexxUjx<{B@nuAvaRo6sW)6TGJqHeF)zmVH{O z&Z~rSae7^f&_tS8-^p9W1)C=6`fD7w?e~dUQ|`riqp%(5qv2G~q-5?j)%b`0n;&?3 zPw|_s#UV?>gq;a-R<|pdpbSyu4>w&4#Za^Kr?)G8dR74WhNCi;74QxGFECuL7PSZ? zOFGR|m7hT($bGEU(`0ixmVR4<{NZaKnL;a}CE0T~y$zHie`RCI3fxHz3t#J9vrFDu ziCT0q`jdU61YT~iWwc4Tx|!x?d6*E;9R!T(O>=5c51dXXgoPz#ZZfMgFjdSmUl@LS~s_qZ6_a|M!45K|`}?J{k6F^8WoSLYj0c zGM*x;&9^{M7VZE<>K=`2+(5mVXc(M~Dm$Etuue1VH;Vnat-vZkutA{z0RAV)|1Ias z^&{X8e+{^L6`A|6TY%-N2s7r9UIe?yoVg;a#3GW0^~l1V=EjMg{a8nEa4EIGI|Jo+ zgA#yQNd7%xLQ}$ZM7WO{gw8{ME6DjjfcyMCz)AOpe7lpuW4bq&flJKcmhoE%0xo8~ zQTwfNAg(|l@c?-D)}^70>|GACsGP)R@&v)^sxz`VR1G4*eiO$myb2wkp8nYEnrr#1 z2fwt@0`|X_zkE-7r(jPVsSRU%q+O;DVH69EqpNs7ivE*;4^o;_$BNnuhs%KtNLP8H z=&#WPZk-X7D?{i!e<&D(0)&doIZ&~!sTswOF5(FR8{T4}a(sLXetcT@DmkfMo&*p> z64?c@dPAr*9ux-M7#g)R5b)N%z;uSp;2S9O-jLI6_sY z9Vkow9l)wPC^m7tl?4ChG&wc3_hAc$sqU7FuzlQzgEkrq^6DDz@vGt-X z`?CRoF&O`ry-}uE#l&WbSiaZS50Mx7n|L&9(4JRmtT1LplMGCpmwkFUdfLh;FLrDTJSOyO&it8hYtN z@Vul@?M#8Gh}78JUXAX+$ep(9p!Ig_CfjJ#ZdXM%!_m;Q3YPl0 z;iE|T;!ajaBPG*04`x+DjtqMl@lEC3m&BiYCxON13ZM#kC#B7BaJ)3}=cV7G74R(K zMBFV1$F`-y=ZMOjWs}g1v&^n3SM#~0SQ3IP2ow}I21`-qUKPPm0o-^>K(Zru)yuLXS{Pa?3Y_TunIhceG3c zgI~xHA$V|RdwUT;tJb8#a!%^4b*@QG8qOz6$AORf4c3Sx{naM)ZCEyRn0j7u@oTH? zky6t8gM+@3Gk+#kkfDa6pwB4@M>y|j}PB$ds$-;DjbB(gS z5HTK+)?N5^I$>7-kp}hn7Y&>c&c4g4AGRm5#rp$;qw%wfRIxaQsg}F2ee)_sQ@CWMa3x3wMIeCL(H!n;#+?4rYT zMMP#i9h)b&ntID84Tbo&z1&W2&Rn%M`uz+Z(;8WpLj5xBg(tYS!nab4%xs=tRU4OC z309~=)yxfyxUTAcW~NEhAV67Xy=Z4Y^W$CVy^TJ09Tm%jP;irmze&*{%`^7$B03Y@ znK4q0>Mv5me=wqG05Js1)}5py)Ea#J(9PSXFCv4U zQSKUY{j9O|qVCZDY68q^Mx`tFubrWD^ofU)O_^b$CAlE93FI<0d6t9;WVL{Upf3@F z@v6qr>bckAg&l-jr9DD;3H9>kWr8W5Upg;z>gkZ&{oUao{KdE%5J8=Y1u}g*J0rGSq^#36j@Qb)D{cW3vDu4 z-J3})fcGnMHfCpqN<6gGo28{|{}Q)9y!hTPCn{_Yx5`?%uDxt5+I1um)b74P=I9G_ zCS`_bTCv)ujmPEuxh4sl2$j8p2Q>`2HId1kf*r;cIr1Dq*yAWI|~N9cpgbECvudULwiFK@5>>M zOjZ4sml2C~M*XS}rMrwl#fbf2w`6^HBL?#xlobOB!gig)mzb=5jlVR&z_B~7O)u2~ zXFRVW&q+GFhU+$2Y)%~_>FVa~I6F^Zi6nYfMNK-=KAyfwbBZ)5M${B%6k0%*tuCk) zMD+@U{#F6!e48PvTQa$~THAyOq<>WuuyKRE9pJqsKG|KMc(fC}YaMg&o~1a~y;FA# z7Hb&X7%_BQ^Av-`*K*JYGTAJ5 z3ew6a>!=oD(SI#u#0buv2JPLO0W{TnrfSV7KH`jJ=hmx37WrARFWs2=rk<#!`J4lj z>FNXZ1jV&bX-fY{T|}>HrC>M=T$X72XIHVp28`B3y6$&lO6s<+F3CT!b#?2H^HB9| zUZtbPn%W=7lQ#PK#^$ZCrPak$tfS6TA(1I^(x*gbg!YW>#L&h0t~$Omz(it~En#ZZ zYY4b#q@*2r`K3t>4}PT@AX+_e6#*5+mSoR)``HGfmh+LVcm~e&!<#qBaV0HB0%`aw z8pV3W4WgZEb1F`LGkhQ^Ko#D z?q-CItQz&8t*rS?6Oem_2F3JlltAU0U?X_HFww`)b-;9h2In_E#szKCprDCiBKg(; z97O-ZnapHHXvQeLQRnQBLOR{m5*U$0WiETu&TsCXpM80t5Zr7jgJ#yKk;`L^_qldL zKoXHd+@uyi;Vx3Pp)yN4}N6 zswS2YC|TiVCBK{F)9hb4lmvNUy`y?kb@l#PTUmp2_)>cP4zas}l8r&>dwS%I#AQ`Z zA){jy@tOyF5rr$8B3-Pq{@1UzJ2P62#B5_!8g!I$D^uPn;TzHuAfC#Jx1AK|NDZ!s zXp5;KPq#VxYTuXForb=CMwqloO2nko;D^;NuS+xE2OQqQz-^%&`Sw9qhe zFU|8+Sz7GN4rvZx*334_5hhsspwk>{Iuk&M6sNs$jVpotR(V5@_poVZZJ+OqqJ|m-BX+_ z_$$DKNIoj4^^kvmcxaK)?dVqh-um*lc`>gIyH} z)vPf5*wty-FV5_ou}f#;oeL%=(HY}<5~)LHFurkV6{!0m_M@GjNbp8fFuo+av6w_O z2j$kZPc8_{Vs}8aXxFk@$zvSvHJf1Cl*uc<3^9*+NW=by0(p}U2Qy=CIJ*S;cg_%$ zl>=%Ik`y_Oa;(Q4pB2YwTKi|j!$tLAm8VIjh$S9!jSe(`&gUOk;b=;(!=hd?@QU;@ zazX?&fx@V1&*hn1t)EZP7RAQzg}+egKJy-F>!3u2X4a-&>!o>qS^sP$N@Y7-6l87z zA5dV%F}e#XH?8PZbZwt4y9lRVtkX<78cSIF}&*^e-yQ6ygwO zU6ws>LWbdU@!d02$+CDFLt5YlM%~*`IlFQ=3g#Qw(Vei#sa^4xNys9pr4U2y;6$X0Y3NhE54P^bF5!QYieOxQy9I_ zl#rNpOm0+LZtS3$x91aDK}+i~ zEJb3ax%637``{vB`&g^YwvV%Ryq#Vx@Y-07%>;4bGrVIYlH;7xf!sQ>Rb}F*Rt)B) zhP$Cw&nf!J+q2NZ;uEG)_)5LIFE?iy(j=vRcG!{;J)Bh~R&_n2OJtYARq+DQ059Oq z6Ee4O*tYWt?cA=*i1uagBBdhyXO;c|VLZa8!sG;+r^`F~1c05veaE7nRRL*o&FUif z=L;wWYVovT)Gz9kP7RlcU;1HtMlcT|;=JHaX>Bu=)KA4{inm6Dc@z2R;Rul=D&RX#_#}?e`5w zy*fO|LPhTqVju@LWgbo(2v3FaP?!zqxLn)LLgjS8*l^Rt z>{aVM4+B*}QGaU8vwQw9EyI_62NrVxytcg_V}*b=9#UO&6G2JM)(_1;x#k-o!fX z1B)?a@i(tI1lADFJ7#kXKl|)QZ7;!Tvlk_#Yk|n`Ax%ABUe6nO8*oeym(!LT$GEt& z$sPD+wd@3VNkJu%J^P~MQ6GvmE_`d=uz^Q9_i_1IjLR&8u;=GNNL=e4y4Y#s%KgH) z_r_Jo3Fd6ko5^d*Rzn2rE-W0)EYnGu7DDePLCpd^om}J;L%JNY)7?2`vQROM4jwMw zI*tw^nZu{!xF57LLEq%HHz}WFoO5V0X$E(Hu8hmx8y;rl3IP?2cpBZ78cVnn*T0ej zShIV*{TOubfO)SMP(V2ykTu34+deXMOmE`fsT5*H(B+v;Usj$tU(S4U(}+@?T< zjQZ5Qk1bu5;VRYkM$&QFw9E)J80P-rpfi8HLKg(RNt3HC6tMnt}T&0u~Yvfj*mhjvHIsGm-=R&Wl zP@E)^gh9((n&d?Y@;y97*S2fSi0 zowWv{?abG0G}QHKyJQ@I#kN!G*6(#kKc$;|HbfDsl#RZ1tRxYyS@&TlEA`54kPL8q zUV-C~yykb&h#SL_XI^@_$XH{`o12N(dp7ahnW^DMRrFlN6i7lky+0DebfXVm%_sO#0L(AaYIJ zQ8QOn_i%_20KM z!K9d3nEa8=oA9l;tq8@ItB}lz)=dQfxg9mCOD*gM%57mjyZv@-o{)SOCblu$6-5MR zpWx9~g!hL+4Z;U0-KDvuG@vc%z zfHvyH0-1AB6?q)#g&U|%w-e{&0|h>|nRpY0;e$$5g!-nGYzgJk5Zi*I>@jqe9apu4 z$xaThsrX$6sEv+`O|Oi1oSR7z6y`l@%V)?5ozUWO;m*72*IdNnLnw3gA1A_dD^4g5 zaR{{2{n8iRqACMk=w{}ii3)K~@7HQ+jI49jiXOqZc8PmaoK~6CM#Lljv|0tBtI_LlrzmH?vu>1K5XYGUm9c@>NDivE(tgO zW#N!|w+@!z%M(_RU~B^NQ-g93Q1e&A>2L|1zM+uv38?Bo-WAZ%O{4)nXLkftCZ#h* zL`fF-f(n^c&Mna*wsf zRvy0eCBI)Bef=>!gHo3)#`I#TaK@Rv4X5OVJ3I=IO_3O!<}Ft z3wkRcg`tI`$s!FV94sU1ZQ(Ty0Dz@#YBZa3|Qdsmx9dF9N5lk~G(B^x$_<65Le%JsSvq};)zc>r! zB8Fk(L2?_;S^7zOgb|>p7Y^}6a{!B63bAT$Ej0z>!4KrCLoN{&Wd%K+)d#R{y5@F( zm9(<$ZKCXmq|$xds95ypja?a<3yL*qTC}vso@j4aA7<$zlsu-rLRhUx@ZDBMuA!{B zD;b!t7ej$h>=yHpVMaTX33FnM6@QZimCT6n0^$W%smnn4A?~gllmslLw#UwGro{7@ zOGgz12?hgxC7oiYa^Gvb;<3kW80u7j zk)<+8A+a%w(hK$viPkpGYw9!ausI4Ywz>*J?5~<2G(*LAPz)wQ^zT5>u=~bM6&sV^ z_k#v|34U(Qt3kV}V5_$f7an9Zya>)zRE{+eu0^*NaICJUvG-2R!e~*H-LY-kwr$(C^&Q)`ZQHhO+qR9qmAs@=sY-QM9`h^q zT62!Em$B;U*6Ws`V=I|K9!q5jy++;R2=qqz)K9hQMgyi63LcbBLU)(kI(Gh4Jb*4! zf6Uz^-3n2hLcW#azP{{A?z*_pZ?>xk8iq>JO@N5&ST$?}hfF>GI5Pg*vDL7Ki}+kt zaZeVcxx+DNrjOza*}-NSypskRHl zgZ&^QZXJE7D%#hAyDj3AEW>>kXT{z%KUD9Hx8L{0i`(g3fRgQnY;ZbQzqpVFhva>p zKnkZBWUzR~N}>+qRNF2x8RI&rr&>hBbLvnY_He5GV?$`M2kg(RSLw}v|J-tzXbSLZ za-yXAh1fzo8nyCGIO?;Rd46F(eEouHqyy?Jv15DKeP&&kp+eyOjS(x6H3Kxv2YGqL z!_0WLI?GSN038zwGu?g!6CF)4vR8!%aX+ogHu@xLs0zVqixB+E+Kv^w3rKT&IEY>^>;4_O7sYUP)*!(;irS<`X>-)BWtis zs!kD|Y|5N+o&8?;=!5(htkqCF74E8Sr^l}%n=r@;2lpu*V{!6HaGKde%}*@vPz`!s ze0`I`s`)mI0~fJ+H1qh;!fWOgioIBSD`o~-j{(PI)nN=IQU1yGI`?ejuuK@IJE~$^ zgV{-Yf*a1cgA)g+ayk%v6T0|LM7n6Tl(1z*5e0N{jPlyKZ~rsy4^dl{ ztHQ!JXuOz<#;V$=U>Q9U-(~&CzPMaKuuu+3X0LTS_M`Wa^xJ0!s*S6Do2Z*d{Ok7~ImlyB+0wymoM~x;N2sd9rfaZ=MMdMW1?&J@EzCaFENI*G(LN+>oEo`7GNiZJV~Qy$!wS z^QD{HyCKc_hSvkT&Mack*Hd0q;Oe=Na-SB<{2D~>8 zpobr#eaBdQLIrQu(G~%dOWKq{O%VGWGov7jK0&-1={0EGi-kX#;SDkn4Rn0mU+|n} z@KvV873GEEcscN|)f7gnz-=?2awTGJ1X%A;e%gZm8LR(njSSz&H@{B2zPYQ@mn&Mf zpZ&VkE=g;R7j(}9|8#U=B3YmrboXA_A4T|&@WU;}N}P!-vd=*19UnKXeyhB_w+{D3 zm?Xa5lKr?j=ykEbGILjMBao)%7^$r&7PO4+U&ZQ}6+Rrp*!4>)OExh_o_$>Aj^3Xs zfkh8Y5pk*tU%``#XrodF`oekSkvtmABlgtqwAbEXObiMf=}_X*oT&LL*jOHnj6EIl z?nJB5yZ;b^F!_sxbcK3ROvaydpz;18i&Uu%HEb&6^;GLsNjpC6YD-9Rkl2yyO`{c- zYYxN<`q2Q|#Ks>Clb}*WulCJGEYKBt7Op@gsrC99h3Fgh8ml5GGN^gs&#_F$`X@nX ziH*xo;?HQd*_QTGqRMj})JYyACus!|KVw|^6&UtFht22!d2p~&KU`~0VCH-12}53% z|~?!uTBwHbhW+7F+9kx5mgfei$8elb9C>z%Tf1czs{t zM^O`PKcA-df|l{?u=5s3GKq_jeMiYvEjmGWR9UxU8vwioF*F7oo}{dWhmf6m^VE_g$f@DOj%)7O0Xb_;cS~t0GN}9d0tUc zT%QESKEp{?%UP63#hNbq7yX2voxCOpnS5NgTo0EueLJ*jItxzXi9m_`F_~f{iEgB) z!wREAFka5h%vI|oYVA`r{KdB|HEWnG+No@i@_vgUdsE~u%d&rh`9;%*2rd=hn1b!g z?Eod6S;Op%EH;D59LrB<`a~iYC1;FS0Lh+Zv)O@Hs$z36j&z&XM-A&kqZ-)eWq-JxCHK`rYCMy@-!UWuuV_`sm41c(9&K1t z^QC8tzXR9jtOOsZJOKH?v2nEEzrefY!JrnE4USBI?dHbj0wUK;(Ar$~)uer{6q!C7cc^j=|q|GDZNFjp@X;2!5&j!uh&pOz5 zRRKz-6gZki^eMhKe*IU*7Lqn#t`HW4^rw~M{o1_l3EMSIw(CAP-KPxC{WVRKK(|@1 zU%uvAks0jP6FsB^je0ek1gyjgA}%ilgV<2nw&&(B!_}9)_Hqs5(|Pf|*LV0}ET7X| z_kd#Y6kH+Tn=RO=E)CN*(y7lE4lP+D@o?zQ?3@U^d{P;j!S-#++BNjb3=6tepL?MR z*AbTrlsYsNE%TydWn9qCSY+B%TK<^9D>MAqIh(&h!(L;n*z(D>Do;#$DK9%+V^P387mEe*XkU@bi z2yUK+aCl-J)HT7ImfZ>b_#Fh-thc0uQ^P36yY6K;!tE8uh(IKx*U}Y^?w1xg*H06n(;a$a8VMG@9p|{ialb{(det#g& z{Rr zap~OXZg|L7e;F&MYnQmG6-%Svn#L*{82=r;8)nF<_yQ+xNn2EkGeGub;#)B~^V*U-lfw~^)?urPM&kdX>zGTjv z1s`TGWcI>Ks>qAwuv3BsIah@W*eCb+BR^g$Z`sk1y*7SAwbFyVxQ4KK zo|vwj?%WP8$Ly}#FUc@BOYNq#*q4uB#$Yu8JUhvNQ)4wkgSStBVyzA|;^)b=F!{RU z?Y^I6#R#_(m zg>Lf@*xJ8WcRIj{E4kCX8>}^m0a%`N6P~)mE>*koY3t;6!`#rh%d`?oU2yqD!2}G{ zH%x5URReZevu-^O22F|q!=;X){6?~O=FxgvYO-|$^StZ#AQPPLq2+QoU@tn|TSwbr zuZct3|z zfY5+>*uY8FLJKL&)$>-O0C`l}k5;~$wk*yQ~b$lSPHx_S^OKz)*Xf0#X zy$wHh!fFTaW-*&LM1g)G_0F)3SV{C-Aut%Io5QOU?9Ab{s_px@gDIJz`VYan3bZfk zRD9HWBSQjnqo~C3E4MA?D<;JhrIGN3mJn_Y^KWf&x`KfQ>1;rYSx_Jclj_HRyT*cRM_K8gMJm+*2I!=Q5W$JttwY{O$|PzAmq`_3zkyQI*|?V-icpTc5n z;31t1rSYRc+fw@?hz_64AOKz&VX(p(UpLSjCKR_Un6X9zSle8oztSCk{=&^YN8iV+ zO%}Yw5>VZi>o#Osf@dpwN>j)cr+LC>?#;bZF$Ow(nE2W9A>eKK;x#Lt%Eh}k;x!wx zeNOR&gIH|18o)TG$&00)zGEaOaYtZLQ$9CNX#Xv(Y6O$BcOM0a_tM(7oovVO?#g^r z5SvvSe9Qcit`hXn?60y5e>Wu7)?qVa@3y-u9fpk&plFw+3&e7RDb57y{EDrCD3c$w zK8EhwXY)Lour?enGb!|$h^Bj)59m|19EC=^$d=_RX;|wJmZTZ0Wiaq1cV_X&|7~<6 zqX_-O#YB6T70>J5zY0&?QR?iDw5Tw&>(E!Gx~f8^y;$se(Wk?G0Z#zLITfap<5-=n z&gAhF71qkK&1~dl6uXxqxxhA?Acop&ix4fAu~F;b+>qtn?t5qG0y1szMs(}8Kg}9a zGHRvs8>sOF;U4nu_(9AGtY?VUY!$4Nu;`kAOQxS>5^k=48#L45!UJuE_{!c%euD=K z(zDo#U+_C3Z9Wu!PTvwI7G=?w1>kaYnS!w1dKQRhet_GZ?dyKA7Tj+Ox=_* z|BaNz@h-f`#(@6(Q7r~J<$|dJ5Z39jUsa*=jq~!rTRtP0%ZA*Pf(2$Sda!5*lJqI7+p=WtUggy1~ zVeYgd?P(E(dS%e=GaQ*p?*j(QSyqZ)31eH0#>stgFC8}(5w=E;zj7`M|GD)hq_6Yg zp0$K1^YAlEzD4uH)u;ex9j9w;S~Y8C*ftNfQdr~@w_;J{CM$@b81Wp`iFIJBdu5aE zV(=|CP8o_}tIjuq2(8S?%q2Z(>j`va2KTOHewn0^HdG)3LtQmcQ4h~gw;aDLMX z2^4N;_XmR3KwybE(!rMldXh`BsE#3QdL7Qg7=zbTYm($g6Ms! zt1d1DqfeSs&VwSi0X3aonhcJFXJt*Y`5~+uYkPQRGjOr(4*qadZtQY>D1KM>dfRXC zk$DIn#~=4F2N59B(1i)H{##Ucc2be6g_}F=Lz|j0Vax;kAdLWaI8!g)GHkji^!L1W zeP$`ZXV6gOeQX)!QkQ*uFTZ>;z`wII2rFdGJSp4@-6km(yb?ZDaL$J zn?L>_F0156+&xa99jDv8M-WgseMlJ6{=^axxwYM?u^c82nLKRA>-ZY$kVd;`=);xv zU^dkbJtNqzFrB<4JNA)DWr~-iO<5**tn+%L= z*oSJ$iRZL6qw8cx>**ve!Dh&JZ4=fFOJy0%HTtznOy2w6`KD&A#mU?KqSUI*NjYMJ zE>Z?ZQ)&8O&F|FZGL@+^eCSPkVK!bodASd3Kt?%lb3~_5{Yvas|9H$d9oa-RZkX`x zdf+*BP7xQ~IV)ORf!4(^iAH}$uk=*C8fy(vPm7g#j}`UMHwew9^)rf5Y+#FVFjPR< z7Wxl7({pLWAK@d258h4AAqUOTRtATc+29d_Q&~qUIGSDxP%h& zK~nPW_0J`8^PzqE4p1%;v9d8B=sC3b&y9vB>sk5_j`SOI`@Or-ujJK0ndMNKs%b4z)n8W?m**WAJFRWgIU}w@- zw8Mb7V>&H<^4sS&=H}W*)YPmYE~699Ga`*`+Bv}XKx|38*B_0FIlTJ-2>XfAlY1*X4M6ltG!`Zi^}~t%s82{}BWzPT5Cc!e<$E3b4je*ZQuHOagLO zdvsu}pxo09!O(kzP1s^~H9xB>nTb1?9JRlOAqmr5gZntlTKe9Q=NzLlxFjKS$0LoN=m(^|`#$N016c znb&kVq?FY1M7U3f$Ix|wn0{6048G0wkZW(AI1Cja`Zrmlw16C(V6+o+sO(Wun>+Or12&#Hoa-7p`t0|~!td&=G4(N^6Kgp2n0Nsl(y+{-@( zNB{{Pdlb)FpPp-d9;M zZP$9Z_-JKPA+`BTrRp@ukUbmPlk}G;^ryJfFPXUj*xN;K_V%iF;8qI6@w=WXel3_> z4DHwSB}CN$Vf0grUa0`^#P_ic@LQ$=HWP%Sbc?w* z7t1{#L;2IoX6pJ@Nxm}y;BK8Fb&NE3C zzg<-hi=T>F#9zQg=Gp9TQcH-K+KO|>@@nhcR8-ZL;}bQV=r`n74XehVXc@fNBxyeO z3g73fH@ucWk&tsGw}1TgOOK!yfUp>S_zYKSxM5-I{AQ+;fH{4Oo@tp8@lO}<1-MV$ z)N{Z?GZ~1wWONIHbBQTntPB$1B9;w}y&f1q&rvo8?KcS%2(stlyK2a?bt0{!$nY+2qxDjQ$gn6!43bm=cd@c9MvXs-VwG& zlI|(!@obY4(-DDeo|e5^OS`(OFs4dbs?O;-I+P%bm&JahT2E_5X~dpvMbQ1BCmEfb z{e+vS3krUvBL7F?23(dZv<3^e7VD}QMD@Gm#G}DeK6%|S1E2&)6YC;-sH0ScLxoMM z#1T!XQiWoMfwrn<29(McWgCqm2)**(U5z|8tJ*b2o-Tl$=Lg)dMg3EGlB29gyNIKV zoR$nBWKttv-(blEEB9lge9|nGaFmJ%?SVM0Ds!WO<0zjoKkNu7_mn0GUT$1`<6zU88dYhxH~EaO?3JdTe4hr$}FjW z@L1#)RfHQkaTBgQ>CfA#tkYy#KhWWrnSimb&}4K(kPP|gTDeQQC32RIU*jB~!#4tq z7J#Sq1_TPzpm-?RqOCeo9<7rZMikf-7}?a3a2y_Qk9m)T&3$N#LlIvcYNewlJz`11 zB^BhXJWxvN4*J1_hXR6|ufkS@po)Lns9AB!Epm5|1A)&Zw`ZhAK-@a6KBC?7gLk$| zX^{#qF?JiuJ-J`z37kXdK!-V^(B;zcJ}e(}D|xb|Jk5)E#BBS8A4r-zFVV>4#)le} z*$(R+Y1`T3@_hjo{at;(oZC#k?v?YdR->L}vuH!`fUVb?9nVfxLV-b~Uz(7nA?1qih8IoWKkJ*+UaSo4xH|=pPsd{4EyE z2gGp8CwiyYci~>;5g5Sq`~puaHzqJt<>jT20FW_IeVn{=gj1z*6&#!k6pmQ9oKYX} zs;Jh~IWMO7ya?LFJx9`n_V$xpf+NHrHEd9{BZx;Q+J`XrBS4>9u_4gkdwJ(I_JR0Y z46!n->7gw=)!=h^^rfAVClSVOlN@DZq5pPCuAiP_G$50A=3^)edlXkrio2Xk)@>n0 z_{GrrDtMg7-&&O*Od@`g@UVKoDi~g|MGtE?ATIw?E&wP~4KUCu3q3dNt@a8+t$MJ+ zP9?Ngedm)M9>tm)H|STh+Z1H)ul9rMkn*JbIkjMi^^_<+8c_nTnJu}vF=+s#k;rr% zBRx9Fh5fI~aGH9D-vNqi^AZo;vYrK?@yt(0M*h=OKG#iU|S~$ONP|nf+kcaYQiH4J{ImjdGV}CvOzbYx%cM1$6p^__!>Db^CFQqxP^Pp682#a z4e?%o1n~O!HSsR)359JA9pC5!6m^uwrAR9uBr&xJbbIANA$r}| z1Qqg+I-Hb1Z#!PEUVov8o6)pnkS5HDFNJ%3)?B*tCMJC1y$X>@x=9*!ff*#L-EL0C zU1}TOv>%$YUKd*28r-!#wENHHii!WA%;tHBITlo;of;Si ziy$D*pA-#NA*FU!_jCLbuDB{4ae^22wR(Dr!Go6u2?6z!6lES{=c>&tTzui*RcZzy z#T-;3I=?J(2AkLgLzn{#OYM*KFb!%Y1Z=&>-8heu{p-=5QKeii2E(ATr#6guu8~;S z`u7KS(3C5kTB6l<>0lQUcCbO^$TYHi~`!Q&3!&#u8kU z_$ta%ib}=Kv7G-S*$T}SGF}xwf5}wu)&cv>jLDl4=XJ@Y*7uGCm0IE`*9?TM8r{l3 zXu|!vv)zuFqpe0lhA0ikjV`-oaP>#CJI#Gpa&vY;Nql=q>K*u`!5fv&1J;}l%6sEa zwTl7GIF3wF+e#oWan_*a2yoSTR0=*1&vnXt(2iM%{B=fl-qfFsmf}btwmcRnT%1uZ z^ag;@yuzpkHDlkn=JxZI-L)kU5P1MFbzyh@?*{9C7Bi)F3^*^rIBF*=(=7(Y6fL>K zc6B=|uR|0Rsl&x!WMw|n#7qA$0p!M3YlTA7G*v=>{;|3!NzKUt*- zjuVP~$ZI&AqX_pUU|Hl#Jenb9xS57ZEed6#b|OlX^90M__h{)kyt zW>r?TAo@s7U3?W=7HN~7WW)?`7wdE93D3jd1zn)T^KlspsCBC6D>p&pD}S{8&CpRK z9`7ahsF@UO?>PSC{ad8w@H)`GiFiyPJ1gvw3V>E`m=*eWt2EJeJ7j#xe>f)RqBvnR zLuO&f;ne6I4#JpR+g89m;xiMWh*6vLV*@-!NTrGk99X|fzpm6!#dNb>cKpbZcGw{k zMH>`aZ!aYeo{WnuEGzK5x>>y4-$$pbM5VlIvbL5aEXDS=(G;(6jgV}n&exxnH!64? zgMKT;WV=&2jS+B~mmR_HVS;ov-)jWV$Yndh1i>9|i@T|>(Em63|S@b^Wu zF8*Cr*)QZN0?TT+2JrP;G-}Wd^N}29Hmjp93wzM|eC>}quZe;v`&MaBd~s>`-*0&d z927${T7$opD(Koq^qG&~CEJpFi=P)RqdGJegAC8$&6FAq_rKIsP9^blDK?9Ogwddc zjhyeZy6X(})`A{I4M$5Qa{D1S&IbeN@Xa#I0VetwIdRpvb@)4xdyVM{7QlO5Dj6=3@Ebdcf=gZ zS@gAnj@l9Yj;(atX%*EY`ib54a?CPcScG=%Jtkt__brFW)t2O47f%dGD_**xh8}xv zbQN_+*(GK!L(8BdTK*9}4kx;t?du1;gsITyod&10V6pky75_vfhI?$2X-o+INj8Wm zmFvvUc+I`UxI*oirlq&{Kj62-Y8j1&n}`y3Rj}zS#Fel*K|@aH2BPmMLS6Xqp#8+U z5ot&j0Zs&2crlJJ*)%dEwl&E(vDali*bHyw2XJW)Us-MHSq76f*lUY?vpZO$v%YT| z)h&NiCeFpuEH}(M5TEQ^hslj*af2yuXa6@UG?rq(YE6kbb`Ad(NR=X3e6^(F$DduT z0F{B~#aK8IR|-Vfuhj|yIGXM?DfhT0j9ly=?9B1$5+#ojVyEtRKYB3w@Yg?D+{GFy zh^u9TX4t?ey7EcjRf4m2Wl{vsg`G_C`3`lsQO;_~4_b|G-NCnSy!<;=KJPXc&-GR1 z#;C`xw-Hs4E0{`ws%zz>QH>T_eIEpnKwx%&S6Q12p@yZ)~ro_{6Gxa+hrog zY(~N{Pb0pP=*S6e*?z%A?EiD+S{KAh0DbH074%KV?dwQe3aGt)Qp{)g`>^Y@(%OI= zP0iRivaiJo@NF`YM1~Sz(E%xXLsGG3{AZ=%!EWv0fgXY6r}%xK^j9{}a?mwvL@y8X z#-T3RopK<;NfE1AC#*t|Bhxk({Dn52q=VIY0NGd(o_0=687x>!1#v9xHzXPm{U?vd zY}MOlQhSL4H2hJcp24S*#;9I0W$AiEGBt^481Yl)ib+z0O{)mmQTmeXlJ>8AY_v6tTwu0)u7h{09lCo^7OFePX5V>dmmMd# zJ>Z+mB>cGDsOt~5uoY1U--{t$qF2->tO>;C&3x-#jmD+;O)oq!=NNiwoi(4%J_5$y zfV)Do0nVssgUrubAf@oAkPK;w`YX%3{ivP+lcP}Qe9z>6u3dud4T(tUx4?Ala(w!B zLN*_Eo?Awl3|UmF&jc<2M#RaCnB4xMOmT&idhWlKDg?AeratJR)io)kv#$i@(#6wG z*NXDGgCYyxs039m_ffdV2n{NF-1BWKEIs?yj+oVwyR_&?0H3Tue= z%`@CTq0^@vl^qQ^0VE2@({1jyV;Z%>2L;3-Ktqa@bZB&vJ;4#(O z3aunrlw#ZqR}(j?t)ka7VcW1C>hO50 z!6Qg3m;f+6cN;=#GHYKoA?O+i&S|^b=9uDTaA3%_Iqrp>( z=t+H?+$7$)n~|asn2W37+x-PgFK!My)hysk>qkt)Z3md^Mw{TBfI(=?easuP-W zT~w^w5)}NYT5`TFRV4(KW9+-^dATr>{hXR1R%=fpG~yRoLS`Fxj3vcfV!tI3%}--{>gHiW4C@D;?0b$e#{ znz5P3GP#LM-XYxi3ByE%O&(s(@r2y8Bk==xy}P(}?;{rVVvOJ~|AjQ2ECNavpei%e zN4)xkCU~E9{RW{mHUk_mAy&F+Y73E;h|7z4%O*eSQ_o=O7y^GI1rZg8k z&PSerc_1YSO>{krs-k)!&e1kU&~?Tw*8Ce7Cb6kA^7`dtY;vOpIK)?b-g*D&g^kz* zGlLkdY}1Rf7g&f|T8D4Ks;2nv{Q7}iT^ZPM(xeK=0g5_ziVo`zDd*8h|I1!?QU?md zDsFk$#Iec$N9Ub&A%b{El;X9a@V*}G*dN+60TrLT%Ut$MG;TTy3f->b)bm-!Bh}cB zvQwc;m+EG){ZsiKA)7qKq=uD{f};IA8w!>W@FXXQ2h7 zuI9)=#N@$yPJkNUJ;vIhO*8RBmi!B53HR^%7zQSQ`Pz~rHR4Z)RlOS_sX0Q7>U2&^ zxbw)nLfQ6J1?%S)sR;!;{No{`;4%|h)2Yx!;rK9ngDYx`mKe9^{tWA7MrM|1m^iQ{ zT5eIy;{=Erh)a&NV6107mQDl}!i;~CW8k5^72U83;^=XCik^{!B!1epW2G3z+heTw z(013nq=7B@a`Gi=XXzhv!M}-Fx&&_MNOi*|kjRepPYVejL!DX%jkjG>B2c=9{)z-b z1uT%JA%fOa>*RX&oFss=F5zF$nqG!ERVC_BHe9Lv`g%8+&p%z)jU^wg6t!+?6^AQ zmqJJUNiiqBb+P%=#qHj^jpF%8A1xdRoDP&$I8}K$;i4@smC4FdH@_$}w#L4a=m^9* z^5Hw4CQ+x_>2O?mVbnA)=hK+ORhNd;S@BarR!8pUTtpVo!VC8Sk^oE4t$QkSX?>t- zDAbiXXlx+V0`thTTehn9KUL=^baWjwlI2AtQ-LLHPd(bdcA29Y^yVEE+^nv2x1Oyf zIY~Qu8_9pFI4;BLfGQDi@ZLt{2aho|&iau+|N8g~VGcF=?Q4YZI(tpH<)f`lI&sf~ zH~@X!b$iy&0$Q$q z-+#YH$$35iIYwd^WZai2ebjpioYDu;bnLT{)dqUk3&vS8WOFih?4_e-RMNCL1}Q); z<6Xb0h=j!zrk>$P4WriA2pvQFh!v(OPG5ZBhFBt>=efCK<>BG0*ax`G!&T5Z}K#?rFi6&d2-!kU9o9lQ%+hY{K* z@{Uv=YTAxLeTEnAJMb_Y$A_p?=BkKD>K>0YR z%c;5x<~9WvD=h2f!wLg??fx{v)|+09UxKdo5|y8GS{YN8E?7$<vyJ;zV?3TTPWy{>ToStMZr*N1d)Yj7Vi?A^O4^K*FsVN)? z9<2TCnV%_nX|S}ewr-Aueq_saHt;G@vN04N_x?U)#zqgl=cu?OXHGuiI5(Z(!c+Ccx_CxyGBHHzKGmll%5FVX!Nz5bwh2rDPcG zdsceu|9f4yt_5s5w)@9CN*LjE3#o&@9BQ2HVO#htobbXb#S^;9P!w2rnY?lzLbuxf z**R(Ma|JfcVjVd(a0}t&h?2t7F<#}5_K<(WQZe!VisFu^;0;kR@mL*1?UJjO11oVc`>d#2x_vrgfpz)by}w1GAY+74#V| z3-p}nU+?jKUyBQE9z5iBLrM^78W19W(M*I~GjpE7iQ#&avZd_H217LqDu`0u7p~^o z+ad)3%!a>YggirMc#n}??2H#u?b(Bxq}>c6#{R7UJU9+;31FaV`-hG7Cgu#T)>LjPsu_q8stQBQHuL(x z|84)pT1fcYE=)@xcB&&9h1`>i@#B1s`&}aUN~%Fe+eGS@W?Ve~Cf4(A89{25_rR1z zpEF@DOpVPJ2w!@j-*xaEOa1a2s?#+tPB^A45Dc?KGwmlYB3u~YG# zZ=JuKkV3{Nnp zzVztzfL9diUk zg<1&|@p?o@`#yQ`LSG}%#@<|4p)Twj8=Jxp`#HVCCHwC}NF|YJW%0UK_q2}w6K8G~ zABQYp*)pnn$tUN41)oo9&Yo4q!>*EyXu<_i{9BbG>&K4~T~KC(Ovn39@5xB)l(I*V;npFNE2v(BTXuK8VnxS;IvLT%!ek3YaSdp^n=wi-ZzUeWx}zq zrE>do&Nh_^D<<6r15mnO2>j+Yl&gyz!NV;$TLPPXHNoMWi%APkT`Cy%&Ezu~NxWMn z!|%7JwTy!VzinW%>B64OrAkt0GHGfVj5M_)!Yc6|M`P7-`^|0&)!a;f;|#a*3Dd&v z9o+{4);KBL)7>wM@=OY;muPdMrTNDa6Qf47KCTk>%sCe=PZ>DcU2jWRmJ%kb+QO&q zDDQ~n{~KrJBI3YL`V~1vA9al10ot7Cqf-3Dw8&uWabzZHGxbpzp90oSk#0Z{JD=`2 z2yg96Vq+^NALCCaeyj}K)7h*ER)0;vI(HjlG&I}vtzlw*8{H_J<-NgDam96n(i2t{M1_aiWav|j5BUblgilj23#1|v{QLg8qOqspsz1~L zfaZc)jkt!nPjTtkx0;%K|F|AnUCEipSY~ejvc2*_VG3klaGd0d_7(B^1L;@o=IqB2 z9&P?NDvU`kU-#&^Mginj(Hkn;t2dNjtD$bu$E)L)OES|j<96G}-|XjAvh8IDjwAgs^!-SX0X zk=yBikjYlMo?7&1F}S-@nH#5^<7^F`hK`r2GBih+4>U;??ULvfW64;C(>9tjxzD-e z8{h?NP$dEmI+g6lskU>~ZgGh<$jtrG`(M$>w+;b?ikp5^Sh*f=V1UTr<@=-WH1Zh@P!Hi65W)~!e<4K1NUnW zKV8@wlyJ+m*HmFzaHV6zJIsY4O?PT7QGD8+JH~JPl{c{y+r2Cwi|xJXjE?9%pCSBy zVAJi_v((`5fnTHMb4u06q+c1I)H}}s`z8GSuvSonmTh!BfPp@cyJg03!IWId@wHFL z$b`^69QTk}*y=M^z9V4lS7p@@UQ4Pr3<*o=@t2nT(^(f-jS_})R6n2}N?l2fYzmd# zJ(Koc@)4gDooUna1ZTNtr%?X4<~4dh)zY#)QL3Qyau6ycgJKG7LI;4BS-^@n82+>! zKOf}YRYprfI18v(-h1q8MtRt?El7k4C! zYft{3srD~aHlYnuuTPw?iHBSZ-1s!Ml2XJog;5imj|=7XCKed{F%AVxr;s`oq24g^ zsgdV}(r1xI~YIQQ=*HuAkFdy_4e4#5%HE<5l8l*Frtb1JL=)uJPLIC~%kB290=6+C#Z zrgp#SuM~}HC*&2=rJbCoLI#J}dT&gdI$*Ac$dUH<;)!%u-3yHBEnw7UBnGw^sq_#- zwpjo|viDrzOJ*_$4r|j}4ZLP2zz4m5*2O|Z72|aQu@;dt60uZvz5kS~^#`RzHMUqx z$euZwd;1iQM=#wyS0E9rKb9^=mT4jqgX54!wQS@Whi7Uc8ql)<#+*WT9f!@HartQGE^+~&|WmV=hhm)29(-W-m4 zabbQI03U1iob=RL-VLNqkKPYN_ha?!*${|O2-#*gHnBtO@LNjcjgsu);*UEdW`gNX zzuU`-3JbF0rKR64(>zBX=caUqnesJqddPNDp&1M5nxMq{s|AyfkziMgU>}&RT*Y}; zRgVArzl^QJ?@jadELU}W9jcb2CwN9#O-xzpzaZVEtY5=!yg~~;`IbwVK4<8*#WCL~ zx1EQ$tYrLp;y87(o?Z;xO%XJvn=@XaGaGqN@fc&f>eiC<7)r~)C6Y^|*!@~y8>)=8 z`|eDSUl0*}3sKf)rh<=>u~0I4BkjA4gZlXIi$C{5{GzV|4R6tQR3|$(anDz=?z);* zPq_vq=o!q@F+*0Yw5M`2{Kengtqr6k^eEJY(7!hp&s1>8^2~~IR0&?L!zovl+|W3r z76yLdhk8w7A^nfMxknvq**e0L7L{!P^SM)Iqf8Qs-f=a@(>%(4*z9I@jwkgl|Ac({ z3i;~z%TMASn}>Fd&qXhlb=SJew~)NI9*UFpRcqrz->)|#%_sdy#O2n~*l&#R?g=&Iiczsjn1LSeI%Sg4zVGTHR0JtIu7Q(2WBXzC&j!Z@H1>d<_DmJhq6*p9;@XeAxlW*-!0!K+F{*8nS? zhp}EvCIfGtI0L=FsM?qdL)X&b3*Y0P3_tDu;xoZ>x}~Iek^b8KoTkCgf5`t)1OLH@ z#lY6Tr@LhIg4#xq=5)S0j}wa6k$?imp3ra=Jx@zB+vW78%X`vw0N2v_F0Q#?CX)0!jjk_%q>8M{Wq60)bK(cSei>q?ASI@mc60{ly@#X$HbnEV&+Fxx=W)IlMD znORPHdT$Erc}MmxJS*hvJ%jv8i;yAQ;7=j@OM-q*NM^T+j~-P|I(MHXSyPrmlxWU9 z*K}(F9_Ifb@lOKYj~gQlf`1wkvJP7*MLFUH^UMSjuO@|;0Kg3zM~;irKeqgTCHT(6 z0o#>Soa80WkO@7e%~zE*{{JEOL}3PH+7@5pE&)h3sJ61$v7lxy-7@(}7sxss8O(@x z4w@f?;A8oP+rBO9^K9ByrWLdy&3HFNC&ZDFY^KGD3Na9@Sxq))ZOq-j97Qw#psoPo z7Kk;HTZ%z`>mNGD?WNfgZGu+3Ch+^(OKm2b54)0ei z-col?^#NZL8vSyh3EnC}fIU@wxM~@p`p zSFAXBtOtpr3+P-f{|OU?krp`$3oAW+<%wg?_yHPU3>M^kmd-mfX@Pz|(_!Bjc9!(K zh`Zl{=oPij_~DWo0ea6v4ni>*shL_beJOvz%|LK3@ei}T<%8rLp)#kHsn12qzq^ME z7;PllrEtGgz*TeZ$&58u<`=OPtnb1Yd`0UU$w(ElA<+Z=4sflsAprrKLJY`2kh3~| zNd-=X+pWQagM~-Ve<}*Cn+I*XXAkj5i0Gd7K?W!pd&Hs+DPT=$p-}w}Qed85ZtMzdN=xZaUVeKFJpOWQfD0VRqNiw9}`iUWnpw2uB zDph_ce zQ?3`%+L_W@+%9Arnk=E~$Y(WXab`a~<_1->qtIbHtl1MRrt9*l;`uAmUW)jAyvVDM zGW5ofJdGGm&JUioko3ykWfY|;311&PxW_-*+A|%JUUJ#z(29MxvMo4>u9@_hnivwW zlT^gt@2?E&k&3;2(!V>%qw>?DzdO$?#EH@$p!dl!?$U6C#aVqE?G?jazARY7G($wyUd3J?PqG}LN zZFQMXSN{Nfy&USyCQ4hQI3Kzcy9WKG*W(uoXbu;A1OJUi1by|RI$MG zDM%C<6nA|_9BH7K^_vGJEA|Oc;lMoymz;zinBxiwNq1+R`H|lDTk9Zgmyjt(!_)HZXxui!~Tvd3JU+Tt~mK-A>vWc7YBr^E8*_lJy$Uhjn5A z)$X}d+_OaaXr!KxcUAj{Qj7jI;lQF)NrHRvFkPyPYX#b1Oj=R2?EXXlR)m|Y2Q5yApUZQ5)1HBWwgJK{8) zU$a~dtOhgCNOUrUL!!9U%!Nw4Z+ryG5?6%0C> z64Q$1B)_ZF6)xrO0+9Gete?b>t4UHdUt-(POywOJ%!4{ZupDNPj412_0XxypDTSgW`SJDJ*_*ZPd4eB zM+Cis9bXz5g=%kR!QS6;e=xx$BnulJF@4K9Dfv{(YGnv6!kQN~ot~=2M@hn*c0$GD zkC_6*jKG*`*r{Scrpyxj?yVd`a%=l0sr7Ya0V*3`iLeQR+OUsrDhW7yf` zi6d^EJSfLULr=fpfMhbcGsxQ=?CODWy4rcf>bl=>uPiZE*X>$YxqUf@h1x2)J!c4R!7)NYSy(+Q9Il@TCJheTkaS--GYO9#`-eSMSqIwZTyVmDKQqpzw9O_ayo@VuB;V7fpb>z_2C*%Q z_?7ebr#K18WJcO|_)WJtz(0y_5%Zwt4Ikp+A~|P7*_0RXL}NqCmQsAsDB8P8DyYd% zxxfZAolMLxPrt+x7TY9DVfi?oYmM2uF*(^5#ayny!bpiyb=^!Z^%`>z5p&nE4{vrX z!ik7$3roR9lOtbb(iWc&+FAB^-mg)+g>-r<(m6vaKmA}uYm`Rm>xEO8tA0Rq`Q(1C z&Xki?q23O>9QvT?Um5U{N#_OUccS1Jf@#kzRv(k+@cfD9YFdZ;=be$Z!!ysNe~7ws zU}4GQBBG*x1#t9eD&7+fWT#P{GN>4~MEm?qOQH4y;dd2-2OONVHgD}7E%mpYgpj#H zJdD-p1eY06Whv@KFKbe0Y_n--5*ndll9LWj%*bvPnR-vd|UAvtd-UX82Vh4w_K+Z`+;M#C=|f#a}bd>_G< zzyl}YX|^;c81%4KW8~cQW?5lNRr>>czjL6Z0uDprPQc~kDn0sPz?& zg;C1z!uh3KZ$4U8n%y(Olhg20)93uUg5?muLhYN?Krkkr)5IpqEgL$2kewHgxGakq|TZhOv~L09PyE zF%>3XW@@_n3#;(H@}a^i7MYgBTiOH@1QQ(S#Sm7m<&vc3SMyZ`UDkd~q1QNC!HS1p zxG!ewciSx@(pO>ey6_yX(N;8)9!(aW{&_j0kf`z|%oc%+Utg~2>S6S2>jTV!`lAw- zH=#y8;<(fp;0b=UY}u(Fm+zL<_+db)eu0994k)ZdDU)isX!qf(Acc?g@(36LdT=D^ zqfz7d#^n{1PUcR%Ngw8r5^7P^5YCgO;hccVsv=v$Nq&oCep`hXo=&`GSY+DTWMQJg z1HNC{MuF$K(-p9uBHWSLbA`7bZSa=!uG%QaC_ldzmQ$V4YtVytNDouF_R1IMcE(l= z*m`eJ$+)t0CA-C!%>y-5Ofr9&X}a&MZC6XbsjqoMA5w0;->E;Pv?6)3C6s* z7JiCPC$adT#T#)b#Wp?Dx~`M|_cPl0Vh5lMW%Nc^-OW?7PWO{aF;=SVEgeFhBoS*ls5jhPyaUN{dh59}5M^3+4IYi)b^9p&xwZ+%Oy6 zBc{I|w%vs7&TxcBlUIc$215$=tJ7@!svS$8sV7jpWzco{ewHb$o`W z0v&J1>jMi|56)IJI_oZ?@iZ@uh5UpLKz-L@w8`DuTgT;nd#ep!aL-h&}Z^$=HQoFc4kW^ZBPn7y^u7olIeR z7&tH^eDGwBEyxypaC9}k-ZfYYVkw~jqFcZhSO_ApPvL=K$sWm~s0zIESvPw6uZu~u z@V#1&Xy`2=#Bb%36QYUTo2ItrzgGmNWvZuM z8a^#c#@Jk#9P}KMnsN%x)Q2$?{6c^he@}SShPA#LA;qt<`gT#|acw7Ha*Jpz^FjCjHO)~2Q z5m0ojJp|)0yRvRm<$9vgn?shOQ{}N7oJyrV<8ENze~`zhI9So(f_>p7{4qgsS>~x^ z7wxOA919K*1#5>~`q`F-PBe{Bf>v^vhjw@MEl8r^-mKh5<%SN0ipz#R@~8)#LaHu& zHVgd=stSybg@7^l6(lck~~_ex&j+h`I8snRJ`(;Di#nL@6(Q}{qTDG>RdS=&VeL7Rukqq{i7um0(hX@ zPdBe#+#26R4o=7>+IIr>uM`Av&X^O4mCU+NZCyPe``22cDP>(9@t)am@OWc)1D*5| z^Td$u_WtC$ZyRhgA>%p7bM#R@4~XT`WpusXlQigjV=1#W0~8D0B#6fBd5O*udDLhb zFbKuFpV3#k3zj1K4LX~tl!k&qH0F5&gRO{+twV;CMJIW6Zb7UX#wAPOPaKJ^m~GO> zNixkCcr;tiVGBPa8DdoLObyItHZkf!y&!wr=khrnxuRHVEj5j^J+i`?^PVoWqpCO* z*b`#MEy?JBR&D>D=#%lRL60lTe%+l;*UhMCjqs_ZVm*D5J^j|!w=2|X?*i-y57^rB zJ7N_?z|=vO~1DITM|w>PI2)ueEWe?s-XZQOeh zb?4ouRDX3|-XY^?Lz^+4;L|b z^MQ}bh{@9a9<(XI2kuv!CU%^4gMfktLZg%BMaI6;qZ1OrAwk1ExneK8_%5Lt9!WZG}14%v~=y z{|%IRViE@hC;7Pd)K||joZA&NuVi!ui)Zy5jmUG6s#q8vf`Y5%@*0J7Of1~lY9N!= zxRRGEAFh_q!x;8Kfo#@y316E71I$62^>pKDFi#h8V04`_My(VqIPP8O;7u~4(fc~< z0;mp9o}#^y*0nmU{D^|mJM%n0>AM-LvqGhBcsi)P%ilM#4Bq=)=zn|c!8X;9HgE}27UVt&f zf!_C`%pv7XX(zFmWm^KF60;M130Ic4#&o@Iwk|&#qrQ)@0!Cg3PoIf}k`385s={~W z0psut;YCr+S;c&7Eu48s0p1^4n^iZL@N<9cf(-&`b(V%Pq!f=+ia|AsYN>M6AVg1= z`m)54(tUkBq~+fP%g4WEtzG>d5{0SUA4L^*tlV6+@gI$tB11XW5!Fk(S_AF`4Nb|t zhwe{pY=;HI#TN?XRfz+DI|=R*<9iZ*&qU^AWz21_Hx^%S;q}h;K+-c(KR{n&8!|}W zP5-hFc>d|a`|ubobZJt^$Np}NK=K7 z`{%`Ni#|&64r=Qq;>JO$jD&^YoL@-ZQmCb^zsGO!0&;V5r9bs^DTIh+SdUT&yJ!Nf zxBO03mBXo}o+Gpl*cK4a8dVMu6A3QmXK_}Xjr@y|kJQ|S^zMF-`GVK^*jxG83-J2v z21yLf9!~kALyB9r0EhxngR(*a?8cH8fy<(NAy^_5P{QSPh#+A&xJgtZG|@kXn+N=g zukaNuaR1V{G)DPo;Dh+7OIePz(X~B+h|;NRI#~Q} zO#MKOQ|$QIILq`v;8SrJsCuZV=bA6(OGvU%Z?*VBIbEa%3fEuPewD91{}%W0ZNvLq ztMdblGy2P5ngaF~I+MABo;<;)2asuFz)`a}Qvu^Rmx#Lx!YUkTEjTu<0vJ%Ewtm&U zzDs^ixb8Qckz+UW&Cqv{AC;TjT@|@)gbh8eu`MrXB-)vd!iBdzv8d~3FiqQKAlML9 zPWo)70h2S?1nzPZGP1G)tMuXi-tmoG(+so?K+xq=n9>}&Q$nhDY8QVZG)g~v(p5|m z8HlYAXL}A)e4Y)ykji`99kL09yvf{h-RZY$ELl4T6T0W6XLX3Z9;`Nb`KxoJ zcWcfag)}+=9u5;ACj>qDJ%wXVt$V}YaH>A^9c2l%K=2=yksZhAM{eTiO{q}&d4@xb zZY^Vvu;heLTD?8@KNt`P|KhEnR1zH8zk^EG~5-+DpQ0 zylnuU@SH<&g%0Ju9u@~n{kkCW`MWu-erhD?q^H5AuyEptdzq^hqs?}P=4Z>F+b|E- zm^LTBN3N*#Sn8|8;AY7)Mswzv#-Po(Q_fLB>0AY^h{u4oI@B#HJt5D8U>KXgr9q$fi zO$Ua=u|rzch8r$;>O@w!guDS}tPKkVbt#%h{i@dtrX`U0X=WDNbh+>Q@usXpF#}Uv z1QYD=L)* zVz%58k-uPWB^RPMn5yv%Gf%|JOKGA+x**H+DSqnm-JDV zGr&|u#!ZkI2l@G%$@p&~Rb!PIq{M$qo-m(9{!#M${LdxNpIfDlN$~vPt_EF{OoBD-aWX#^#PmBv&|C1)q z`=#a|aQAb6tMLT>o#9EtZ2i}UXS3D+zQq#;Z3AxrZ}A3)=ugJLU#>r8=2_#nd)N5X z{zY6v6+gWEcqPUUFpkXY8|;(q1V~4iZ{{~R@rt1xZ1V}1QG+b2C-wTm61L#PlrrUKsi>6!4WX<$10)$@L zV>!vvJvZ`zfmbf4Tl4thDNi&Y<`Z6~G`V|f08_vO}F2 z2%&_nKA(cjB*he{@YpDcBG0J-!;+8^QPUz!`BEr zh?a-Cp@b?C@&2M7TP6jP|094Fn-}2jXa5FJ=zjqObWr%e, + shallContinueToSearch: (build.linea.domain.EthLog) -> SearchDirection? // null means stop searching + ): SafeFuture + + fun getLogs( + fromBlock: BlockParameter, + toBlock: BlockParameter, + address: String, + topics: List + ): SafeFuture> +} diff --git a/jvm-libs/linea/core/domain-models/src/main/kotlin/linea/domain/RetryConfig.kt b/jvm-libs/linea/core/domain-models/src/main/kotlin/linea/domain/RetryConfig.kt new file mode 100644 index 000000000..7b9dd7fa2 --- /dev/null +++ b/jvm-libs/linea/core/domain-models/src/main/kotlin/linea/domain/RetryConfig.kt @@ -0,0 +1,32 @@ +package linea.domain + +import kotlin.time.Duration +import kotlin.time.Duration.Companion.milliseconds + +data class RetryConfig( + val maxRetries: UInt? = null, + val timeout: Duration? = null, + val backoffDelay: Duration = 100.milliseconds, + val failuresWarningThreshold: UInt = 0u +) { + val isRetryDisabled = maxRetries == 0u || timeout == 0.milliseconds + val isRetryEnabled: Boolean = !isRetryDisabled + + init { + maxRetries?.also { + require(maxRetries >= failuresWarningThreshold) { + "maxRetries must be greater or equal than failuresWarningThreshold." + + " maxRetries=$maxRetries, failuresWarningThreshold=$failuresWarningThreshold" + } + } + timeout?.also { + require(timeout > 0.milliseconds) { "timeout must be >= 1ms. value=$timeout" } + } + + require(backoffDelay > 0.milliseconds) { "backoffDelay must be >= 1ms. value=$timeout" } + } + + companion object { + val noRetries = RetryConfig(maxRetries = 0u) + } +} diff --git a/jvm-libs/linea/core/domain-models/src/test/kotlin/linea/domain/RetryConfigTest.kt b/jvm-libs/linea/core/domain-models/src/test/kotlin/linea/domain/RetryConfigTest.kt new file mode 100644 index 000000000..16a8afeae --- /dev/null +++ b/jvm-libs/linea/core/domain-models/src/test/kotlin/linea/domain/RetryConfigTest.kt @@ -0,0 +1,58 @@ +package linea.domain + +import org.assertj.core.api.Assertions.assertThat +import org.assertj.core.api.Assertions.assertThatThrownBy +import org.junit.jupiter.api.Test +import kotlin.time.Duration.Companion.milliseconds +import kotlin.time.Duration.Companion.seconds + +class RetryConfigTest { + @Test + fun `should support no retries`() { + val notRetryConfig = RetryConfig(maxRetries = 0u) + assertThat(notRetryConfig.isRetryDisabled).isTrue() + assertThat(notRetryConfig.isRetryEnabled).isFalse() + assertThat(notRetryConfig.timeout).isNull() + assertThat(notRetryConfig.maxRetries).isEqualTo(0u) + assertThat(notRetryConfig.failuresWarningThreshold).isEqualTo(0u) + assertThat(RetryConfig.noRetries).isEqualTo(notRetryConfig) + } + + @Test + fun `should support retries with timeout only`() { + val notRetryConfig = RetryConfig(timeout = 2.seconds) + assertThat(notRetryConfig.isRetryDisabled).isFalse() + assertThat(notRetryConfig.isRetryEnabled).isTrue() + assertThat(notRetryConfig.timeout).isEqualTo(2.seconds) + assertThat(notRetryConfig.maxRetries).isNull() + assertThat(notRetryConfig.failuresWarningThreshold).isEqualTo(0u) + } + + @Test + fun `should support retries with maxRetries only`() { + val notRetryConfig = RetryConfig(maxRetries = 10u) + assertThat(notRetryConfig.isRetryDisabled).isFalse() + assertThat(notRetryConfig.isRetryEnabled).isTrue() + assertThat(notRetryConfig.timeout).isNull() + assertThat(notRetryConfig.maxRetries).isEqualTo(10u) + assertThat(notRetryConfig.failuresWarningThreshold).isEqualTo(0u) + } + + @Test + fun `should support retries with timeout and maxRetries`() { + val notRetryConfig = RetryConfig(maxRetries = 10u, timeout = 20.seconds, backoffDelay = 1500.milliseconds) + assertThat(notRetryConfig.isRetryDisabled).isFalse() + assertThat(notRetryConfig.isRetryEnabled).isTrue() + assertThat(notRetryConfig.timeout).isEqualTo(20.seconds) + assertThat(notRetryConfig.maxRetries).isEqualTo(10u) + assertThat(notRetryConfig.backoffDelay).isEqualTo(1500.milliseconds) + assertThat(notRetryConfig.failuresWarningThreshold).isEqualTo(0u) + } + + @Test + fun `should throw exception when timeout is less than 1ms`() { + assertThatThrownBy { + RetryConfig(timeout = 0.milliseconds) + }.isInstanceOf(IllegalArgumentException::class.java) + } +} diff --git a/jvm-libs/linea/testing/file-system/src/main/kotlin/net/consensys/linea/testing/filesystem/Files.kt b/jvm-libs/linea/testing/file-system/src/main/kotlin/net/consensys/linea/testing/filesystem/Files.kt index 7d0d56a16..a05d35969 100644 --- a/jvm-libs/linea/testing/file-system/src/main/kotlin/net/consensys/linea/testing/filesystem/Files.kt +++ b/jvm-libs/linea/testing/file-system/src/main/kotlin/net/consensys/linea/testing/filesystem/Files.kt @@ -39,5 +39,5 @@ fun getPathTo( lookupParentDir: Boolean = true ): Path { return findPathTo(targetFileOrDir, lookupDir, lookupParentDir) - ?: throw IllegalArgumentException("Could not find file or directory in path: $lookupDir or its parent directories") + ?: throw IllegalArgumentException("Could not find $targetFileOrDir in path: $lookupDir or its parent directories") } diff --git a/jvm-libs/linea/web3j-extensions/build.gradle b/jvm-libs/linea/web3j-extensions/build.gradle index 16d1caf69..081aac2c4 100644 --- a/jvm-libs/linea/web3j-extensions/build.gradle +++ b/jvm-libs/linea/web3j-extensions/build.gradle @@ -1,7 +1,6 @@ plugins { id 'net.consensys.zkevm.kotlin-common-conventions' id 'java-library' - id 'java-test-fixtures' } description="Web3j extensions for Linea" @@ -9,17 +8,20 @@ description="Web3j extensions for Linea" dependencies { api "org.web3j:core:${libs.versions.web3j.get()}" api project(':jvm-libs:linea:core:domain-models') + api project(':jvm-libs:linea:clients:interfaces') api project(':jvm-libs:generic:logging') + api project(":jvm-libs:generic:extensions:kotlin") + api project(':jvm-libs:generic:extensions:futures') api project(':jvm-libs:linea:besu-libs') - implementation project(":jvm-libs:generic:extensions:kotlin") - implementation project(":jvm-libs:generic:extensions:futures") implementation "tech.pegasys.teku.internal:bytes:${libs.versions.teku.get()}" implementation "tech.pegasys.teku.internal:jackson:${libs.versions.teku.get()}" implementation "tech.pegasys.teku.internal:unsigned:${libs.versions.teku.get()}" + testImplementation(testFixtures(project(":jvm-libs:generic:json-rpc"))) testImplementation "org.apache.logging.log4j:log4j-slf4j2-impl:${libs.versions.log4j.get()}" testImplementation "com.fasterxml.jackson.core:jackson-annotations:${libs.versions.jackson.get()}" testImplementation "com.fasterxml.jackson.core:jackson-databind:${libs.versions.jackson.get()}" + testImplementation "com.github.tomakehurst:wiremock-jre8:${libs.versions.wiremock.get()}" testImplementation project(":jvm-libs:linea:besu-rlp-and-mappers") } diff --git a/coordinator/clients/smart-contract-client/src/main/kotlin/net/consensys/linea/contract/Web3JLogsClient.kt b/jvm-libs/linea/web3j-extensions/src/main/kotlin/build/linea/web3j/Web3JLogsClient.kt similarity index 98% rename from coordinator/clients/smart-contract-client/src/main/kotlin/net/consensys/linea/contract/Web3JLogsClient.kt rename to jvm-libs/linea/web3j-extensions/src/main/kotlin/build/linea/web3j/Web3JLogsClient.kt index ed24214b7..a56b92e94 100644 --- a/coordinator/clients/smart-contract-client/src/main/kotlin/net/consensys/linea/contract/Web3JLogsClient.kt +++ b/jvm-libs/linea/web3j-extensions/src/main/kotlin/build/linea/web3j/Web3JLogsClient.kt @@ -1,4 +1,4 @@ -package net.consensys.linea.contract +package build.linea.web3j import io.vertx.core.Vertx import net.consensys.linea.async.AsyncRetryer diff --git a/jvm-libs/linea/web3j-extensions/src/main/kotlin/linea/web3j/SearchCursor.kt b/jvm-libs/linea/web3j-extensions/src/main/kotlin/linea/web3j/SearchCursor.kt new file mode 100644 index 000000000..0b4eddcfb --- /dev/null +++ b/jvm-libs/linea/web3j-extensions/src/main/kotlin/linea/web3j/SearchCursor.kt @@ -0,0 +1,87 @@ +package linea.web3j + +import linea.SearchDirection + +internal fun rangeChunks( + start: ULong, + end: ULong, + chunkSize: Int +): List { + return (start..end step chunkSize.toLong()) + .map { chunkStart -> + val chunkEnd = (chunkStart + chunkSize.toUInt() - 1u).coerceAtMost(end) + ULongRange(chunkStart, chunkEnd) + } +} + +/** + * SearchCursor is a helper class to iterate over a range of ULong values in a binary search manner. + * When search is not provided returns the next unsearched chunk without moving left or right cursors because + * no direction is provided, but flags the chunk as searched to not go over again. + * + * This caveat is because when searching for EthLogs on L1, a blockInterval (represend by chunk here) may not have logs + * so the search predicate cannot tell what direction to go next, so we need to flag the chunk as searched and try the + * next chunk. + */ +internal class SearchCursor( + val from: ULong, + val to: ULong, + val chunkSize: Int +) { + private data class Chunk(val interval: Pair, var searched: Boolean = false) + + private val searchChunks = rangeChunks(from, to, chunkSize) + .map { chunkInterval -> Chunk(chunkInterval.first to chunkInterval.endInclusive, searched = false) } + private var left = 0 + private var right = searchChunks.size - 1 + private var prevCursor: Int? = null + + @Synchronized + fun next(searchDirection: SearchDirection?): Pair? { + return if (left > right) { + null + } else { + if (prevCursor == null) { + // 1st call, lets start in the middle + val mid = left + (right - left) / 2 + searchChunks[mid] to mid + } else { + if (searchDirection == null) { + findLeftNextUnsearchedChunkAndUpdateLeftLimit() + } else { + if (searchDirection == SearchDirection.FORWARD) { + left = prevCursor!! + 1 + } else { + right = prevCursor!! - 1 + } + if (left > right) { + null + } else { + val mid = left + (right - left) / 2 + val chunk = searchChunks[mid] + if (chunk.searched) { + // we have already searched this chunk, lets find next unsearched + findLeftNextUnsearchedChunkAndUpdateLeftLimit() + } else { + chunk to mid + } + } + } + }?.let { (chunk, index) -> + prevCursor = index + chunk.searched = true + chunk.interval + } + } + } + + private fun findLeftNextUnsearchedChunkAndUpdateLeftLimit(): Pair? { + for (i in left..right) { + if (!searchChunks[i].searched) { + left = i + return searchChunks[i] to i + } + } + return null + } +} diff --git a/jvm-libs/linea/web3j-extensions/src/main/kotlin/linea/web3j/Web3JLogsSearcher.kt b/jvm-libs/linea/web3j-extensions/src/main/kotlin/linea/web3j/Web3JLogsSearcher.kt new file mode 100644 index 000000000..06bc54f58 --- /dev/null +++ b/jvm-libs/linea/web3j-extensions/src/main/kotlin/linea/web3j/Web3JLogsSearcher.kt @@ -0,0 +1,209 @@ +package linea.web3j + +import build.linea.web3j.domain.toDomain +import build.linea.web3j.domain.toWeb3j +import io.vertx.core.Vertx +import linea.EthLogsSearcher +import linea.SearchDirection +import linea.domain.RetryConfig +import net.consensys.linea.BlockParameter +import net.consensys.linea.BlockParameter.Companion.toBlockParameter +import net.consensys.linea.CommonDomainFunctions +import net.consensys.linea.async.AsyncRetryer +import net.consensys.linea.async.toSafeFuture +import net.consensys.toULong +import org.apache.logging.log4j.LogManager +import org.apache.logging.log4j.Logger +import org.web3j.protocol.Web3j +import org.web3j.protocol.core.methods.request.EthFilter +import org.web3j.protocol.core.methods.response.EthLog +import org.web3j.protocol.core.methods.response.Log +import tech.pegasys.teku.infrastructure.async.SafeFuture +import kotlin.time.Duration +import kotlin.time.Duration.Companion.milliseconds + +private sealed interface SearchResult { + data class ItemFound(val log: build.linea.domain.EthLog) : SearchResult + data class KeepSearching(val direction: SearchDirection) : SearchResult + data object NoResultsInInterval : SearchResult +} + +class Web3JLogsSearcher( + val vertx: Vertx, + val web3jClient: Web3j, + val config: Config = Config(), + val log: Logger = LogManager.getLogger(Web3JLogsSearcher::class.java) +) : EthLogsSearcher { + data class Config( + val backoffDelay: Duration = 100.milliseconds, + val requestRetryConfig: RetryConfig = RetryConfig() + ) + + override fun findLog( + fromBlock: BlockParameter, + toBlock: BlockParameter, + chunkSize: Int, + address: String, + topics: List, + shallContinueToSearch: (build.linea.domain.EthLog) -> SearchDirection? + ): SafeFuture { + require(chunkSize > 0) { "chunkSize=$chunkSize must be greater than 0" } + + return getAbsoluteBlockNumbers(fromBlock, toBlock) + .thenCompose { (start, end) -> + findLogLoop( + start, + end, + chunkSize, + address, + topics, + shallContinueToSearch + ) + } + } + + private fun findLogLoop( + fromBlock: ULong, + toBlock: ULong, + chunkSize: Int, + address: String, + topics: List, + shallContinueToSearchPredicate: (build.linea.domain.EthLog) -> SearchDirection? + ): SafeFuture { + val cursor = SearchCursor(fromBlock, toBlock, chunkSize) + log.trace("searching between blocks={}", CommonDomainFunctions.blockIntervalString(fromBlock, toBlock)) + + var nextChunkToSearch: Pair? = cursor.next(searchDirection = SearchDirection.FORWARD) + return AsyncRetryer.retry( + vertx, + backoffDelay = config.backoffDelay, + stopRetriesPredicate = { it is SearchResult.ItemFound || nextChunkToSearch == null } + ) { + val (chunkStart, chunkEnd) = nextChunkToSearch!! + log.trace("searching in chunk={}", CommonDomainFunctions.blockIntervalString(chunkStart, chunkEnd)) + findLogInInterval(chunkStart, chunkEnd, address, topics, shallContinueToSearchPredicate) + .thenPeek { result -> + if (result is SearchResult.NoResultsInInterval) { + nextChunkToSearch = cursor.next(searchDirection = null) + } else if (result is SearchResult.KeepSearching) { + // need to search in the same chunk + nextChunkToSearch = cursor.next(searchDirection = result.direction) + } + } + }.thenApply { either -> + when (either) { + is SearchResult.ItemFound -> either.log + else -> null + } + } + } + + private fun findLogInInterval( + fromBlock: ULong, + toBlock: ULong, + address: String, + topics: List, + shallContinueToSearchPredicate: (build.linea.domain.EthLog) -> SearchDirection? + ): SafeFuture { + return getLogs( + fromBlock = fromBlock.toBlockParameter(), + toBlock = toBlock.toBlockParameter(), + address = address, + topics = topics + ) + .thenApply { logs -> + if (logs.isEmpty()) { + SearchResult.NoResultsInInterval + } else { + val item = logs.find { shallContinueToSearchPredicate(it) == null } + if (item != null) { + SearchResult.ItemFound(item) + } else { + val nextSearchDirection = shallContinueToSearchPredicate(logs.first())!! + SearchResult.KeepSearching(nextSearchDirection) + } + } + } + } + + override fun getLogs( + fromBlock: BlockParameter, + toBlock: BlockParameter, + address: String, + topics: List + ): SafeFuture> { + return if (config.requestRetryConfig.isRetryEnabled) { + AsyncRetryer.retry( + vertx = vertx, + backoffDelay = config.requestRetryConfig.backoffDelay, + timeout = config.requestRetryConfig.timeout, + maxRetries = config.requestRetryConfig.maxRetries?.toInt() + ) { + getLogsInternal(fromBlock, toBlock, address, topics) + } + } else { + getLogsInternal(fromBlock, toBlock, address, topics) + } + } + + private fun getLogsInternal( + fromBlock: BlockParameter, + toBlock: BlockParameter, + address: String, + topics: List + ): SafeFuture> { + val ethFilter = EthFilter( + /*fromBlock*/ fromBlock.toWeb3j(), + /*toBlock*/ toBlock.toWeb3j(), + /*address*/ address + ).apply { + topics.forEach { addSingleTopic(it) } + } + + return web3jClient + .ethGetLogs(ethFilter) + .sendAsync() + .toSafeFuture() + .thenCompose { + if (it.hasError()) { + SafeFuture.failedFuture( + RuntimeException( + "json-rpc error: code=${it.error.code} message=${it.error.message} " + + "data=${it.error.data}" + ) + ) + } else { + val logs = if (it.logs != null) { + @Suppress("UNCHECKED_CAST") + (it.logs as List>) + .map { logResult -> + logResult.get().toDomain() + } + } else { + emptyList() + } + + SafeFuture.completedFuture(logs) + } + } + } + + private fun getAbsoluteBlockNumbers( + fromBlock: BlockParameter, + toBlock: BlockParameter + ): SafeFuture> { + return if (fromBlock is BlockParameter.BlockNumber && toBlock is BlockParameter.BlockNumber) { + return SafeFuture.completedFuture(Pair(fromBlock.getNumber(), toBlock.getNumber())) + } else { + SafeFuture.collectAll( + web3jClient.ethGetBlockByNumber(fromBlock.toWeb3j(), false).sendAsync().toSafeFuture(), + web3jClient.ethGetBlockByNumber(toBlock.toWeb3j(), false).sendAsync().toSafeFuture() + ).thenApply { (fromBlockResponse, toBlockResponse) -> + Pair( + fromBlockResponse.block.number.toULong(), + toBlockResponse.block.number.toULong() + ) + } + } + } +} diff --git a/coordinator/clients/smart-contract-client/src/test/kotlin/net/consensys/linea/contract/Web3JLogsClientIntTest.kt b/jvm-libs/linea/web3j-extensions/src/test/kotlin/build/linea/web3j/Web3JLogsClientIntTest.kt similarity index 99% rename from coordinator/clients/smart-contract-client/src/test/kotlin/net/consensys/linea/contract/Web3JLogsClientIntTest.kt rename to jvm-libs/linea/web3j-extensions/src/test/kotlin/build/linea/web3j/Web3JLogsClientIntTest.kt index 2b9c85598..578dc543d 100644 --- a/coordinator/clients/smart-contract-client/src/test/kotlin/net/consensys/linea/contract/Web3JLogsClientIntTest.kt +++ b/jvm-libs/linea/web3j-extensions/src/test/kotlin/build/linea/web3j/Web3JLogsClientIntTest.kt @@ -1,4 +1,4 @@ -package net.consensys.linea.contract +package build.linea.web3j import com.github.tomakehurst.wiremock.WireMockServer import com.github.tomakehurst.wiremock.client.WireMock.aResponse diff --git a/coordinator/clients/smart-contract-client/src/test/kotlin/net/consensys/linea/contract/Web3JLogsClientTest.kt b/jvm-libs/linea/web3j-extensions/src/test/kotlin/build/linea/web3j/Web3JLogsClientTest.kt similarity index 99% rename from coordinator/clients/smart-contract-client/src/test/kotlin/net/consensys/linea/contract/Web3JLogsClientTest.kt rename to jvm-libs/linea/web3j-extensions/src/test/kotlin/build/linea/web3j/Web3JLogsClientTest.kt index 06112face..4204c65c3 100644 --- a/coordinator/clients/smart-contract-client/src/test/kotlin/net/consensys/linea/contract/Web3JLogsClientTest.kt +++ b/jvm-libs/linea/web3j-extensions/src/test/kotlin/build/linea/web3j/Web3JLogsClientTest.kt @@ -1,4 +1,4 @@ -package net.consensys.linea.contract +package build.linea.web3j import io.vertx.core.Vertx import org.assertj.core.api.Assertions.assertThat diff --git a/jvm-libs/linea/web3j-extensions/src/test/kotlin/linea/web3j/SearchCursorTest.kt b/jvm-libs/linea/web3j-extensions/src/test/kotlin/linea/web3j/SearchCursorTest.kt new file mode 100644 index 000000000..4266e6db6 --- /dev/null +++ b/jvm-libs/linea/web3j-extensions/src/test/kotlin/linea/web3j/SearchCursorTest.kt @@ -0,0 +1,191 @@ +package linea.web3j + +import linea.SearchDirection +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +class SearchCursorTest { + + @Test + fun `should calculate range chunks correctly`() { + assertThat(rangeChunks(0uL, 50uL, 10)).containsExactly( + 0UL..9UL, + 10UL..19UL, + 20UL..29UL, + 30UL..39UL, + 40UL..49UL, + 50UL..50UL + ) + + assertThat(rangeChunks(0uL, 45uL, 10)).containsExactly( + 0UL..9UL, + 10UL..19UL, + 20UL..29UL, + 30UL..39UL, + 40UL..45UL + ) + } + + @Test + fun `next starts in the middle regardless of direction`() { + assertThat( + SearchCursor( + from = 1uL, + to = 100uL, + chunkSize = 10 + ).next(searchDirection = null) + ).isEqualTo(41UL to 50UL) + assertThat( + SearchCursor( + from = 1uL, + to = 100uL, + chunkSize = 10 + ).next(searchDirection = SearchDirection.FORWARD) + ).isEqualTo(41UL to 50UL) + assertThat( + SearchCursor( + from = 1uL, + to = 100uL, + chunkSize = 10 + ).next(searchDirection = SearchDirection.BACKWARD) + ).isEqualTo(41UL to 50UL) + } + + @Test + fun `next follows binary search when direction is FORWARD`() { + val searchCursor = SearchCursor(from = 1uL, to = 100uL, chunkSize = 10) + + assertThat(searchCursor.next(SearchDirection.FORWARD)).isEqualTo(41UL to 50UL) + assertThat(searchCursor.next(SearchDirection.FORWARD)).isEqualTo(71UL to 80UL) + assertThat(searchCursor.next(SearchDirection.FORWARD)).isEqualTo(81UL to 90UL) + assertThat(searchCursor.next(SearchDirection.FORWARD)).isEqualTo(91UL to 100UL) + } + + @Test + fun `next follows binary search when direction is BACKWARD`() { + val searchCursor = SearchCursor(from = 1uL, to = 100uL, chunkSize = 10) + + assertThat(searchCursor.next(SearchDirection.BACKWARD)).isEqualTo(41UL to 50UL) + assertThat(searchCursor.next(SearchDirection.BACKWARD)).isEqualTo(11UL to 20UL) + assertThat(searchCursor.next(SearchDirection.BACKWARD)).isEqualTo(1UL to 10UL) + } + + @Test + fun `next follows binary search when direction is null`() { + val searchCursor = SearchCursor(from = 1uL, to = 100uL, chunkSize = 10) + + assertThat(searchCursor.next(null)).isEqualTo(41UL to 50UL) + assertThat(searchCursor.next(null)).isEqualTo(1UL to 10UL) + assertThat(searchCursor.next(null)).isEqualTo(11UL to 20UL) + assertThat(searchCursor.next(null)).isEqualTo(21UL to 30UL) + assertThat(searchCursor.next(null)).isEqualTo(31UL to 40UL) + assertThat(searchCursor.next(null)).isEqualTo(51UL to 60UL) + assertThat(searchCursor.next(null)).isEqualTo(61UL to 70UL) + assertThat(searchCursor.next(null)).isEqualTo(71UL to 80UL) + assertThat(searchCursor.next(null)).isEqualTo(81UL to 90UL) + assertThat(searchCursor.next(null)).isEqualTo(91UL to 100UL) + } + + @Test + fun `next iterates over chunks when no direction is provided`() { + val searchCursor = SearchCursor(from = 1uL, to = 100uL, chunkSize = 10) + val chunks = mutableListOf>() + var next = searchCursor.next(searchDirection = null) + + while (next != null) { + chunks.add(next) + next = searchCursor.next(searchDirection = null) + } + + assertThat(chunks.sortedBy { it.first }).containsExactly( + 1UL to 10UL, + 11UL to 20UL, + 21UL to 30UL, + 31UL to 40UL, + 41UL to 50UL, + 51UL to 60UL, + 61UL to 70UL, + 71UL to 80UL, + 81UL to 90UL, + 91UL to 100UL + ) + } + + @Test + fun `next iterates over chunks when no direction is provided and follows direction when provided`() { + val searchCursor = SearchCursor(from = 1uL, to = 200uL, chunkSize = 10) + + assertThat(searchCursor.next(searchDirection = null)).isEqualTo(91UL to 100UL) + + assertThat(searchCursor.next(searchDirection = null)).isEqualTo(1UL to 10UL) + assertThat(searchCursor.next(searchDirection = SearchDirection.BACKWARD)).isNull() + } + + @Test + fun `next iterates follows direction without repeating`() { + val searchCursor = SearchCursor(from = 1uL, to = 200uL, chunkSize = 10) + + assertThat(searchCursor.next(searchDirection = null)).isEqualTo(91UL to 100UL) + + assertThat(searchCursor.next(searchDirection = null)).isEqualTo(1UL to 10UL) + assertThat(searchCursor.next(searchDirection = SearchDirection.FORWARD)).isEqualTo(101UL to 110UL) + assertThat(searchCursor.next(searchDirection = SearchDirection.BACKWARD)).isEqualTo(51UL to 60UL) + assertThat(searchCursor.next(searchDirection = null)).isEqualTo(11UL to 20UL) + // This backward is not technically valid in a typical binary search, + // but it is a valid use case for this cursor because when searching for logs + // the predicate can try to go back but search chunks are exhausted + assertThat(searchCursor.next(searchDirection = SearchDirection.BACKWARD)).isNull() + } + + @Test + fun `next iterates follows direction without repeating - forward`() { + val searchCursor = SearchCursor(from = 1uL, to = 200uL, chunkSize = 10) + + assertThat(searchCursor.next(searchDirection = null)).isEqualTo(91UL to 100UL) + + assertThat(searchCursor.next(searchDirection = SearchDirection.FORWARD)).isEqualTo(141UL to 150UL) + assertThat(searchCursor.next(searchDirection = SearchDirection.FORWARD)).isEqualTo(171UL to 180UL) + assertThat(searchCursor.next(searchDirection = null)).isEqualTo(151UL to 160UL) + // This backward is not technically valid in a typical binary search, + // but it is a valid use case for this cursor because when searching for logs + // the predicate can try to go back but search chunks are exhausted + assertThat(searchCursor.next(searchDirection = SearchDirection.BACKWARD)).isNull() + } + + @Test + fun `next iterates follows direction without repeating - forward 2`() { + val searchCursor = SearchCursor(from = 1uL, to = 200uL, chunkSize = 10) + + assertThat(searchCursor.next(searchDirection = null)).isEqualTo(91UL to 100UL) + + assertThat(searchCursor.next(searchDirection = SearchDirection.BACKWARD)).isEqualTo(41UL to 50UL) + assertThat(searchCursor.next(searchDirection = SearchDirection.FORWARD)).isEqualTo(61UL to 70UL) + assertThat(searchCursor.next(searchDirection = SearchDirection.FORWARD)).isEqualTo(71UL to 80UL) + assertThat(searchCursor.next(searchDirection = null)).isEqualTo(81UL to 90UL) + assertThat(searchCursor.next(searchDirection = null)).isNull() + // This backward is not technically valid in a typical binary search, + // but it is a valid use case for this cursor because when searching for logs + // the predicate can try to go back but search chunks are exauhsted + assertThat(searchCursor.next(searchDirection = SearchDirection.BACKWARD)).isNull() + } + + @Test + fun `next iterates follows direction without repeating - forward 3`() { + val searchCursor = SearchCursor(from = 0uL, to = 100uL, chunkSize = 5) + // chunks: + // 0..4, 5..9, 10..14, 15..19, 20..24, 25..29, 30..34, 35..39, 40..44, 45..49, + // 50..54, + // 55..59, 60..64, 65..69, 70..74, 75..79, 80..84, 85..89, 90..94, 95..99, 100..100 + assertThat(searchCursor.next(searchDirection = null)).isEqualTo(50UL to 54UL) + assertThat(searchCursor.next(searchDirection = SearchDirection.BACKWARD)).isEqualTo(20UL to 24UL) + assertThat(searchCursor.next(searchDirection = null)).isEqualTo(0UL to 4UL) + assertThat(searchCursor.next(searchDirection = null)).isEqualTo(5UL to 9UL) + assertThat(searchCursor.next(searchDirection = null)).isEqualTo(10UL to 14UL) + assertThat(searchCursor.next(searchDirection = SearchDirection.FORWARD)).isEqualTo(30UL to 34UL) + assertThat(searchCursor.next(searchDirection = null)).isEqualTo(15UL to 19UL) + assertThat(searchCursor.next(searchDirection = SearchDirection.FORWARD)).isEqualTo(25UL to 29UL) + assertThat(searchCursor.next(searchDirection = null)).isEqualTo(35UL to 39UL) + assertThat(searchCursor.next(searchDirection = null)).isEqualTo(40UL to 44UL) + assertThat(searchCursor.next(searchDirection = null)).isEqualTo(45UL to 49UL) + } +} diff --git a/jvm-libs/linea/web3j-extensions/src/test/kotlin/linea/web3j/ULongRangesHelperTest.kt b/jvm-libs/linea/web3j-extensions/src/test/kotlin/linea/web3j/ULongRangesHelperTest.kt new file mode 100644 index 000000000..82bd7b2b3 --- /dev/null +++ b/jvm-libs/linea/web3j-extensions/src/test/kotlin/linea/web3j/ULongRangesHelperTest.kt @@ -0,0 +1,117 @@ +package linea.web3j + +import net.consensys.intersection +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +internal fun generateEffectiveIntervals( + blocksWithLogs: List, + filterFromBlock: ULong, + filterToBlock: ULong +): List { + // if blocksWithLogs is [10..19, 25..29, 40..49] and filter.fromBlock=15 and filter.toBlock=45 + // then we will return logs for blocks [15..19, 25..29, 40..45] + val fromToRange = filterFromBlock..filterToBlock + + return blocksWithLogs + .map { it.intersection(fromToRange) } + .filter { !it.isEmpty() } + .map { range -> (range.first.coerceAtLeast(filterFromBlock))..(range.last.coerceAtMost(filterToBlock)) } +} + +class ULongRangesHelperTest { + + @Test + fun `generateEffectiveIntervals returns effective intervals for given blocks with logs and filter`() { + val blocksWithLogs = listOf(10UL..19UL, 40UL..49UL, 60UL..69UL) + + // before range + generateEffectiveIntervals( + blocksWithLogs = blocksWithLogs, + filterFromBlock = 0UL, + filterToBlock = 9UL + ) + .also { + assertThat(it).isEmpty() + } + + // intersect 1st half of range + generateEffectiveIntervals( + blocksWithLogs = blocksWithLogs, + filterFromBlock = 0UL, + filterToBlock = 15UL + ) + .also { + assertThat(it).containsExactly(10UL..15UL) + } + // intersect 2st half of range + generateEffectiveIntervals( + blocksWithLogs = blocksWithLogs, + filterFromBlock = 15UL, + filterToBlock = 25UL + ) + .also { + assertThat(it).containsExactly(15UL..19UL) + } + + // overlapping single range + generateEffectiveIntervals( + blocksWithLogs = blocksWithLogs, + filterFromBlock = 0UL, + filterToBlock = 25UL + ) + .also { + assertThat(it).containsExactly(10UL..19UL) + } + + // within single range + generateEffectiveIntervals( + blocksWithLogs = blocksWithLogs, + filterFromBlock = 42UL, + filterToBlock = 45UL + ) + .also { + assertThat(it).containsExactly(42UL..45UL) + } + + // after the range + generateEffectiveIntervals( + blocksWithLogs = blocksWithLogs, + filterFromBlock = 50UL, + filterToBlock = 55UL + ) + .also { + assertThat(it).isEmpty() + } + + // overlapping all ranges + generateEffectiveIntervals( + blocksWithLogs = blocksWithLogs, + filterFromBlock = 0UL, + filterToBlock = 100UL + ) + .also { + assertThat(it).containsExactly(10UL..19UL, 40UL..49UL, 60UL..69UL) + } + + // overlapping middle ranges and intersect 1st half and 2nd of edge ranges + generateEffectiveIntervals( + blocksWithLogs = blocksWithLogs, + filterFromBlock = 15UL, + filterToBlock = 65UL + ) + .also { + assertThat(it).containsExactly(15UL..19UL, 40UL..49UL, 60UL..65UL) + } + + // intersect 1st half and 2nd of ranges + generateEffectiveIntervals( + blocksWithLogs = blocksWithLogs, + filterFromBlock = 15UL, + filterToBlock = 45UL + ) + .also { + assertThat(it).containsExactly(15UL..19UL, 40UL..45UL) + } + } +} diff --git a/jvm-libs/linea/web3j-extensions/src/test/kotlin/linea/web3j/Web3JLogsSearcherIntTest.kt b/jvm-libs/linea/web3j-extensions/src/test/kotlin/linea/web3j/Web3JLogsSearcherIntTest.kt new file mode 100644 index 000000000..efc5f889e --- /dev/null +++ b/jvm-libs/linea/web3j-extensions/src/test/kotlin/linea/web3j/Web3JLogsSearcherIntTest.kt @@ -0,0 +1,472 @@ +package linea.web3j + +import build.linea.domain.EthLog +import com.github.tomakehurst.wiremock.WireMockServer +import com.github.tomakehurst.wiremock.client.WireMock.aResponse +import com.github.tomakehurst.wiremock.client.WireMock.containing +import com.github.tomakehurst.wiremock.client.WireMock.post +import com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo +import com.github.tomakehurst.wiremock.core.WireMockConfiguration +import io.vertx.core.Vertx +import linea.SearchDirection +import linea.domain.RetryConfig +import linea.jsonrpc.TestingJsonRpcServer +import net.consensys.encodeHex +import net.consensys.fromHexString +import net.consensys.linea.BlockParameter.Companion.toBlockParameter +import net.consensys.linea.jsonrpc.JsonRpcError +import net.consensys.linea.jsonrpc.JsonRpcRequest +import net.consensys.toHexString +import net.consensys.toHexStringUInt256 +import org.apache.logging.log4j.LogManager +import org.assertj.core.api.Assertions.assertThat +import org.assertj.core.api.Assertions.assertThatThrownBy +import org.junit.jupiter.api.AfterEach +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.web3j.protocol.Web3j +import org.web3j.protocol.http.HttpService +import java.net.URI +import kotlin.random.Random +import kotlin.time.Duration.Companion.milliseconds + +internal data class EthGetLogsRequest( + val fromBlock: ULong, + val toBlock: ULong, + val topics: List, + val address: List +) + +class Web3JLogsSearcherIntTest { + private lateinit var web3jClient: Web3j + private lateinit var logsClient: Web3JLogsSearcher + private lateinit var vertx: Vertx + private lateinit var wireMockServer: WireMockServer + private lateinit var TestingJsonRpcServer: TestingJsonRpcServer + private val address = "0x508ca82df566dcd1b0de8296e70a96332cd644ec" + private val log = LogManager.getLogger("test.case.Web3JLogsSearcherIntTest") + + @BeforeEach + fun beforeEach() { + vertx = Vertx.vertx() + } + + @AfterEach + fun tearDown() { + vertx.close() + } + + private fun setupClientWithWireMockServer( + retryConfig: RetryConfig = RetryConfig.noRetries + ) { + wireMockServer = WireMockServer(WireMockConfiguration.options().dynamicPort()) + wireMockServer.start() + + web3jClient = Web3j.build(HttpService(URI("http://127.0.0.1:" + wireMockServer.port()).toURL().toString())) + vertx = Vertx.vertx() + logsClient = Web3JLogsSearcher( + vertx, + web3jClient, + config = Web3JLogsSearcher.Config( + backoffDelay = 1.milliseconds, + requestRetryConfig = retryConfig + ) + ) + } + + private fun setupClientWithTestingJsonRpcServer( + retryConfig: RetryConfig = RetryConfig.noRetries, + subsetOfBlocksWithLogs: List? = null + ) { + TestingJsonRpcServer = TestingJsonRpcServer( + vertx = vertx, + serverName = "fake-execution-layer-log-searcher", + recordRequestsResponses = true + ) + setUpFakeLogsServerToHandleEthLogs(TestingJsonRpcServer, subsetOfBlocksWithLogs) + logsClient = Web3JLogsSearcher( + vertx, + web3jClient = Web3j.build(HttpService(URI("http://127.0.0.1:" + TestingJsonRpcServer.boundPort).toString())), + config = Web3JLogsSearcher.Config( + backoffDelay = 1.milliseconds, + requestRetryConfig = retryConfig + ), + log = LogManager.getLogger("test.case.Web3JLogsSearcher") + ) + } + + private fun replyEthGetLogsWith(statusCode: Int, responseBody: String) { + wireMockServer.stubFor( + post(urlEqualTo("/")) + .withRequestBody(containing("eth_getLogs")) + .willReturn( + aResponse() + .withStatus(statusCode) + .withBody(responseBody) + .withHeader("Content-Type", "application/json") + ) + ) + } + + @Test + fun `when eth_getLogs returns json-rpc error shall return failed promise`() { + setupClientWithWireMockServer() + replyEthGetLogsWith( + statusCode = 200, + responseBody = """ + { + "jsonrpc": "2.0", + "error": { + "code": -32000, + "message": "Error: unable to retrieve logs" + }, + "id": 1 + } + """.trimIndent() + ) + + assertThatThrownBy { + logsClient.getLogs( + 0UL.toBlockParameter(), + 20UL.toBlockParameter(), + address = address, + topics = emptyList() + ).get() + } + .hasCauseInstanceOf(RuntimeException::class.java) + .hasMessageContaining("json-rpc error: code=-32000 message=Error: unable to retrieve logs") + } + + @Test + fun `when eth_getLogs returns invalid json-rpc result shall return error instead of infinite retry`() { + setupClientWithWireMockServer() + replyEthGetLogsWith( + statusCode = 200, + responseBody = """ + { + "jsonrpc": "2.0", + "id": 1, + "result": [{ + "address": "0x508ca82df566dcd1b0de8296e70a96332cd644ec", + "blockHash": "0x216a74dcf", + "blockNumber": "0x864b52", + "data": "0x", + "logIndex": "0x0", + "removed": false, + "topics": ["0xe856c2b8bd4eb0027ce32eeaf595c21b0b6b4644b326e5b7bd80a1cf8db72e6c"], + "transactionHash": "0xfcff12cba7002ec38f391f2452", + "transactionIndex": "0x0" + }] + } + """.trimIndent() + ) + + assertThatThrownBy { + logsClient.getLogs( + 0UL.toBlockParameter(), + 20UL.toBlockParameter(), + address = address, + topics = emptyList() + ).get() + } + } + + @Test + fun `when eth_getLogs request fails shall retry request until it succeeds`() { + setupClientWithTestingJsonRpcServer( + retryConfig = RetryConfig( + backoffDelay = 1.milliseconds, + maxRetries = 4u + ) + ) + + TestingJsonRpcServer.handle("eth_getLogs", { _ -> + // simulate 2 failures + log.debug("eth_getLogs callCount=${TestingJsonRpcServer.callCountByMethod("eth_getLogs")}") + if (TestingJsonRpcServer.callCountByMethod("eth_getLogs") < 2) { + throw JsonRpcError.internalError().asException() + } else { + generateLogsForBlockRange(fromBlock = 10, toBlock = 15) + } + }) + + val getLogsFuture = logsClient.getLogs( + 0UL.toBlockParameter(), + 20UL.toBlockParameter(), + address = address, + topics = emptyList() + ) + + getLogsFuture.get().also { logs -> + assertThat(logs).hasSize(6) + } + } + + @Test + fun `when eth_getLogs gets an HTTP error shall return failed promise`() { + setupClientWithWireMockServer() + + replyEthGetLogsWith( + statusCode = 500, + responseBody = "Internal Server Error" + ) + + assertThatThrownBy { + logsClient.getLogs( + 0UL.toBlockParameter(), + 20UL.toBlockParameter(), + address = address, + topics = emptyList() + ).get() + } + .hasCauseInstanceOf(org.web3j.protocol.exceptions.ClientConnectionException::class.java) + .hasMessageContaining("Invalid response received: 500; Internal Server Error") + } + + @Test + fun `when eth_getLogs gets a DNS error shall return failed promise`() { + val randomHostname = "nowhere-${Random.nextBytes(20).encodeHex()}.local" + web3jClient = Web3j.build(HttpService("http://$randomHostname:1234")) + vertx = Vertx.vertx() + logsClient = Web3JLogsSearcher( + vertx, + web3jClient, + config = Web3JLogsSearcher.Config( + backoffDelay = 1.milliseconds, + requestRetryConfig = RetryConfig.noRetries + ) + ) + + assertThatThrownBy { + logsClient.getLogs( + 0UL.toBlockParameter(), + 20UL.toBlockParameter(), + address = address, + topics = emptyList() + ).get() + } + .hasCauseInstanceOf(java.net.UnknownHostException::class.java) + .hasMessageContaining("$randomHostname") + vertx.close() + } + + private fun shallContinueToSearch( + ethLog: EthLog, + targetNumber: ULong + ): SearchDirection? { + val number = ULong.fromHexString(ethLog.topics[1].encodeHex()) + return when { + number < targetNumber -> SearchDirection.FORWARD + number > targetNumber -> SearchDirection.BACKWARD + else -> null + } + } + + @Test + fun `findLogs searches and returns log when found`() { + setupClientWithTestingJsonRpcServer() + + (100..200) + .forEach { number -> + logsClient.findLog( + fromBlock = 100UL.toBlockParameter(), + toBlock = 200UL.toBlockParameter(), + address = address, + topics = listOf("0xffaabbcc"), + chunkSize = 10, + shallContinueToSearch = { ethLog -> + shallContinueToSearch(ethLog, targetNumber = number.toULong()) + } + ) + .get() + .also { log -> + assertThat(log).isNotNull() + assertThat(log!!.topics[1].encodeHex()).isEqualTo(number.toULong().toHexStringUInt256()) + } + } + } + + @Test + fun `findLogs searches L1 and returns null when not found - before range`() { + setupClientWithTestingJsonRpcServer() + + logsClient.findLog( + fromBlock = 100UL.toBlockParameter(), + toBlock = 200UL.toBlockParameter(), + address = address, + topics = listOf("0xffaabbcc"), + chunkSize = 10, + shallContinueToSearch = { ethLog -> + shallContinueToSearch(ethLog, targetNumber = 89UL) + } + ) + .get() + .also { log -> + assertThat(log).isNull() + assertThat(TestingJsonRpcServer.callCountByMethod("eth_getLogs")).isBetween(1, 4) + } + } + + @Test + fun `findLogs searches L1 and returns null when no logs in blockRange`() { + setupClientWithTestingJsonRpcServer( + subsetOfBlocksWithLogs = listOf(100UL..109UL, 150UL..159UL) + ) + + logsClient.findLog( + fromBlock = 100UL.toBlockParameter(), + toBlock = 200UL.toBlockParameter(), + address = address, + topics = listOf("0xffaabbcc"), + chunkSize = 10, + shallContinueToSearch = { ethLog -> + shallContinueToSearch(ethLog, targetNumber = 89UL) + } + ) + .get() + .also { log -> + assertThat(log).isNull() + } + } + + @Test + fun `findLogs searches L1 and returns null when not found - after range`() { + setupClientWithTestingJsonRpcServer() + logsClient.findLog( + fromBlock = 100UL.toBlockParameter(), + toBlock = 200UL.toBlockParameter(), + address = address, + topics = listOf("0xffaabbcc"), + chunkSize = 10, + shallContinueToSearch = { ethLog -> + shallContinueToSearch(ethLog, targetNumber = 250UL) + } + ) + .get() + .also { log -> + assertThat(log).isNull() + assertThat(TestingJsonRpcServer.callCountByMethod("eth_getLogs")).isBetween(1, 4) + } + } + + @Test + fun `findLogs searches L1 and returns null when range has no logs`() { + setupClientWithTestingJsonRpcServer( + subsetOfBlocksWithLogs = listOf(10UL..19UL, 50UL..59UL) + ) + logsClient.findLog( + fromBlock = 0UL.toBlockParameter(), + toBlock = 100UL.toBlockParameter(), + address = address, + topics = listOf("0xffaabbcc"), + chunkSize = 5, + shallContinueToSearch = { ethLog -> + shallContinueToSearch(ethLog, targetNumber = 35UL) + .also { println("log=${ethLog.blockNumber} direction=$it") } + } + ) + .get() + .also { log -> + assertThat(log).isNull() + assertThat(TestingJsonRpcServer.callCountByMethod("eth_getLogs")).isBetween(1, 11) + } + } + + companion object { + private fun generateLogsForBlockRange( + fromBlock: Int, + toBlock: Int, + stepSize: Int = 1, + topic: String = "0x" + ): List> { + return (fromBlock..toBlock step stepSize) + .map { + generateLogJson( + blockNumber = it, + topic = topic + ) + } + } + + private fun generateLogJson( + blockNumber: Int, + topic: String = "0x", + transactionHash: String = "0x" + ): Map { + val topics = listOf( + topic, + blockNumber.toULong().toHexStringUInt256() + ) + return mapOf( + "address" to "0x", + "blockHash" to "${blockNumber.toULong().toHexStringUInt256()}", + "blockNumber" to "${blockNumber.toULong().toHexString()}", + "data" to "0x", + "logIndex" to "0x0", + "removed" to false, + "topics" to topics, + "transactionHash" to transactionHash, + "transactionIndex" to "0x0" + ) + } + + internal fun generateLogs( + blocksWithLogs: List, + filter: EthGetLogsRequest + ): List> { + return generateEffectiveIntervals(blocksWithLogs, filter.fromBlock, filter.toBlock) + // .also { + // println( + // "filter=${CommonDomainFunctions.blockIntervalString(filter.fromBlock, filter.toBlock)} logs=$it" + // ) + // } + .flatMap { + generateLogsForBlockRange(it.first.toInt(), it.last.toInt(), topic = filter.topics[0]) + } + } + + @Suppress("UNCHECKED_CAST") + private fun parseEthLogsRequest(request: JsonRpcRequest): EthGetLogsRequest { + /** eth_getLogs request example + { + "jsonrpc": "2.0", + "method": "eth_getLogs", + "params": [{ + "topics": ["0xa0262dc79e4ccb71ceac8574ae906311ae338aa4a2044fd4ec4b99fad5ab60cb", "0xa0262dc79e4ccb71ceac8574ae906311ae338aa4a2044fd4ec4b99fad5ab60ff"], + "fromBlock": "earliest", + "toBlock": "latest", + "address": ["0xCf7Ed3AccA5a467e9e704C703E8D87F634fB0Fc9"] + }], + }*/ + val logsFilter = (request.params as List)[0] as Map + val fromBlock = ULong.fromHexString(logsFilter["fromBlock"] as String) + val toBlock = ULong.fromHexString(logsFilter["toBlock"] as String) + val topics = logsFilter["topics"] as List + return EthGetLogsRequest( + fromBlock = fromBlock, + toBlock = toBlock, + topics = topics, + address = logsFilter["address"] as List + ) + } + + private fun setUpFakeLogsServerToHandleEthLogs( + TestingJsonRpcServer: TestingJsonRpcServer, + subsetOfBlocksWithLogs: List? + ) { + TestingJsonRpcServer.apply { + this.handle("eth_getLogs", { request -> + val filter = parseEthLogsRequest(request) + subsetOfBlocksWithLogs + ?.let { + generateLogs(subsetOfBlocksWithLogs, filter) + } ?: generateLogsForBlockRange( + fromBlock = filter.fromBlock.toInt(), + toBlock = filter.toBlock.toInt(), + topic = filter.topics[0] + ) + }) + } + } + } +} diff --git a/state-recover/clients/smartcontract/src/integrationTest/resources/log4j2.xml b/jvm-libs/linea/web3j-extensions/src/test/resources/log4j2.xml similarity index 64% rename from state-recover/clients/smartcontract/src/integrationTest/resources/log4j2.xml rename to jvm-libs/linea/web3j-extensions/src/test/resources/log4j2.xml index 63ca5f6ca..13e4c9947 100644 --- a/state-recover/clients/smartcontract/src/integrationTest/resources/log4j2.xml +++ b/jvm-libs/linea/web3j-extensions/src/test/resources/log4j2.xml @@ -2,12 +2,14 @@ - + - - + + + + diff --git a/settings.gradle b/settings.gradle index 8ac12e88e..9007998c9 100644 --- a/settings.gradle +++ b/settings.gradle @@ -66,9 +66,11 @@ include 'transaction-exclusion-api:app' include 'transaction-exclusion-api:core' include 'transaction-exclusion-api:persistence:rejectedtransaction' -include 'state-recover:appcore:logic' -include 'state-recover:appcore:domain-models' include 'state-recover:appcore:clients-interfaces' +include 'state-recover:appcore:domain-models' +include 'state-recover:appcore:logic' +include 'state-recover:besu-plugin' include 'state-recover:clients:blobscan-client' include 'state-recover:clients:execution-layer-json-rpc-client' include 'state-recover:clients:eth-api' +include 'state-recover:test-cases' diff --git a/state-recover/appcore/clients-interfaces/build.gradle b/state-recover/appcore/clients-interfaces/build.gradle index 081b3e53a..77d31c11e 100644 --- a/state-recover/appcore/clients-interfaces/build.gradle +++ b/state-recover/appcore/clients-interfaces/build.gradle @@ -6,6 +6,7 @@ group = 'build.linea.staterecover' dependencies { api(project(':jvm-libs:generic:extensions:kotlin')) + api(project(':jvm-libs:generic:serialization:jackson')) api(project(':jvm-libs:linea:core:domain-models')) api(project(':state-recover:appcore:domain-models')) } diff --git a/state-recover/appcore/clients-interfaces/src/main/kotlin/build/linea/staterecover/clients/ExecutionLayerClient.kt b/state-recover/appcore/clients-interfaces/src/main/kotlin/build/linea/staterecover/clients/ExecutionLayerClient.kt deleted file mode 100644 index 97b9d40a1..000000000 --- a/state-recover/appcore/clients-interfaces/src/main/kotlin/build/linea/staterecover/clients/ExecutionLayerClient.kt +++ /dev/null @@ -1,12 +0,0 @@ -package build.linea.staterecover.clients - -import build.linea.staterecover.BlockL1RecoveredData -import net.consensys.linea.BlockNumberAndHash -import net.consensys.linea.BlockParameter -import tech.pegasys.teku.infrastructure.async.SafeFuture - -interface ExecutionLayerClient { - fun getBlockNumberAndHash(blockParameter: BlockParameter): SafeFuture - fun lineaEngineImportBlocksFromBlob(blocks: List): SafeFuture - fun lineaEngineForkChoiceUpdated(headBlockHash: ByteArray, finalizedBlockHash: ByteArray): SafeFuture -} diff --git a/state-recover/appcore/clients-interfaces/src/main/kotlin/build/linea/staterecover/clients/BlobFetcher.kt b/state-recover/appcore/clients-interfaces/src/main/kotlin/linea/staterecover/BlobFetcher.kt similarity index 81% rename from state-recover/appcore/clients-interfaces/src/main/kotlin/build/linea/staterecover/clients/BlobFetcher.kt rename to state-recover/appcore/clients-interfaces/src/main/kotlin/linea/staterecover/BlobFetcher.kt index 71523de7f..c3f42d66a 100644 --- a/state-recover/appcore/clients-interfaces/src/main/kotlin/build/linea/staterecover/clients/BlobFetcher.kt +++ b/state-recover/appcore/clients-interfaces/src/main/kotlin/linea/staterecover/BlobFetcher.kt @@ -1,4 +1,4 @@ -package build.linea.staterecover.clients +package linea.staterecover import tech.pegasys.teku.infrastructure.async.SafeFuture diff --git a/state-recover/appcore/clients-interfaces/src/main/kotlin/linea/staterecover/ExecutionLayerClient.kt b/state-recover/appcore/clients-interfaces/src/main/kotlin/linea/staterecover/ExecutionLayerClient.kt new file mode 100644 index 000000000..cab9ad994 --- /dev/null +++ b/state-recover/appcore/clients-interfaces/src/main/kotlin/linea/staterecover/ExecutionLayerClient.kt @@ -0,0 +1,16 @@ +package linea.staterecover + +import net.consensys.linea.BlockNumberAndHash +import net.consensys.linea.BlockParameter +import tech.pegasys.teku.infrastructure.async.SafeFuture + +data class StateRecoveryStatus( + val headBlockNumber: ULong, + val stateRecoverStartBlockNumber: ULong? +) +interface ExecutionLayerClient { + fun getBlockNumberAndHash(blockParameter: BlockParameter): SafeFuture + fun lineaEngineImportBlocksFromBlob(blocks: List): SafeFuture + fun lineaGetStateRecoveryStatus(): SafeFuture + fun lineaEnableStateRecovery(stateRecoverStartBlockNumber: ULong): SafeFuture +} diff --git a/state-recover/appcore/clients-interfaces/src/main/kotlin/linea/staterecover/RecoveryStatusPersistence.kt b/state-recover/appcore/clients-interfaces/src/main/kotlin/linea/staterecover/RecoveryStatusPersistence.kt new file mode 100644 index 000000000..238a39ac6 --- /dev/null +++ b/state-recover/appcore/clients-interfaces/src/main/kotlin/linea/staterecover/RecoveryStatusPersistence.kt @@ -0,0 +1,81 @@ +package linea.staterecover + +import com.fasterxml.jackson.core.JacksonException +import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper +import java.nio.file.Path + +interface RecoveryStatusPersistence { + fun saveRecoveryStartBlockNumber(recoveryStartBlockNumber: ULong) + fun getRecoveryStartBlockNumber(): ULong? +} + +class InMemoryRecoveryStatus : RecoveryStatusPersistence { + private var recoveryStartBlockNumber: ULong? = null + + @Synchronized + override fun saveRecoveryStartBlockNumber(recoveryStartBlockNumber: ULong) { + this.recoveryStartBlockNumber = recoveryStartBlockNumber + } + + @Synchronized + override fun getRecoveryStartBlockNumber(): ULong? { + return recoveryStartBlockNumber + } +} + +class FileBasedRecoveryStatusPersistence( + filePath: Path +) : RecoveryStatusPersistence { + // A little future proofing in case we need to change the file format in the future + private enum class FileVersion { + V1 // note: do not rename because it will fail to parse the file if already written + } + + private data class RecoveryStatusEnvelopeDto( + val version: FileVersion, + val recoveryStatus: RecoveryStatusV1Dto? + ) + + private data class RecoveryStatusV1Dto( + val recoveryStartBlockNumber: ULong + ) + private val objectMapper = jacksonObjectMapper() + private val file = filePath.toFile() + private var currentStatus: RecoveryStatusV1Dto? = loadStatusFromFileOrCreateIfDoesNotExist() + + private fun saveToFile(status: RecoveryStatusV1Dto?) { + file.writeText( + objectMapper.writeValueAsString( + RecoveryStatusEnvelopeDto(FileVersion.V1, status) + ) + ) + } + + private fun loadStatusFromFileOrCreateIfDoesNotExist(): RecoveryStatusV1Dto? { + // eager file write because if we cannot read/write the file, then application shall throw and fail early + return if (!file.exists()) { + // Create the file with an empty status + saveToFile(status = null) + null + } else { + // read status from file + val envelope = try { + objectMapper.readValue(file, RecoveryStatusEnvelopeDto::class.java) + } catch (e: JacksonException) { + throw IllegalStateException("failed to parse recovery status file: ${file.absolutePath} ", e) + } + envelope.recoveryStatus + } + } + + @Synchronized + override fun saveRecoveryStartBlockNumber(recoveryStartBlockNumber: ULong) { + saveToFile(status = RecoveryStatusV1Dto(recoveryStartBlockNumber)) + currentStatus = RecoveryStatusV1Dto(recoveryStartBlockNumber) + } + + @Synchronized + override fun getRecoveryStartBlockNumber(): ULong? { + return currentStatus?.recoveryStartBlockNumber + } +} diff --git a/state-recover/appcore/clients-interfaces/src/main/kotlin/linea/staterecover/TransactionDetailsClient.kt b/state-recover/appcore/clients-interfaces/src/main/kotlin/linea/staterecover/TransactionDetailsClient.kt new file mode 100644 index 000000000..f8e9c42da --- /dev/null +++ b/state-recover/appcore/clients-interfaces/src/main/kotlin/linea/staterecover/TransactionDetailsClient.kt @@ -0,0 +1,7 @@ +package linea.staterecover + +import tech.pegasys.teku.infrastructure.async.SafeFuture + +interface TransactionDetailsClient { + fun getBlobVersionedHashesByTransactionHash(transactionHash: ByteArray): SafeFuture> +} diff --git a/state-recover/appcore/clients-interfaces/src/test/kotlin/linea/staterecover/FileRecoveryStatusPersistenceTest.kt b/state-recover/appcore/clients-interfaces/src/test/kotlin/linea/staterecover/FileRecoveryStatusPersistenceTest.kt new file mode 100644 index 000000000..2ec00e8cc --- /dev/null +++ b/state-recover/appcore/clients-interfaces/src/test/kotlin/linea/staterecover/FileRecoveryStatusPersistenceTest.kt @@ -0,0 +1,87 @@ +package linea.staterecover + +import org.assertj.core.api.Assertions.assertThat +import org.assertj.core.api.Assertions.assertThatThrownBy +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.io.TempDir +import java.nio.file.Files +import java.nio.file.Path +import java.nio.file.attribute.PosixFilePermissions + +class FileRecoveryStatusPersistenceTest { + private lateinit var recoveryStatusPersistence: RecoveryStatusPersistence + + @Test + fun `should return null when no recovery start block number is saved`( + @TempDir tempDir: Path + ) { + val recoveryStatusPersistence = FileBasedRecoveryStatusPersistence(tempDir.resolve("recovery-status.json")) + assertThat(recoveryStatusPersistence.getRecoveryStartBlockNumber()).isNull() + } + + @Test + fun `should return the saved recovery start block number`( + @TempDir tempDir: Path + ) { + FileBasedRecoveryStatusPersistence(tempDir.resolve("recovery-status.json")) + .also { persistence -> + assertThat(persistence.saveRecoveryStartBlockNumber(10U)) + assertThat(persistence.getRecoveryStartBlockNumber()).isEqualTo(10UL) + } + + // simulate application restart, the saved recovery start block number should be loaded from file OK + FileBasedRecoveryStatusPersistence(tempDir.resolve("recovery-status.json")) + .also { persistence -> + assertThat(persistence.getRecoveryStartBlockNumber()).isEqualTo(10UL) + assertThat(persistence.saveRecoveryStartBlockNumber(11U)) + assertThat(persistence.getRecoveryStartBlockNumber()).isEqualTo(11UL) + } + + // simulate application restart, the saved recovery start block number should be loaded from file OK + FileBasedRecoveryStatusPersistence(tempDir.resolve("recovery-status.json")) + .also { persistence -> + assertThat(persistence.getRecoveryStartBlockNumber()).isEqualTo(11UL) + } + } + + @Test + fun `shall throw when it cannot create the file`( + @TempDir tempDir: Path + ) { + val dirWithoutWritePermissions = tempDir.resolve("dir-without-write-permissions") + + Files.createDirectory(dirWithoutWritePermissions) + Files.setPosixFilePermissions(dirWithoutWritePermissions, PosixFilePermissions.fromString("r-xr-xr-x")) + + val file = dirWithoutWritePermissions.resolve("recovery-status.json") + + assertThatThrownBy { + recoveryStatusPersistence = FileBasedRecoveryStatusPersistence(file) + } + .hasMessageContaining(file.toString()) + .hasMessageContaining("Permission denied") + } + + @Test + fun `should throw error when file version is not supported`( + @TempDir tempDir: Path + ) { + val invalidJsonPayload = """ + { + "version": "2", + "recoveryStatus": { + "recoveryStartBlockNumber": 10 + } + } + """.trimIndent() + val file = tempDir.resolve("recovery-status.json") + Files.write(file, invalidJsonPayload.toByteArray()) + + assertThatThrownBy { + recoveryStatusPersistence = FileBasedRecoveryStatusPersistence(file) + } + .isInstanceOf(IllegalStateException::class.java) + .hasMessageContaining(file.toString()) + .hasMessageContaining("parse") + } +} diff --git a/state-recover/appcore/domain-models/src/main/kotlin/build/linea/staterecover/TransactionL1RecoveredData.kt b/state-recover/appcore/domain-models/src/main/kotlin/build/linea/staterecover/TransactionL1RecoveredData.kt deleted file mode 100644 index cd09e2a78..000000000 --- a/state-recover/appcore/domain-models/src/main/kotlin/build/linea/staterecover/TransactionL1RecoveredData.kt +++ /dev/null @@ -1,74 +0,0 @@ -package build.linea.staterecover - -import java.math.BigInteger - -data class TransactionL1RecoveredData( - val type: UByte, - val nonce: ULong, - val maxPriorityFeePerGas: BigInteger, - val maxFeePerGas: BigInteger, - val gasLimit: ULong, - val from: ByteArray, - val to: ByteArray, - val value: BigInteger, - val data: ByteArray, - val accessList: List -) { - - data class AccessTuple( - val address: ByteArray, - val storageKeys: List - ) { - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (javaClass != other?.javaClass) return false - - other as AccessTuple - - if (!address.contentEquals(other.address)) return false - if (storageKeys != other.storageKeys) return false - - return true - } - - override fun hashCode(): Int { - var result = address.contentHashCode() - result = 31 * result + storageKeys.hashCode() - return result - } - } - - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (javaClass != other?.javaClass) return false - - other as TransactionL1RecoveredData - - if (type != other.type) return false - if (nonce != other.nonce) return false - if (maxPriorityFeePerGas != other.maxPriorityFeePerGas) return false - if (maxFeePerGas != other.maxFeePerGas) return false - if (gasLimit != other.gasLimit) return false - if (!from.contentEquals(other.from)) return false - if (!to.contentEquals(other.to)) return false - if (value != other.value) return false - if (!data.contentEquals(other.data)) return false - if (accessList != other.accessList) return false - - return true - } - - override fun hashCode(): Int { - var result = type.hashCode() - result = 31 * result + nonce.hashCode() - result = 31 * result + maxPriorityFeePerGas.hashCode() - result = 31 * result + maxFeePerGas.hashCode() - result = 31 * result + gasLimit.hashCode() - result = 31 * result + from.contentHashCode() - result = 31 * result + to.contentHashCode() - result = 31 * result + value.hashCode() - result = 31 * result + data.contentHashCode() - result = 31 * result + accessList.hashCode() - return result - } -} diff --git a/state-recover/appcore/domain-models/src/main/kotlin/build/linea/staterecover/BlockL1RecoveredData.kt b/state-recover/appcore/domain-models/src/main/kotlin/linea/staterecover/BlockFromL1RecoveredData.kt similarity index 68% rename from state-recover/appcore/domain-models/src/main/kotlin/build/linea/staterecover/BlockL1RecoveredData.kt rename to state-recover/appcore/domain-models/src/main/kotlin/linea/staterecover/BlockFromL1RecoveredData.kt index be0eef8f2..4e65a6a95 100644 --- a/state-recover/appcore/domain-models/src/main/kotlin/build/linea/staterecover/BlockL1RecoveredData.kt +++ b/state-recover/appcore/domain-models/src/main/kotlin/linea/staterecover/BlockFromL1RecoveredData.kt @@ -1,44 +1,21 @@ -package build.linea.staterecover +package linea.staterecover import kotlinx.datetime.Instant import net.consensys.encodeHex -data class BlockExtraData( - val beneficiary: ByteArray -) { - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (javaClass != other?.javaClass) return false - - other as BlockExtraData - - return beneficiary.contentEquals(other.beneficiary) - } - - override fun hashCode(): Int { - return beneficiary.contentHashCode() - } - - override fun toString(): String { - return "BlockExtraData(beneficiary=${beneficiary.encodeHex()})" - } -} - -data class BlockL1RecoveredData( +data class BlockHeaderFromL1RecoveredData( val blockNumber: ULong, val blockHash: ByteArray, val coinbase: ByteArray, val blockTimestamp: Instant, val gasLimit: ULong, - val difficulty: ULong, - val extraData: BlockExtraData, - val transactions: List + val difficulty: ULong ) { override fun equals(other: Any?): Boolean { if (this === other) return true if (javaClass != other?.javaClass) return false - other as BlockL1RecoveredData + other as BlockHeaderFromL1RecoveredData if (blockNumber != other.blockNumber) return false if (!blockHash.contentEquals(other.blockHash)) return false @@ -46,8 +23,6 @@ data class BlockL1RecoveredData( if (blockTimestamp != other.blockTimestamp) return false if (gasLimit != other.gasLimit) return false if (difficulty != other.difficulty) return false - if (extraData != other.extraData) return false - if (transactions != other.transactions) return false return true } @@ -59,20 +34,44 @@ data class BlockL1RecoveredData( result = 31 * result + blockTimestamp.hashCode() result = 31 * result + gasLimit.hashCode() result = 31 * result + difficulty.hashCode() - result = 31 * result + extraData.hashCode() - result = 31 * result + transactions.hashCode() return result } override fun toString(): String { - return "BlockL1RecoveredData(" + + return "BlockHeaderFromL1RecoveredData(" + "blockNumber=$blockNumber, " + "blockHash=${blockHash.encodeHex()}, " + - "coinbase=${coinbase.encodeHex()}, " + + "coinbase=${coinbase.encodeHex()}," + "blockTimestamp=$blockTimestamp, " + "gasLimit=$gasLimit, " + - "difficulty=$difficulty, " + - "extraData=$extraData, " + - "transactions=$transactions)" + "difficulty=$difficulty" + + ")" + } +} + +data class BlockFromL1RecoveredData( + val header: BlockHeaderFromL1RecoveredData, + val transactions: List +) { + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as BlockFromL1RecoveredData + + if (header != other.header) return false + if (transactions != other.transactions) return false + + return true + } + + override fun hashCode(): Int { + var result = header.hashCode() + result = 31 * result + transactions.hashCode() + return result + } + + override fun toString(): String { + return "BlockFromL1RecoveredData(header=$header, transactions=$transactions)" } } diff --git a/state-recover/appcore/domain-models/src/main/kotlin/linea/staterecover/TransactionFromL1RecoveredData.kt b/state-recover/appcore/domain-models/src/main/kotlin/linea/staterecover/TransactionFromL1RecoveredData.kt new file mode 100644 index 000000000..3b21faaa3 --- /dev/null +++ b/state-recover/appcore/domain-models/src/main/kotlin/linea/staterecover/TransactionFromL1RecoveredData.kt @@ -0,0 +1,103 @@ +package linea.staterecover + +import net.consensys.encodeHex +import java.math.BigInteger + +data class TransactionFromL1RecoveredData( + val type: UByte, + val nonce: ULong, + val maxPriorityFeePerGas: BigInteger?, + val maxFeePerGas: BigInteger?, + val gasPrice: BigInteger?, + val gasLimit: ULong, + val from: ByteArray, + val to: ByteArray?, + val value: BigInteger, + val data: ByteArray?, + val accessList: List? +) { + + data class AccessTuple( + val address: ByteArray, + val storageKeys: List + ) { + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as AccessTuple + + if (!address.contentEquals(other.address)) return false + if (storageKeys != other.storageKeys) return false + + return true + } + + override fun hashCode(): Int { + var result = address.contentHashCode() + result = 31 * result + storageKeys.hashCode() + return result + } + + override fun toString(): String { + return "AccessTuple(address=${address.encodeHex()}, storageKeys=$storageKeys)" + } + } + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as TransactionFromL1RecoveredData + + if (type != other.type) return false + if (nonce != other.nonce) return false + if (maxPriorityFeePerGas != other.maxPriorityFeePerGas) return false + if (maxFeePerGas != other.maxFeePerGas) return false + if (gasPrice != other.gasPrice) return false + if (gasLimit != other.gasLimit) return false + if (!from.contentEquals(other.from)) return false + if (to != null) { + if (other.to == null) return false + if (!to.contentEquals(other.to)) return false + } else if (other.to != null) return false + if (value != other.value) return false + if (data != null) { + if (other.data == null) return false + if (!data.contentEquals(other.data)) return false + } else if (other.data != null) return false + if (accessList != other.accessList) return false + + return true + } + + override fun hashCode(): Int { + var result = type.hashCode() + result = 31 * result + nonce.hashCode() + result = 31 * result + (maxPriorityFeePerGas?.hashCode() ?: 0) + result = 31 * result + (maxFeePerGas?.hashCode() ?: 0) + result = 31 * result + (gasPrice?.hashCode() ?: 0) + result = 31 * result + gasLimit.hashCode() + result = 31 * result + from.contentHashCode() + result = 31 * result + (to?.contentHashCode() ?: 0) + result = 31 * result + value.hashCode() + result = 31 * result + (data?.contentHashCode() ?: 0) + result = 31 * result + (accessList?.hashCode() ?: 0) + return result + } + + override fun toString(): String { + return "TransactionL1RecoveredData(" + + "type=$type, " + + "nonce=$nonce, " + + "maxPriorityFeePerGas=$maxPriorityFeePerGas, " + + "maxFeePerGas=$maxFeePerGas, " + + "gasPrice=$gasPrice, " + + "gasLimit=$gasLimit, " + + "from=${from.encodeHex()}, " + + "to=${to?.encodeHex()}, " + + "value=$value, " + + "data=${data?.encodeHex()}, " + + "accessList=$accessList)" + } +} diff --git a/state-recover/appcore/logic/build.gradle b/state-recover/appcore/logic/build.gradle new file mode 100644 index 000000000..09a7e0800 --- /dev/null +++ b/state-recover/appcore/logic/build.gradle @@ -0,0 +1,27 @@ +plugins { + id 'net.consensys.zkevm.kotlin-library-conventions' +} + +group = 'build.linea.staterecover' + +dependencies { + api("io.vertx:vertx-core:${libs.versions.vertx.get()}") + api(project(':jvm-libs:generic:extensions:kotlin')) + api(project(':jvm-libs:generic:logging')) + api(project(':jvm-libs:linea:core:domain-models')) + api(project(':jvm-libs:linea:core:long-running-service')) + api(project(':jvm-libs:linea:clients:interfaces')) + api(project(':jvm-libs:linea:clients:linea-state-manager')) + api(project(':jvm-libs:linea:blob-decompressor')) + api(project(':state-recover:appcore:clients-interfaces')) + api(project(':state-recover:appcore:domain-models')) + api project(':jvm-libs:linea:besu-rlp-and-mappers') + api project(':jvm-libs:linea:besu-libs') + + testImplementation(project(":jvm-libs:linea:testing:file-system")) + testImplementation(testFixtures(project(":jvm-libs:linea:blob-compressor"))) + testImplementation("org.bouncycastle:bcprov-jdk18on:1.78.1") + testImplementation("org.apache.logging.log4j:log4j-slf4j2-impl:${libs.versions.log4j.get()}") { + because "besu libs in the tests use slf4j" + } +} diff --git a/state-recover/appcore/logic/src/main/kotlin/linea/staterecover/BlobDecompressorAndDeserializer.kt b/state-recover/appcore/logic/src/main/kotlin/linea/staterecover/BlobDecompressorAndDeserializer.kt new file mode 100644 index 000000000..fabe322bd --- /dev/null +++ b/state-recover/appcore/logic/src/main/kotlin/linea/staterecover/BlobDecompressorAndDeserializer.kt @@ -0,0 +1,144 @@ +package linea.staterecover + +import io.vertx.core.Vertx +import kotlinx.datetime.Clock +import kotlinx.datetime.Instant +import linea.domain.BinaryDecoder +import linea.rlp.BesuRlpBlobDecoder +import linea.rlp.RLP +import net.consensys.decodeHex +import net.consensys.encodeHex +import net.consensys.linea.CommonDomainFunctions +import net.consensys.linea.async.toSafeFuture +import net.consensys.linea.blob.BlobDecompressor +import org.apache.logging.log4j.LogManager +import org.apache.logging.log4j.Logger +import org.hyperledger.besu.ethereum.core.Block +import tech.pegasys.teku.infrastructure.async.SafeFuture +import java.util.concurrent.Callable +import kotlin.jvm.optionals.getOrNull + +interface BlobDecompressorAndDeserializer { + /** + * Decompresses the EIP4844 blobs and deserializes them into domain objects. + */ + fun decompress( + startBlockNumber: ULong, + blobs: List + ): SafeFuture> +} + +data class BlockHeaderStaticFields( + val coinbase: ByteArray, + val gasLimit: ULong = 61_000_000UL, + val difficulty: ULong = 2UL +) { + companion object { + val mainnet = BlockHeaderStaticFields( + coinbase = "0x8F81e2E3F8b46467523463835F965fFE476E1c9E".decodeHex() + ) + val sepolia = BlockHeaderStaticFields( + coinbase = "0x4D517Aef039A48b3B6bF921e210b7551C8E37107".decodeHex() + ) + val localDev = BlockHeaderStaticFields( + coinbase = "0x6d976c9b8ceee705d4fe8699b44e5eb58242f484".decodeHex() + ) + } + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as BlockHeaderStaticFields + + if (!coinbase.contentEquals(other.coinbase)) return false + if (gasLimit != other.gasLimit) return false + if (difficulty != other.difficulty) return false + + return true + } + + override fun hashCode(): Int { + var result = coinbase.contentHashCode() + result = 31 * result + gasLimit.hashCode() + result = 31 * result + difficulty.hashCode() + return result + } + + override fun toString(): String { + return "BlockHeaderStaticFields(coinbase=${coinbase.encodeHex()}, gasLimit=$gasLimit, difficulty=$difficulty)" + } +} + +class BlobDecompressorToDomainV1( + val decompressor: BlobDecompressor, + val staticFields: BlockHeaderStaticFields, + val vertx: Vertx, + val decoder: BinaryDecoder = BesuRlpBlobDecoder, + val logger: Logger = LogManager.getLogger(BlobDecompressorToDomainV1::class.java) +) : BlobDecompressorAndDeserializer { + override fun decompress( + startBlockNumber: ULong, + blobs: List + ): SafeFuture> { + var blockNumber = startBlockNumber + val startTime = Clock.System.now() + logger.debug("start decompressing blobs: startBlockNumber={} {} blobs", startBlockNumber, blobs.size) + val decompressedBlobs = blobs.map { decompressor.decompress(it) } + return SafeFuture + .collectAll(decompressedBlobs.map(::decodeBlocksAsync).stream()) + .thenApply { blobsBlocks: List> -> + blobsBlocks.flatten().map { block -> + val header = BlockHeaderFromL1RecoveredData( + blockNumber = blockNumber++, + blockHash = block.header.hash.toArray(), + coinbase = staticFields.coinbase, + blockTimestamp = Instant.fromEpochSeconds(block.header.timestamp), + gasLimit = this.staticFields.gasLimit, + difficulty = this.staticFields.difficulty + ) + val transactions = block.body.transactions.map { transaction -> + TransactionFromL1RecoveredData( + type = transaction.type.serializedType.toUByte(), + from = transaction.sender.toArray(), + nonce = transaction.nonce.toULong(), + gasLimit = transaction.gasLimit.toULong(), + maxFeePerGas = transaction.maxFeePerGas.getOrNull()?.asBigInteger, + maxPriorityFeePerGas = transaction.maxPriorityFeePerGas.getOrNull()?.asBigInteger, + gasPrice = transaction.gasPrice.getOrNull()?.asBigInteger, + to = transaction.to.getOrNull()?.toArray(), + value = transaction.value.asBigInteger, + data = transaction.payload.toArray(), + accessList = transaction.accessList.getOrNull()?.map { accessTuple -> + TransactionFromL1RecoveredData.AccessTuple( + address = accessTuple.address.toArray(), + storageKeys = accessTuple.storageKeys.map { it.toArray() } + ) + } + ) + } + BlockFromL1RecoveredData( + header = header, + transactions = transactions + ) + } + }.thenPeek { + val endTime = Clock.System.now() + logger.debug( + "blobs decompressed and serialized: duration={} blobsCount={} blocks={}", + endTime - startTime, + blobs.size, + CommonDomainFunctions.blockIntervalString(startBlockNumber, blockNumber - 1UL) + ) + } + } + + private fun decodeBlocksAsync(blocksRLP: ByteArray): SafeFuture> { + return vertx.executeBlocking( + Callable { RLP.decodeList(blocksRLP).map(decoder::decode) }, + false + ) + .onFailure(logger::error) + .toSafeFuture() + } +} diff --git a/state-recover/appcore/logic/src/main/kotlin/linea/staterecover/BlockImporter.kt b/state-recover/appcore/logic/src/main/kotlin/linea/staterecover/BlockImporter.kt new file mode 100644 index 000000000..404f3cdb5 --- /dev/null +++ b/state-recover/appcore/logic/src/main/kotlin/linea/staterecover/BlockImporter.kt @@ -0,0 +1,77 @@ +package linea.staterecover + +import build.linea.clients.StateManagerClientV1 +import build.linea.domain.BlockInterval +import io.vertx.core.Vertx +import net.consensys.linea.async.AsyncRetryer +import tech.pegasys.teku.infrastructure.async.SafeFuture +import kotlin.time.Duration +import kotlin.time.Duration.Companion.seconds + +data class ImportResult( + val blockNumber: ULong, + val zkStateRootHash: ByteArray +) { + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as ImportResult + + if (blockNumber != other.blockNumber) return false + if (!zkStateRootHash.contentEquals(other.zkStateRootHash)) return false + + return true + } + + override fun hashCode(): Int { + var result = blockNumber.hashCode() + result = 31 * result + zkStateRootHash.contentHashCode() + return result + } +} + +interface BlockImporterAndStateVerifier { + fun importBlocks(blocks: List): SafeFuture +} + +class BlockImporterAndStateVerifierV1( + private val vertx: Vertx, + private val elClient: ExecutionLayerClient, + private val stateManagerClient: StateManagerClientV1, + private val stateManagerImportTimeoutPerBlock: Duration +) : BlockImporterAndStateVerifier { + override fun importBlocks(blocks: List): SafeFuture { + return elClient + .lineaEngineImportBlocksFromBlob(blocks) + .thenCompose { + getBlockStateRootHash( + blockNumber = blocks.last().header.blockNumber, + timeout = stateManagerImportTimeoutPerBlock.times(blocks.size) + ) + } + .thenApply { stateRootHash -> + ImportResult( + blockNumber = blocks.last().header.blockNumber, + zkStateRootHash = stateRootHash + ) + } + } + + private fun getBlockStateRootHash( + blockNumber: ULong, + timeout: Duration + ): SafeFuture { + return AsyncRetryer + .retry( + vertx, + backoffDelay = 1.seconds, + timeout = timeout, + stopRetriesPredicate = { headBlockNumber -> headBlockNumber >= blockNumber }, + action = { stateManagerClient.rollupGetHeadBlockNumber() } + ) + .thenCompose { + stateManagerClient.rollupGetStateMerkleProof(BlockInterval(blockNumber, blockNumber)) + }.thenApply { proofResponse -> proofResponse.zkEndStateRootHash } + } +} diff --git a/state-recover/appcore/clients-interfaces/src/main/kotlin/build/linea/staterecover/clients/LineaSubmissionEventsClient.kt b/state-recover/appcore/logic/src/main/kotlin/linea/staterecover/LineaSubmissionEventsClient.kt similarity index 94% rename from state-recover/appcore/clients-interfaces/src/main/kotlin/build/linea/staterecover/clients/LineaSubmissionEventsClient.kt rename to state-recover/appcore/logic/src/main/kotlin/linea/staterecover/LineaSubmissionEventsClient.kt index 789e3a38d..be4006fe0 100644 --- a/state-recover/appcore/clients-interfaces/src/main/kotlin/build/linea/staterecover/clients/LineaSubmissionEventsClient.kt +++ b/state-recover/appcore/logic/src/main/kotlin/linea/staterecover/LineaSubmissionEventsClient.kt @@ -1,4 +1,4 @@ -package build.linea.staterecover.clients +package linea.staterecover import build.linea.domain.BlockInterval import build.linea.domain.EthLog @@ -14,6 +14,7 @@ data class DataSubmittedV3( val finalStateRootHash: ByteArray ) { companion object { + val topic = "0x55f4c645c36aa5cd3f443d6be44d7a7a5df9d2100d7139dfc69d4289ee072319" fun fromEthLog(ethLog: EthLog): EthLogEvent { // DataSubmittedV3(bytes32 parentShnarf, bytes32 indexed shnarf, bytes32 finalStateRootHash); return EthLogEvent( @@ -63,6 +64,7 @@ data class DataFinalizedV3( val finalStateRootHash: ByteArray ) : BlockInterval { companion object { + val topic = "0xa0262dc79e4ccb71ceac8574ae906311ae338aa4a2044fd4ec4b99fad5ab60cb" fun fromEthLog(ethLog: EthLog): EthLogEvent { /**event DataFinalizedV3( uint256 indexed startBlockNumber, @@ -126,7 +128,7 @@ data class FinalizationAndDataEventsV3( interface LineaRollupSubmissionEventsClient { fun findDataFinalizedEventByStartBlockNumber( - l2BlockNumber: ULong + l2StartBlockNumberInclusive: ULong ): SafeFuture?> fun findDataFinalizedEventContainingBlock( diff --git a/state-recover/clients/smartcontract/src/main/kotlin/linea/build/staterecover/clients/smartcontract/LineaSubmissionEventsClientWeb3jIpml.kt b/state-recover/appcore/logic/src/main/kotlin/linea/staterecover/LineaSubmissionEventsClientImpl.kt similarity index 54% rename from state-recover/clients/smartcontract/src/main/kotlin/linea/build/staterecover/clients/smartcontract/LineaSubmissionEventsClientWeb3jIpml.kt rename to state-recover/appcore/logic/src/main/kotlin/linea/staterecover/LineaSubmissionEventsClientImpl.kt index 7d7da3e57..f3f96a4c2 100644 --- a/state-recover/clients/smartcontract/src/main/kotlin/linea/build/staterecover/clients/smartcontract/LineaSubmissionEventsClientWeb3jIpml.kt +++ b/state-recover/appcore/logic/src/main/kotlin/linea/staterecover/LineaSubmissionEventsClientImpl.kt @@ -1,41 +1,48 @@ -package linea.build.staterecover.clients.smartcontract +package linea.staterecover -import build.linea.contract.LineaRollupV6 import build.linea.domain.EthLogEvent -import build.linea.staterecover.clients.DataFinalizedV3 -import build.linea.staterecover.clients.DataSubmittedV3 -import build.linea.staterecover.clients.FinalizationAndDataEventsV3 -import build.linea.staterecover.clients.LineaRollupSubmissionEventsClient -import build.linea.web3j.domain.toDomain -import build.linea.web3j.domain.toWeb3j +import linea.EthLogsSearcher +import linea.SearchDirection import net.consensys.encodeHex import net.consensys.linea.BlockParameter import net.consensys.linea.BlockParameter.Companion.toBlockParameter -import net.consensys.linea.contract.Web3JLogsClient import net.consensys.toHexStringUInt256 -import org.web3j.abi.EventEncoder -import org.web3j.protocol.core.methods.request.EthFilter -import org.web3j.protocol.core.methods.response.Log import tech.pegasys.teku.infrastructure.async.SafeFuture -class LineaSubmissionEventsClientWeb3jIpml( - private val logsClient: Web3JLogsClient, +class LineaSubmissionEventsClientImpl( + private val logsSearcher: EthLogsSearcher, private val smartContractAddress: String, - private val mostRecentBlockTag: BlockParameter = BlockParameter.Tag.FINALIZED + private val l1EarliestSearchBlock: BlockParameter = BlockParameter.Tag.EARLIEST, + private val l1LatestSearchBlock: BlockParameter = BlockParameter.Tag.FINALIZED, + private val logsBlockChunkSize: Int = 1000 ) : LineaRollupSubmissionEventsClient { - - override fun findDataFinalizedEventContainingBlock(l2BlockNumber: ULong): SafeFuture?> { - TODO("Not yet implemented") + override fun findDataFinalizedEventContainingBlock( + l2BlockNumber: ULong + ): SafeFuture?> { + return logsSearcher.findLog( + fromBlock = l1EarliestSearchBlock, + toBlock = l1LatestSearchBlock, + address = smartContractAddress, + topics = listOf(DataFinalizedV3.topic), + chunkSize = logsBlockChunkSize, + shallContinueToSearch = { log -> + val (event) = DataFinalizedV3.fromEthLog(log) + when { + l2BlockNumber < event.startBlockNumber -> SearchDirection.BACKWARD + l2BlockNumber > event.endBlockNumber -> SearchDirection.FORWARD + else -> null + } + } + ).thenApply { it?.let { DataFinalizedV3.fromEthLog(it) } } } override fun findDataFinalizedEventByStartBlockNumber( - l2BlockNumber: ULong + l2StartBlockNumberInclusive: ULong ): SafeFuture?> { - // TODO: be less eager on block range to search return findDataFinalizedV3Event( - fromL1BlockNumber = BlockParameter.Tag.EARLIEST, - toL1BlockNumber = mostRecentBlockTag, - startBlockNumber = l2BlockNumber + fromL1BlockNumber = l1EarliestSearchBlock, + toL1BlockNumber = l1LatestSearchBlock, + startBlockNumber = l2StartBlockNumberInclusive ) } @@ -43,8 +50,8 @@ class LineaSubmissionEventsClientWeb3jIpml( l2StartBlockNumberInclusive: ULong ): SafeFuture { return findDataFinalizedV3Event( - fromL1BlockNumber = BlockParameter.Tag.EARLIEST, - toL1BlockNumber = mostRecentBlockTag, + fromL1BlockNumber = l1EarliestSearchBlock, + toL1BlockNumber = l1LatestSearchBlock, startBlockNumber = l2StartBlockNumberInclusive ) .thenCompose { finalizationEvent -> @@ -69,40 +76,37 @@ class LineaSubmissionEventsClientWeb3jIpml( "Either startBlockNumber or endBlockNumber must be provided" } - val ethFilter = - EthFilter( - fromL1BlockNumber.toWeb3j(), - toL1BlockNumber.toWeb3j(), - smartContractAddress - ).apply { - /** - event DataFinalizedV3( - uint256 indexed startBlockNumber, - uint256 indexed endBlockNumber, - bytes32 indexed shnarf, - bytes32 parentStateRootHash, - bytes32 finalStateRootHash - ); - */ - addSingleTopic(EventEncoder.encode(LineaRollupV6.DATAFINALIZEDV3_EVENT)) - addSingleTopic(startBlockNumber?.toHexStringUInt256()) - addSingleTopic(endBlockNumber?.toHexStringUInt256()) - } - - return logsClient - .getLogs(ethFilter) - .thenApply(Companion::parseDataFinalizedV3) - .thenCompose { finalizedEvents -> - if (finalizedEvents.size > 1) { - // just a safety check - // this should never happen: Finalization events shall be sequential and deterministic - val errorMessage = - "More than one DataFinalizedV3 event found for startBlockNumber=$startBlockNumber events=$finalizedEvents" - SafeFuture.failedFuture(IllegalStateException(errorMessage)) - } else { - SafeFuture.completedFuture(finalizedEvents.firstOrNull()) - } + /** + event DataFinalizedV3( + uint256 indexed startBlockNumber, + uint256 indexed endBlockNumber, + bytes32 indexed shnarf, + bytes32 parentStateRootHash, + bytes32 finalStateRootHash + ); + */ + return logsSearcher.getLogs( + fromBlock = fromL1BlockNumber, + toBlock = toL1BlockNumber, + address = smartContractAddress, + topics = listOf( + DataFinalizedV3.topic, + startBlockNumber?.toHexStringUInt256(), + endBlockNumber?.toHexStringUInt256() + ) + ).thenCompose { rawLogs -> + val finalizedEvents = rawLogs.map(DataFinalizedV3::fromEthLog) + + if (finalizedEvents.size > 1) { + // just a safety check + // this should never happen: Finalization events shall be sequential and deterministic + val errorMessage = + "More than one DataFinalizedV3 event found for startBlockNumber=$startBlockNumber events=$finalizedEvents" + SafeFuture.failedFuture(IllegalStateException(errorMessage)) + } else { + SafeFuture.completedFuture(finalizedEvents.firstOrNull()) } + } } private fun findAggregationDataSubmittedV3Events( @@ -154,21 +158,18 @@ class LineaSubmissionEventsClientWeb3jIpml( tol1BlockParameter: BlockParameter, shnarf: ByteArray ): SafeFuture?> { - val ethFilter = - EthFilter( - fromL1BlockParameter.toWeb3j(), - tol1BlockParameter.toWeb3j(), - smartContractAddress - ).apply { - // event DataSubmittedV3(bytes32 parentShnarf, bytes32 indexed shnarf, bytes32 finalStateRootHash); - addSingleTopic(EventEncoder.encode(LineaRollupV6.DATASUBMITTEDV3_EVENT)) - addSingleTopic(shnarf.encodeHex()) // shnarf - } - - return logsClient - .getLogs(ethFilter) - .thenApply(Companion::parseDataSubmittedV3) - .thenApply { events -> + return logsSearcher + .getLogs( + fromBlock = fromL1BlockParameter, + toBlock = tol1BlockParameter, + address = smartContractAddress, + topics = listOf( + DataSubmittedV3.topic, + shnarf.encodeHex() + ) + ) + .thenApply { rawLogs -> + val events = rawLogs.map(DataSubmittedV3::fromEthLog) if (events.size > 1) { // just a safety check // this should never happen: having more than blob with the same shnarf @@ -180,14 +181,4 @@ class LineaSubmissionEventsClientWeb3jIpml( } } } - - companion object { - private fun parseDataSubmittedV3(logs: List): List> { - return logs.map { log -> DataSubmittedV3.fromEthLog(log.toDomain()) } - } - - private fun parseDataFinalizedV3(logs: List): List> { - return logs.map { log -> DataFinalizedV3.fromEthLog(log.toDomain()) } - } - } } diff --git a/state-recover/appcore/logic/src/main/kotlin/linea/staterecover/StateRecoverApp.kt b/state-recover/appcore/logic/src/main/kotlin/linea/staterecover/StateRecoverApp.kt new file mode 100644 index 000000000..a7d18c2d5 --- /dev/null +++ b/state-recover/appcore/logic/src/main/kotlin/linea/staterecover/StateRecoverApp.kt @@ -0,0 +1,192 @@ +package linea.staterecover + +import build.linea.clients.StateManagerClientV1 +import build.linea.contract.l1.LineaRollupSmartContractClientReadOnly +import build.linea.domain.EthLogEvent +import io.vertx.core.Vertx +import linea.EthLogsSearcher +import net.consensys.linea.BlockParameter +import net.consensys.linea.BlockParameter.Companion.toBlockParameter +import net.consensys.linea.async.AsyncRetryer +import net.consensys.linea.blob.BlobDecompressorVersion +import net.consensys.linea.blob.GoNativeBlobDecompressorFactory +import net.consensys.zkevm.LongRunningService +import org.apache.logging.log4j.LogManager +import tech.pegasys.teku.infrastructure.async.SafeFuture +import java.util.concurrent.CompletableFuture +import kotlin.time.Duration +import kotlin.time.Duration.Companion.seconds + +class StateRecoverApp( + private val vertx: Vertx, + // Driving Ports + private val lineaContractClient: LineaRollupSmartContractClientReadOnly, + private val ethLogsSearcher: EthLogsSearcher, + // Driven Ports + private val blobFetcher: BlobFetcher, + private val elClient: ExecutionLayerClient, + private val stateManagerClient: StateManagerClientV1, + private val transactionDetailsClient: TransactionDetailsClient, + private val blockHeaderStaticFields: BlockHeaderStaticFields, + // configs + private val config: Config = Config.lineaMainnet +) : LongRunningService { + data class Config( + val smartContractAddress: String, + val l1EarliestSearchBlock: BlockParameter = BlockParameter.Tag.EARLIEST, + val l1LatestSearchBlock: BlockParameter = BlockParameter.Tag.FINALIZED, + val l1PollingInterval: Duration = 12.seconds, + val executionClientPollingInterval: Duration = 1.seconds, + val blobDecompressorVersion: BlobDecompressorVersion = BlobDecompressorVersion.V1_1_0, + val logsBlockChunkSize: UInt = 1000u, + /** + * The block number at which the recovery mode will start overriding the recovery start block number + * this is meant for testing purposes, not production + */ + val overridingRecoveryStartBlockNumber: ULong? = null + ) { + companion object { + val lineaMainnet = Config( + smartContractAddress = "0xd19d4b5d358258f05d7b411e21a1460d11b0876f", + // TODO: set block of V6 Upgrade + l1EarliestSearchBlock = 1UL.toBlockParameter(), + l1LatestSearchBlock = BlockParameter.Tag.FINALIZED, + executionClientPollingInterval = 10.seconds, + l1PollingInterval = 12.seconds + ) + val lineaSepolia = Config( + smartContractAddress = "0xb218f8a4bc926cf1ca7b3423c154a0d627bdb7e5", + l1EarliestSearchBlock = 7164537UL.toBlockParameter(), + l1LatestSearchBlock = BlockParameter.Tag.FINALIZED, + executionClientPollingInterval = 10.seconds, + l1PollingInterval = 12.seconds + ) + } + } + + init { + require(config.smartContractAddress.lowercase() == lineaContractClient.getAddress().lowercase()) { + "contract address mismatch: config=${config.smartContractAddress} client=${lineaContractClient.getAddress()}" + } + } + private val l1EventsClient = LineaSubmissionEventsClientImpl( + logsSearcher = ethLogsSearcher, + smartContractAddress = config.smartContractAddress, + l1EarliestSearchBlock = config.l1EarliestSearchBlock, + l1LatestSearchBlock = config.l1LatestSearchBlock, + logsBlockChunkSize = config.logsBlockChunkSize.toInt() + ) + private val log = LogManager.getLogger(this::class.java) + private val blockImporterAndStateVerifier = BlockImporterAndStateVerifierV1( + vertx = vertx, + elClient = elClient, + stateManagerClient = stateManagerClient, + stateManagerImportTimeoutPerBlock = 2.seconds + ) + private val blobDecompressor: BlobDecompressorAndDeserializer = BlobDecompressorToDomainV1( + decompressor = GoNativeBlobDecompressorFactory.getInstance(config.blobDecompressorVersion), + staticFields = blockHeaderStaticFields, + vertx = vertx + ) + private val stateSynchronizerService = StateSynchronizerService( + vertx = vertx, + elClient = elClient, + submissionEventsClient = l1EventsClient, + blobsFetcher = blobFetcher, + transactionDetailsClient = transactionDetailsClient, + blobDecompressor = blobDecompressor, + blockImporterAndStateVerifier = blockImporterAndStateVerifier, + pollingInterval = config.l1PollingInterval + ) + val lastSuccessfullyRecoveredFinalization: EthLogEvent? + get() = stateSynchronizerService.lastSuccessfullyProcessedFinalization + val stateRootMismatchFound: Boolean + get() = stateSynchronizerService.stateRootMismatchFound + + fun trySetRecoveryModeAtBlockHeight(stateRecoverStartBlockNumber: ULong): SafeFuture { + return elClient + .lineaGetStateRecoveryStatus() + .thenCompose { statusBeforeUpdate -> + elClient + .lineaEnableStateRecovery(stateRecoverStartBlockNumber) + .thenPeek { newStatus -> + val updateLabel = if (statusBeforeUpdate.stateRecoverStartBlockNumber == null) "Enabled" else "Updated" + log.info( + "Recovery mode was {}: headBlockNumber={} " + + "prevStartBlockNumber={} newStartBlockNumber={}", + updateLabel, + newStatus.headBlockNumber, + statusBeforeUpdate.stateRecoverStartBlockNumber, + newStatus.stateRecoverStartBlockNumber + ) + } + } + } + + private fun enableRecoveryMode(): SafeFuture<*> { + if (config.overridingRecoveryStartBlockNumber != null) { + return trySetRecoveryModeAtBlockHeight(config.overridingRecoveryStartBlockNumber) + } + + return elClient + .lineaGetStateRecoveryStatus() + .thenCompose { status -> + if (status.stateRecoverStartBlockNumber != null) { + // already enabled, let's just resume from where we left off + log.info( + "starting recovery mode already enabled: stateRecoverStartBlockNumber={} headBlockNumber={}", + status.stateRecoverStartBlockNumber, + status.headBlockNumber + ) + SafeFuture.completedFuture(Unit) + } else { + lineaContractClient.finalizedL2BlockNumber(blockParameter = config.l1LatestSearchBlock) + .thenCompose { lastFinalizedBlockNumber -> + val stateRecoverStartBlockNumber = lastFinalizedBlockNumber + 1UL + log.info( + "Starting enabling recovery mode: stateRecoverStartBlockNumber={} headBlockNumber={}", + stateRecoverStartBlockNumber, + status.headBlockNumber + ) + elClient.lineaEnableStateRecovery(stateRecoverStartBlockNumber) + }.thenApply { } + } + } + } + + private fun waitForSyncUntilStateRecoverBlock(): SafeFuture { + return AsyncRetryer.retry( + vertx = vertx, + backoffDelay = config.executionClientPollingInterval, + stopRetriesPredicate = { recoveryStatus -> + log.debug( + "waiting for node to sync until stateRecoverStartBlockNumber={} headBlockNumber={}", + recoveryStatus.stateRecoverStartBlockNumber, + recoveryStatus.headBlockNumber + ) + // headBlockNumber shall be at least 1 block behind of stateRecoverStartBlockNumber + // if it is after it means it was already enabled + recoveryStatus.stateRecoverStartBlockNumber?.let { startBlockNumber -> + recoveryStatus.headBlockNumber + 1u >= startBlockNumber + } ?: false + } + ) { + elClient.lineaGetStateRecoveryStatus() + } + } + + override fun start(): CompletableFuture { + log.warn("Starting StateRecoverApp") + val enablementFuture = enableRecoveryMode() + + enablementFuture + .thenCompose { waitForSyncUntilStateRecoverBlock() } + .thenCompose { stateSynchronizerService.start() } + + return enablementFuture.thenApply { } + } + + override fun stop(): CompletableFuture { + return stateSynchronizerService.stop() + } +} diff --git a/state-recover/appcore/logic/src/main/kotlin/linea/staterecover/StateSynchronizerService.kt b/state-recover/appcore/logic/src/main/kotlin/linea/staterecover/StateSynchronizerService.kt new file mode 100644 index 000000000..8d7bf4173 --- /dev/null +++ b/state-recover/appcore/logic/src/main/kotlin/linea/staterecover/StateSynchronizerService.kt @@ -0,0 +1,163 @@ +package linea.staterecover + +import build.linea.domain.EthLogEvent +import io.vertx.core.Vertx +import net.consensys.encodeHex +import net.consensys.linea.BlockNumberAndHash +import net.consensys.linea.BlockParameter +import net.consensys.zkevm.PeriodicPollingService +import org.apache.logging.log4j.LogManager +import org.apache.logging.log4j.Logger +import tech.pegasys.teku.infrastructure.async.SafeFuture +import kotlin.time.Duration + +class StateSynchronizerService( + private val vertx: Vertx, + private val elClient: ExecutionLayerClient, + private val submissionEventsClient: LineaRollupSubmissionEventsClient, + private val blobsFetcher: BlobFetcher, + private val transactionDetailsClient: TransactionDetailsClient, + private val blobDecompressor: BlobDecompressorAndDeserializer, + private val blockImporterAndStateVerifier: BlockImporterAndStateVerifier, + private val pollingInterval: Duration, + private val log: Logger = LogManager.getLogger(StateSynchronizerService::class.java) +) : PeriodicPollingService( + vertx = vertx, + log = log, + pollingIntervalMs = pollingInterval.inWholeMilliseconds +) { + private data class DataSubmittedEventAndBlobs( + val ethLogEvent: EthLogEvent, + val blobs: List + ) + + var lastSuccessfullyProcessedFinalization: EthLogEvent? = null + var stateRootMismatchFound: Boolean = false + private set(value) { + field = value + } + + private fun findNextFinalization(): SafeFuture?> { + return if (lastSuccessfullyProcessedFinalization != null) { + submissionEventsClient + .findDataFinalizedEventByStartBlockNumber( + l2StartBlockNumberInclusive = lastSuccessfullyProcessedFinalization!!.event.endBlockNumber + 1UL + ) + } else { + elClient.getBlockNumberAndHash(blockParameter = BlockParameter.Tag.LATEST) + .thenCompose { headBlock -> + // 1st, assuming head matches a prev finalization, + val nextBlockToImport = headBlock.number + 1UL + submissionEventsClient + .findDataFinalizedEventByStartBlockNumber(l2StartBlockNumberInclusive = nextBlockToImport) + .thenCompose { finalizationEvent -> + if (finalizationEvent != null) { + SafeFuture.completedFuture(finalizationEvent) + } else { + // 2nd: otherwise, local head may be in between, let's find corresponding finalization + submissionEventsClient + .findDataFinalizedEventContainingBlock(l2BlockNumber = nextBlockToImport) + } + } + } + } + } + + override fun action(): SafeFuture { + if (stateRootMismatchFound) { + return SafeFuture.failedFuture(IllegalStateException("state root mismatch found cannot continue")) + } + + return findNextFinalization() + .thenCompose { nextFinalization -> + if (nextFinalization == null) { + // nothing to do for now + SafeFuture.completedFuture(null) + } else { + submissionEventsClient + .findDataSubmittedV3EventsUntilNextFinalization( + l2StartBlockNumberInclusive = nextFinalization.event.startBlockNumber + ) + } + } + .thenCompose { submissionEvents -> + if (submissionEvents == null) { + SafeFuture.completedFuture("No new events") + } else { + getBlobsForEvents(submissionEvents.dataSubmittedEvents) + .thenCompose { dataSubmissionsWithBlobs -> + updateNodeWithBlobsAndVerifyState(dataSubmissionsWithBlobs, submissionEvents.dataFinalizedEvent.event) + } + .thenApply { + lastSuccessfullyProcessedFinalization = submissionEvents.dataFinalizedEvent + } + } + } + } + + private fun getBlobsForEvents( + events: List> + ): SafeFuture> { + return SafeFuture.collectAll( + events + .map { dataSubmittedEvent -> + transactionDetailsClient + .getBlobVersionedHashesByTransactionHash(dataSubmittedEvent.log.transactionHash) + .thenCompose(blobsFetcher::fetchBlobsByHash) + .thenApply { blobs -> DataSubmittedEventAndBlobs(dataSubmittedEvent, blobs) } + }.stream() + ) + } + + private fun updateNodeWithBlobsAndVerifyState( + dataSubmissions: List, + dataFinalizedV3: DataFinalizedV3 + ): SafeFuture { + return blobDecompressor + .decompress( + startBlockNumber = dataFinalizedV3.startBlockNumber, + blobs = dataSubmissions.flatMap { it.blobs } + ).thenCompose { decompressedBlocks: List -> + log.debug("importing blocks={}", dataFinalizedV3.intervalString()) + blockImporterAndStateVerifier + .importBlocks(decompressedBlocks) + .thenCompose { importResult -> + log.debug("imported blocks={}", dataFinalizedV3.intervalString()) + assertStateMatches(importResult, dataFinalizedV3) + } + .thenApply { + BlockNumberAndHash( + number = decompressedBlocks.last().header.blockNumber, + hash = decompressedBlocks.last().header.blockHash + ) + } + } + } + + private fun assertStateMatches( + importResult: ImportResult, + finalizedV3: DataFinalizedV3 + ): SafeFuture { + return if (importResult.zkStateRootHash.contentEquals(finalizedV3.finalStateRootHash)) { + log.info( + "state recovered up to block={} zkStateRootHash={} finalization={}", + importResult.blockNumber, + importResult.zkStateRootHash.encodeHex(), + finalizedV3.intervalString() + ) + SafeFuture.completedFuture(Unit) + } else { + log.error( + "stopping data recovery from L1, stateRootHash mismatch: " + + "finalization={} recoveredStateRootHash={} expected block={} to have l1 proven stateRootHash={}", + finalizedV3.intervalString(), + finalizedV3.finalStateRootHash.encodeHex(), + importResult.zkStateRootHash.encodeHex(), + finalizedV3.endBlockNumber + ) + stateRootMismatchFound = true + this.stop() + SafeFuture.completedFuture(Unit) + } + } +} diff --git a/state-recover/appcore/logic/src/test/kotlin/linea/staterecover/BlobDecompressorAndDeserializerV1Test.kt b/state-recover/appcore/logic/src/test/kotlin/linea/staterecover/BlobDecompressorAndDeserializerV1Test.kt new file mode 100644 index 000000000..2229c49b9 --- /dev/null +++ b/state-recover/appcore/logic/src/test/kotlin/linea/staterecover/BlobDecompressorAndDeserializerV1Test.kt @@ -0,0 +1,137 @@ +package linea.staterecover + +import io.vertx.core.Vertx +import kotlinx.datetime.Instant +import linea.blob.BlobCompressor +import linea.blob.GoBackedBlobCompressor +import linea.rlp.RLP +import net.consensys.encodeHex +import net.consensys.linea.blob.BlobCompressorVersion +import net.consensys.linea.blob.BlobDecompressorVersion +import net.consensys.linea.blob.GoNativeBlobDecompressorFactory +import net.consensys.linea.nativecompressor.CompressorTestData +import org.apache.tuweni.bytes.Bytes32 +import org.assertj.core.api.Assertions.assertThat +import org.assertj.core.api.Assertions.fail +import org.hyperledger.besu.datatypes.Address +import org.hyperledger.besu.ethereum.core.Block +import org.hyperledger.besu.ethereum.core.Transaction +import org.junit.jupiter.api.AfterEach +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.TestInstance +import org.opentest4j.AssertionFailedError +import kotlin.jvm.optionals.getOrNull + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +class BlobDecompressorAndDeserializerV1Test { + private lateinit var compressor: BlobCompressor + private val blockStaticFields = BlockHeaderStaticFields( + coinbase = Address.ZERO.toArray(), + gasLimit = 30_000_000UL, + difficulty = 0UL + ) + private lateinit var decompressorToDomain: BlobDecompressorAndDeserializer + private lateinit var vertx: Vertx + + @BeforeEach + fun setUp() { + vertx = Vertx.vertx() + compressor = GoBackedBlobCompressor.getInstance( + compressorVersion = BlobCompressorVersion.V1_0_1, + dataLimit = 124u * 1024u + ) + val decompressor = GoNativeBlobDecompressorFactory.getInstance(BlobDecompressorVersion.V1_1_0) + decompressorToDomain = BlobDecompressorToDomainV1(decompressor, blockStaticFields, vertx) + } + + @AfterEach + fun afterEach() { + vertx.close() + } + + @Test + fun `should decompress block and transactions`() { + val blocksRLP = CompressorTestData.blocksRlpEncoded + assertBlockCompressionAndDecompression(blocksRLP) + } + + private fun assertBlockCompressionAndDecompression( + blocksRLP: List + ) { + val blocks = blocksRLP.map(RLP::decodeBlockWithMainnetFunctions) + val startingBlockNumber = blocks[0].header.number.toULong() + + val blobs = blocks.chunked(2).map { compressBlocks(it) } + + val recoveredBlocks = decompressorToDomain.decompress( + startBlockNumber = startingBlockNumber, + blobs = blobs + ).get() + assertThat(recoveredBlocks[0].header.blockNumber).isEqualTo(startingBlockNumber) + + recoveredBlocks.zip(blocks) { recoveredBlock, originalBlock -> + assertBlockData(recoveredBlock, originalBlock) + } + } + + private fun assertBlockData( + uncompressed: BlockFromL1RecoveredData, + original: Block + ) { + try { + assertThat(uncompressed.header.blockNumber).isEqualTo(original.header.number.toULong()) + assertThat(uncompressed.header.blockHash.encodeHex()).isEqualTo(original.header.hash.toArray().encodeHex()) + assertThat(uncompressed.header.coinbase).isEqualTo(blockStaticFields.coinbase) + assertThat(uncompressed.header.blockTimestamp).isEqualTo(Instant.fromEpochSeconds(original.header.timestamp)) + assertThat(uncompressed.header.gasLimit).isEqualTo(blockStaticFields.gasLimit) + assertThat(uncompressed.header.difficulty).isEqualTo(blockStaticFields.difficulty) + uncompressed.transactions.zip(original.body.transactions) { uncompressedTransaction, originalTransaction -> + assertTransactionData(uncompressedTransaction, originalTransaction) + } + } catch (e: AssertionFailedError) { + fail( + "uncompressed block does not match expected original: blockNumber: ${e.message} " + + "\n original =$original " + + "\n uncompressed=$uncompressed ", + e + ) + } + } + + private fun assertTransactionData( + uncompressed: TransactionFromL1RecoveredData, + original: Transaction + ) { + assertThat(uncompressed.type).isEqualTo(original.type.serializedType.toUByte()) + assertThat(uncompressed.from).isEqualTo(original.sender.toArray()) + assertThat(uncompressed.nonce).isEqualTo(original.nonce.toULong()) + assertThat(uncompressed.to).isEqualTo(original.to.getOrNull()?.toArray()) + assertThat(uncompressed.gasLimit).isEqualTo(original.gasLimit.toULong()) + assertThat(uncompressed.maxFeePerGas).isEqualTo(original.maxFeePerGas.getOrNull()?.asBigInteger) + assertThat(uncompressed.maxPriorityFeePerGas).isEqualTo(original.maxPriorityFeePerGas.getOrNull()?.asBigInteger) + assertThat(uncompressed.gasPrice).isEqualTo(original.gasPrice.getOrNull()?.asBigInteger) + assertThat(uncompressed.value).isEqualTo(original.value.asBigInteger) + assertThat(uncompressed.data?.encodeHex()).isEqualTo(original.payload?.toArray()?.encodeHex()) + if (uncompressed.accessList.isNullOrEmpty() != original.accessList.getOrNull().isNullOrEmpty()) { + assertThat(uncompressed.accessList).isEqualTo(original.accessList.getOrNull()) + } else { + uncompressed.accessList?.zip(original.accessList.getOrNull()!!) { a, b -> + assertThat(a.address).isEqualTo(b.address.toArray()) + assertThat(a.storageKeys.map { Bytes32.wrap(it) }).isEqualTo(b.storageKeys) + } + } + } + + private fun compressBlocks(blocks: List): ByteArray { + return compress(blocks.map { block -> block.toRlp().toArray() }) + } + + private fun compress(blocks: List): ByteArray { + blocks.forEach { blockRlp -> + compressor.appendBlock(blockRlp) + } + + return compressor.getCompressedDataAndReset() + } +} diff --git a/state-recover/besu-plugin/build.gradle b/state-recover/besu-plugin/build.gradle new file mode 100644 index 000000000..b8a9c92f2 --- /dev/null +++ b/state-recover/besu-plugin/build.gradle @@ -0,0 +1,71 @@ +plugins { + id 'net.consensys.zkevm.kotlin-library-conventions' + id 'com.gradleup.shadow' version '8.3.5' +} + +group = 'build.linea.staterecover' +archivesBaseName = 'linea-staterecover-plugin' +version = '0.0.1-rc2' + +dependencies { + compileOnly("info.picocli:picocli:${libs.versions.picoli.get()}") { + because 'Required for command line parsing. Provided by Besu at runtime.' + } + implementation "org.jetbrains.kotlin:kotlin-reflect:1.9.21" + api(project(":jvm-libs:generic:serialization:jackson")) + api(project(":jvm-libs:linea:clients:linea-l1-contract-client")) + api(project(":jvm-libs:linea:web3j-extensions")) + api(project(":state-recover:appcore:logic")) + api(project(":state-recover:clients:blobscan-client")) + api(project(":state-recover:clients:eth-api")) + api(project(":state-recover:clients:execution-layer-json-rpc-client")) +} + +ext.groupsToIncludeInShadow = [ + "build.linea.*", + "io.micrometer.*", + "org.jetbrains.kotlin:kotlin-reflect.*", + "org.jetbrains.kotlinx:kotlinx-datetime.*", + "tech.pegasys.teku.internal:async", + "io.vertx.*", + // this can be removed once Besu updates to Vertx 4.12+ + "com.michael-bull.kotlin-result:kotlin-result.*", + "com.fasterxml.jackson.module:jackson-module-kotlin", +] + +def canIncludeLib(String lib) { + def allowed = groupsToIncludeInShadow.find { libAllowed -> + lib.matches(libAllowed) + } != null + allowed +} + +tasks.create("testLibsInclusion", Task) { + // def lib = "build.linea.internal:kotlin-extensions" + doLast { + def lib = "com.michael-bull.kotlin-result:kotlin-result" + println("Can include $lib: ${canIncludeLib(lib)}") + } +} + +shadowJar { + if ("${project.version}" != 'unspecified') { + archiveClassifier.set('') + archiveVersion.set("${project.version}") + } + + dependencies { + exclude { dependency -> + !canIncludeLib("${dependency.moduleGroup}:${dependency.moduleName}") + } + } + + manifest { + attributes( + 'Specification-Title': archiveBaseName, + 'Specification-Version': project.version, + 'Implementation-Title': archiveBaseName, + 'Implementation-Version': project.version, + ) + } +} diff --git a/state-recover/besu-plugin/src/main/kotlin/linea/staterecover/clients/ExecutionLayerInProcessClient.kt b/state-recover/besu-plugin/src/main/kotlin/linea/staterecover/clients/ExecutionLayerInProcessClient.kt new file mode 100644 index 000000000..0b6e51918 --- /dev/null +++ b/state-recover/besu-plugin/src/main/kotlin/linea/staterecover/clients/ExecutionLayerInProcessClient.kt @@ -0,0 +1,110 @@ +package linea.staterecover.clients + +import linea.staterecover.BlockFromL1RecoveredData +import linea.staterecover.ExecutionLayerClient +import linea.staterecover.RecoveryStatusPersistence +import linea.staterecover.StateRecoveryStatus +import linea.staterecover.plugin.BlockImporter +import linea.staterecover.plugin.RecoveryModeManager +import net.consensys.linea.BlockNumberAndHash +import net.consensys.linea.BlockParameter +import org.apache.logging.log4j.LogManager +import org.hyperledger.besu.plugin.data.BlockHeader +import org.hyperledger.besu.plugin.services.BlockSimulationService +import org.hyperledger.besu.plugin.services.BlockchainService +import org.hyperledger.besu.plugin.services.sync.SynchronizationService +import tech.pegasys.teku.infrastructure.async.SafeFuture +import kotlin.jvm.optionals.getOrNull + +class ExecutionLayerInProcessClient( + private val blockchainService: BlockchainService, + private val stateRecoveryModeManager: RecoveryModeManager, + private val stateRecoveryStatusPersistence: RecoveryStatusPersistence, + private val blockImporter: BlockImporter +) : ExecutionLayerClient { + companion object { + fun create( + blockchainService: BlockchainService, + simulatorService: BlockSimulationService, + synchronizationService: SynchronizationService, + stateRecoveryModeManager: RecoveryModeManager, + stateRecoveryStatusPersistence: RecoveryStatusPersistence + ): ExecutionLayerInProcessClient { + return ExecutionLayerInProcessClient( + blockchainService = blockchainService, + stateRecoveryModeManager = stateRecoveryModeManager, + stateRecoveryStatusPersistence = stateRecoveryStatusPersistence, + blockImporter = BlockImporter( + blockchainService = blockchainService, + simulatorService = simulatorService, + synchronizationService = synchronizationService + ) + ) + } + } + + private val log = LogManager.getLogger(ExecutionLayerInProcessClient::class.java) + + override fun getBlockNumberAndHash(blockParameter: BlockParameter): SafeFuture { + val blockHeader: BlockHeader? = when (blockParameter) { + is BlockParameter.Tag -> when { + blockParameter == BlockParameter.Tag.LATEST -> blockchainService.chainHeadHeader + else -> throw IllegalArgumentException("Unsupported block parameter: $blockParameter") + } + + is BlockParameter.BlockNumber -> + blockchainService + .getBlockByNumber(blockParameter.getNumber().toLong()) + .map { it.blockHeader } + .getOrNull() + } + + return blockHeader + ?.let { + SafeFuture.completedFuture( + BlockNumberAndHash( + it.number.toULong(), + it.blockHash.toArray() + ) + ) + } + ?: SafeFuture.failedFuture(IllegalArgumentException("Block not found for parameter: $blockParameter")) + } + + override fun lineaEngineImportBlocksFromBlob(blocks: List): SafeFuture { + logBlockImport(blocks) + return kotlin.runCatching { + blocks.map { blockImporter.importBlock(it) } + SafeFuture.completedFuture(Unit) + }.getOrElse { th -> SafeFuture.failedFuture(th) } + } + + override fun lineaGetStateRecoveryStatus(): SafeFuture { + return SafeFuture + .completedFuture( + StateRecoveryStatus( + headBlockNumber = stateRecoveryModeManager.headBlockNumber, + stateRecoverStartBlockNumber = stateRecoveryModeManager.targetBlockNumber + ) + ) + } + + override fun lineaEnableStateRecovery(stateRecoverStartBlockNumber: ULong): SafeFuture { + stateRecoveryModeManager.setTargetBlockNumber(stateRecoverStartBlockNumber) + + return SafeFuture.completedFuture( + StateRecoveryStatus( + headBlockNumber = stateRecoveryModeManager.headBlockNumber, + stateRecoverStartBlockNumber = stateRecoveryStatusPersistence.getRecoveryStartBlockNumber() + ) + ) + } + + private fun logBlockImport(blocks: List) { + if (log.isTraceEnabled) { + log.trace("importing blocks from blob: blocks={}", blocks) + } else { + log.debug("importing blocks from blob: blocks={}", blocks.map { it.header.blockNumber }) + } + } +} diff --git a/state-recover/besu-plugin/src/main/kotlin/linea/staterecover/plugin/AppConfigurator.kt b/state-recover/besu-plugin/src/main/kotlin/linea/staterecover/plugin/AppConfigurator.kt new file mode 100644 index 000000000..e7b25bec2 --- /dev/null +++ b/state-recover/besu-plugin/src/main/kotlin/linea/staterecover/plugin/AppConfigurator.kt @@ -0,0 +1,93 @@ +package linea.staterecover.plugin + +import build.linea.clients.StateManagerClientV1 +import build.linea.clients.StateManagerV1JsonRpcClient +import build.linea.contract.l1.Web3JLineaRollupSmartContractClientReadOnly +import io.micrometer.core.instrument.MeterRegistry +import io.vertx.core.Vertx +import io.vertx.micrometer.backends.BackendRegistries +import linea.build.staterecover.clients.VertxTransactionDetailsClient +import linea.staterecover.BlockHeaderStaticFields +import linea.staterecover.ExecutionLayerClient +import linea.staterecover.StateRecoverApp +import linea.staterecover.TransactionDetailsClient +import linea.staterecover.clients.blobscan.BlobScanClient +import linea.web3j.Web3JLogsSearcher +import linea.web3j.createWeb3jHttpClient +import net.consensys.linea.jsonrpc.client.RequestRetryConfig +import net.consensys.linea.jsonrpc.client.VertxHttpJsonRpcClientFactory +import org.apache.logging.log4j.LogManager +import java.net.URI +import kotlin.time.Duration.Companion.seconds + +fun createAppAllInProcess( + vertx: Vertx = Vertx.vertx(), + meterRegistry: MeterRegistry = BackendRegistries.getDefaultNow(), + elClient: ExecutionLayerClient, + stateManagerClientEndpoint: URI, + l1RpcEndpoint: URI, + blobScanEndpoint: URI, + blockHeaderStaticFields: BlockHeaderStaticFields, + appConfig: StateRecoverApp.Config +): StateRecoverApp { + val lineaContractClient = Web3JLineaRollupSmartContractClientReadOnly( + contractAddress = appConfig.smartContractAddress, + web3j = createWeb3jHttpClient( + rpcUrl = l1RpcEndpoint.toString(), + log = LogManager.getLogger("linea.plugin.staterecover.clients.l1.smart-contract") + ) + ) + val ethLogsSearcher = run { + val log = LogManager.getLogger("linea.plugin.staterecover.clients.l1.logs-searcher") + Web3JLogsSearcher( + vertx = vertx, + web3jClient = createWeb3jHttpClient( + rpcUrl = l1RpcEndpoint.toString(), + log = log + ), + log = log + ) + } + val blobScanClient = BlobScanClient.create( + vertx = vertx, + endpoint = blobScanEndpoint, + requestRetryConfig = RequestRetryConfig( + backoffDelay = 1.seconds + ), + logger = LogManager.getLogger("linea.plugin.staterecover.clients.l1.blob-scan") + ) + val jsonRpcClientFactory = VertxHttpJsonRpcClientFactory(vertx, meterRegistry) + val stateManagerClient: StateManagerClientV1 = StateManagerV1JsonRpcClient.create( + rpcClientFactory = jsonRpcClientFactory, + endpoints = listOf(stateManagerClientEndpoint), + maxInflightRequestsPerClient = 10u, + requestRetry = RequestRetryConfig( + backoffDelay = 1.seconds + ), + zkStateManagerVersion = "2.3.0", + logger = LogManager.getLogger("linea.plugin.staterecover.clients.state-manager") + ) + + val transactionDetailsClient: TransactionDetailsClient = VertxTransactionDetailsClient.create( + jsonRpcClientFactory = jsonRpcClientFactory, + endpoint = l1RpcEndpoint, + retryConfig = RequestRetryConfig( + backoffDelay = 1.seconds + ), + logger = LogManager.getLogger("linea.plugin.staterecover.clients.l1.transaction-details") + ) + + val app = StateRecoverApp( + vertx = vertx, + lineaContractClient = lineaContractClient, + ethLogsSearcher = ethLogsSearcher, + blobFetcher = blobScanClient, + elClient = elClient, + stateManagerClient = stateManagerClient, + transactionDetailsClient = transactionDetailsClient, + blockHeaderStaticFields = blockHeaderStaticFields, + config = appConfig + ) + + return app +} diff --git a/state-recover/besu-plugin/src/main/kotlin/linea/staterecover/plugin/BlockContextData.kt b/state-recover/besu-plugin/src/main/kotlin/linea/staterecover/plugin/BlockContextData.kt new file mode 100644 index 000000000..cb8501952 --- /dev/null +++ b/state-recover/besu-plugin/src/main/kotlin/linea/staterecover/plugin/BlockContextData.kt @@ -0,0 +1,13 @@ +package linea.staterecover.plugin + +import org.hyperledger.besu.plugin.data.BlockBody +import org.hyperledger.besu.plugin.data.BlockContext +import org.hyperledger.besu.plugin.data.BlockHeader + +data class BlockContextData( + private val blockHeader: BlockHeader, + private val blockBody: BlockBody +) : BlockContext { + override fun getBlockHeader(): BlockHeader = blockHeader + override fun getBlockBody(): BlockBody = blockBody +} diff --git a/state-recover/besu-plugin/src/main/kotlin/linea/staterecover/plugin/BlockImporter.kt b/state-recover/besu-plugin/src/main/kotlin/linea/staterecover/plugin/BlockImporter.kt new file mode 100644 index 000000000..1f8e39487 --- /dev/null +++ b/state-recover/besu-plugin/src/main/kotlin/linea/staterecover/plugin/BlockImporter.kt @@ -0,0 +1,122 @@ +package linea.staterecover.plugin + +import linea.staterecover.BlockFromL1RecoveredData +import net.consensys.encodeHex +import net.consensys.toBigInteger +import net.consensys.toULong +import org.apache.logging.log4j.LogManager +import org.apache.tuweni.bytes.Bytes32 +import org.hyperledger.besu.datatypes.AccountOverrideMap +import org.hyperledger.besu.datatypes.Address +import org.hyperledger.besu.datatypes.Hash +import org.hyperledger.besu.plugin.data.BlockContext +import org.hyperledger.besu.plugin.data.BlockHeader +import org.hyperledger.besu.plugin.data.BlockOverrides +import org.hyperledger.besu.plugin.data.PluginBlockSimulationResult +import org.hyperledger.besu.plugin.services.BlockSimulationService +import org.hyperledger.besu.plugin.services.BlockchainService +import org.hyperledger.besu.plugin.services.sync.SynchronizationService + +class BlockImporter( + private val blockchainService: BlockchainService, + private val simulatorService: BlockSimulationService, + private val synchronizationService: SynchronizationService +) { + private val log = LogManager.getLogger(BlockImporter::class.java) + private val chainId = blockchainService.chainId.orElseThrow().toULong() + + fun importBlock(block: BlockFromL1RecoveredData): PluginBlockSimulationResult { + val executedBlockResult = executeBlockWithTransactionsWithoutSignature(block) + return importBlock(BlockContextData(executedBlockResult.blockHeader, executedBlockResult.blockBody)) + } + + private fun executeBlockWithTransactionsWithoutSignature( + block: BlockFromL1RecoveredData + ): PluginBlockSimulationResult { + log.debug( + "simulating import block={} blockHash={}", + block.header.blockNumber, + block.header.blockHash.encodeHex() + ) + val transactions = TransactionMapper.mapToBesu( + block.transactions, + chainId + ) + val parentBlockNumber = block.header.blockNumber.toLong() - 1 + + val executedBlockResult = + simulatorService.simulate( + parentBlockNumber, + transactions, + createOverrides(block), + AccountOverrideMap() + ) + + log.debug( + " import simulation result: block={} blockHeader={}", + executedBlockResult.blockHeader.number, + executedBlockResult.blockHeader + ) + return executedBlockResult + } + + private fun createOverrides(blockFromBlob: BlockFromL1RecoveredData): BlockOverrides { + return BlockOverrides.builder() + .blockHash(Hash.wrap(Bytes32.wrap(blockFromBlob.header.blockHash))) + .feeRecipient(Address.fromHexString(blockFromBlob.header.coinbase.encodeHex())) + .blockNumber(blockFromBlob.header.blockNumber.toLong()) + .gasLimit(blockFromBlob.header.gasLimit.toLong()) + .timestamp(blockFromBlob.header.blockTimestamp.epochSeconds) + .difficulty(blockFromBlob.header.difficulty.toBigInteger()) + .mixHashOrPrevRandao(Hash.ZERO) + .build() + } + + fun importBlock(context: BlockContext): PluginBlockSimulationResult { + log.debug( + "calling simulateAndPersistWorldState block={} blockHeader={}", + context.blockHeader.number, + context.blockHeader + ) + val parentBlockNumber = context.blockHeader.number - 1 + val importedBlockResult = + simulatorService.simulateAndPersistWorldState( + parentBlockNumber, + context.blockBody.transactions, + createOverrides(context.blockHeader), + AccountOverrideMap() + ) + log.debug( + "simulateAndPersistWorldState result: block={} blockHeader={}", + context.blockHeader.number, + importedBlockResult.blockHeader + ) + storeAndSetHead(importedBlockResult) + return importedBlockResult + } + + private fun createOverrides(blockHeader: BlockHeader): BlockOverrides { + return BlockOverrides.builder() + .feeRecipient(blockHeader.coinbase) + .blockNumber(blockHeader.number) + .gasLimit(blockHeader.gasLimit) + .timestamp(blockHeader.timestamp) + .difficulty(blockHeader.difficulty.asBigInteger) + .stateRoot(blockHeader.stateRoot) + .mixHashOrPrevRandao(Hash.ZERO) + .build() + } + + private fun storeAndSetHead(block: PluginBlockSimulationResult) { + log.debug( + "storeAndSetHead result: blockHeader={}", + block.blockHeader + ) + blockchainService.storeBlock( + block.blockHeader, + block.blockBody, + block.receipts + ) + synchronizationService.setHeadUnsafe(block.blockHeader, block.blockBody) + } +} diff --git a/state-recover/besu-plugin/src/main/kotlin/linea/staterecover/plugin/LineaStateRecoverPlugin.kt b/state-recover/besu-plugin/src/main/kotlin/linea/staterecover/plugin/LineaStateRecoverPlugin.kt new file mode 100644 index 000000000..cbc3e7189 --- /dev/null +++ b/state-recover/besu-plugin/src/main/kotlin/linea/staterecover/plugin/LineaStateRecoverPlugin.kt @@ -0,0 +1,127 @@ +package linea.staterecover.plugin + +import io.micrometer.core.instrument.simple.SimpleMeterRegistry +import io.vertx.core.Vertx +import linea.staterecover.BlockHeaderStaticFields +import linea.staterecover.FileBasedRecoveryStatusPersistence +import linea.staterecover.RecoveryStatusPersistence +import linea.staterecover.StateRecoverApp +import linea.staterecover.clients.ExecutionLayerInProcessClient +import net.consensys.linea.async.get +import org.apache.logging.log4j.LogManager +import org.apache.logging.log4j.Logger +import org.hyperledger.besu.plugin.BesuPlugin +import org.hyperledger.besu.plugin.ServiceManager +import org.hyperledger.besu.plugin.services.BesuConfiguration +import org.hyperledger.besu.plugin.services.BesuEvents +import org.hyperledger.besu.plugin.services.BesuService +import org.hyperledger.besu.plugin.services.BlockSimulationService +import org.hyperledger.besu.plugin.services.BlockchainService +import org.hyperledger.besu.plugin.services.PicoCLIOptions +import org.hyperledger.besu.plugin.services.mining.MiningService +import org.hyperledger.besu.plugin.services.p2p.P2PService +import org.hyperledger.besu.plugin.services.sync.SynchronizationService + +fun ServiceManager.getServiceOrThrow(clazz: Class): T { + return this.getService(clazz) + .orElseThrow { IllegalStateException("${clazz.name} is not present in BesuContext") } +} + +open class LineaStateRecoverPlugin : BesuPlugin { + private val log: Logger = LogManager.getLogger(LineaStateRecoverPlugin::class.java) + private val vertx = Vertx.vertx() + private val cliOptions = PluginCliOptions() + private lateinit var serviceManager: ServiceManager + private lateinit var recoveryModeManager: RecoveryModeManager + private lateinit var recoveryStatusPersistence: RecoveryStatusPersistence + private lateinit var stateRecoverApp: StateRecoverApp + + override fun register(serviceManager: ServiceManager) { + log.debug("registering") + this.serviceManager = serviceManager + serviceManager + .getServiceOrThrow(PicoCLIOptions::class.java) + .addPicoCLIOptions(PluginCliOptions.cliOptionsPrefix, cliOptions) + log.debug("registered") + } + + override fun start() { + val config = cliOptions.getConfig() + val blockchainService = serviceManager.getServiceOrThrow(BlockchainService::class.java) + val blockHeaderStaticFields = BlockHeaderStaticFields( + coinbase = config.lineaSequencerBeneficiaryAddress.toArray(), + gasLimit = blockchainService.chainHeadHeader.gasLimit.toULong(), + difficulty = 2UL // Note, this will need to change once we move to QBFT + ) + this.recoveryStatusPersistence = FileBasedRecoveryStatusPersistence( + serviceManager.getServiceOrThrow(BesuConfiguration::class.java) + .dataPath + .resolve("plugin-staterecovery-status.json") + ) + log.info( + "starting: config={} blockHeaderStaticFields={} previousRecoveryStartBlockNumber={}", + config, + blockHeaderStaticFields, + this.recoveryStatusPersistence.getRecoveryStartBlockNumber() + ) + + val synchronizationService = serviceManager.getServiceOrThrow(SynchronizationService::class.java) + this.recoveryModeManager = RecoveryModeManager( + p2pService = serviceManager.getServiceOrThrow(P2PService::class.java), + miningService = serviceManager.getServiceOrThrow(MiningService::class.java), + recoveryStatePersistence = this.recoveryStatusPersistence, + synchronizationService = synchronizationService + ) + val simulatorService = serviceManager.getServiceOrThrow(BlockSimulationService::class.java) + val executionLayerClient = ExecutionLayerInProcessClient.create( + blockchainService = blockchainService, + stateRecoveryModeManager = this.recoveryModeManager, + stateRecoveryStatusPersistence = this.recoveryStatusPersistence, + simulatorService = simulatorService, + synchronizationService = synchronizationService + ) + + this.stateRecoverApp = run { + createAppAllInProcess( + vertx = vertx, + // Metrics won't be exposed. Needs proper integration with Besu Metrics, not priority now. + meterRegistry = SimpleMeterRegistry(), + elClient = executionLayerClient, + stateManagerClientEndpoint = config.shomeiEndpoint, + l1RpcEndpoint = config.l1RpcEndpoint, + blobScanEndpoint = config.blobscanEndpoint, + blockHeaderStaticFields = blockHeaderStaticFields, + appConfig = StateRecoverApp.Config( + smartContractAddress = config.l1SmartContractAddress.toString(), + l1LatestSearchBlock = net.consensys.linea.BlockParameter.Tag.LATEST, + overridingRecoveryStartBlockNumber = config.overridingRecoveryStartBlockNumber, + l1PollingInterval = config.l1PollingInterval + ) + ) + } + // add recoverty mode manager as listener to block added events + // so it stops P2P sync when it got target block + serviceManager + .getServiceOrThrow(BesuEvents::class.java) + .addBlockAddedListener(recoveryModeManager) + this.stateRecoverApp.start().get() + log.info( + "started: recoveryStartBlockNumber={}", + this.recoveryStatusPersistence.getRecoveryStartBlockNumber() + ) + } + + override fun afterExternalServicePostMainLoop() { + } + + override fun stop() { + stateRecoverApp.stop() + .whenComplete { _, throwable -> + vertx.close().get() + if (throwable != null) { + throw throwable + } + } + .get() + } +} diff --git a/state-recover/besu-plugin/src/main/kotlin/linea/staterecover/plugin/PluginOptions.kt b/state-recover/besu-plugin/src/main/kotlin/linea/staterecover/plugin/PluginOptions.kt new file mode 100644 index 000000000..745191467 --- /dev/null +++ b/state-recover/besu-plugin/src/main/kotlin/linea/staterecover/plugin/PluginOptions.kt @@ -0,0 +1,107 @@ +package linea.staterecover.plugin + +import org.hyperledger.besu.datatypes.Address +import picocli.CommandLine +import java.net.URI +import java.time.Duration +import kotlin.time.Duration.Companion.seconds +import kotlin.time.toKotlinDuration + +data class PluginConfig( + val lineaSequencerBeneficiaryAddress: Address, + val l1SmartContractAddress: Address, + val l1RpcEndpoint: URI, + val blobscanEndpoint: URI, + val shomeiEndpoint: URI, + val l1PollingInterval: kotlin.time.Duration, + val overridingRecoveryStartBlockNumber: ULong? = null +) { + init { + require(l1PollingInterval >= 1.seconds) { "Polling interval=$l1PollingInterval must be greater that 1s." } + } +} + +class PluginCliOptions { + companion object { + const val cliOptionsPrefix = "plugin-staterecovery" + } + + @CommandLine.Option( + names = ["--$cliOptionsPrefix-l1-smart-contract-address"], + description = ["L1 smart contract address"], + required = true, + converter = [AddressConverter::class], + defaultValue = "\${env:L1_ROLLUP_CONTRACT_ADDRESS}" + ) + lateinit var l1SmartContractAddress: Address + + @CommandLine.Option( + names = ["--$cliOptionsPrefix-linea-sequencer-beneficiary-address"], + description = ["Linea sequencer beneficiary address"], + required = true, + converter = [AddressConverter::class], + defaultValue = "\${env:LINEA_SEQUENCER_BENEFICIARY_ADDRESS}" + ) + lateinit var lineaSequencerBeneficiaryAddress: Address + + @CommandLine.Option( + names = ["--$cliOptionsPrefix-l1-rpc-endpoint"], + description = ["L1 RPC endpoint"], + required = true + ) + lateinit var l1RpcEndpoint: URI + + @CommandLine.Option( + names = ["--$cliOptionsPrefix-shomei-endpoint"], + description = ["shomei (state manager) endpoint"], + required = true + ) + lateinit var shomeiEndpoint: URI + + @CommandLine.Option( + names = ["--$cliOptionsPrefix-blobscan-endpoint"], + description = ["blobscan api endpoint"], + required = true + ) + lateinit var blobscanEndpoint: URI + + @CommandLine.Option( + names = ["--$cliOptionsPrefix-l1-polling-interval"], + description = ["L1 polling interval for new finalized blobs"], + required = false + ) + var l1PollingInterval: Duration = Duration.ofSeconds(12) + + @CommandLine.Option( + names = ["--$cliOptionsPrefix-overriding-recovery-start-block-number"], + description = [ + "Tries to force the recovery start block number to the given value. " + + "This is mean for testing purposes, not production. Must be greater than or equal to 1." + ], + required = false + ) + var overridingRecoveryStartBlockNumber: Long? = null + + fun getConfig(): PluginConfig { + require(overridingRecoveryStartBlockNumber == null || overridingRecoveryStartBlockNumber!! >= 1) { + "overridingRecoveryStartBlockNumber=$overridingRecoveryStartBlockNumber must be greater than or equal to 1" + } + return PluginConfig( + lineaSequencerBeneficiaryAddress = lineaSequencerBeneficiaryAddress, + l1SmartContractAddress = l1SmartContractAddress, + l1RpcEndpoint = l1RpcEndpoint, + blobscanEndpoint = blobscanEndpoint, + shomeiEndpoint = shomeiEndpoint, + l1PollingInterval = l1PollingInterval.toKotlinDuration(), + overridingRecoveryStartBlockNumber = overridingRecoveryStartBlockNumber?.toULong() + ) + } + + class AddressConverter : CommandLine.ITypeConverter
{ + override fun convert(value: String): Address { + return Address.fromHexString(value) ?: throw CommandLine.TypeConversionException( + "Invalid address: $value" + ) + } + } +} diff --git a/state-recover/besu-plugin/src/main/kotlin/linea/staterecover/plugin/RecoveryModeManager.kt b/state-recover/besu-plugin/src/main/kotlin/linea/staterecover/plugin/RecoveryModeManager.kt new file mode 100644 index 000000000..010445ba5 --- /dev/null +++ b/state-recover/besu-plugin/src/main/kotlin/linea/staterecover/plugin/RecoveryModeManager.kt @@ -0,0 +1,103 @@ +package linea.staterecover.plugin + +import linea.staterecover.RecoveryStatusPersistence +import org.apache.logging.log4j.LogManager +import org.apache.logging.log4j.Logger +import org.hyperledger.besu.plugin.data.AddedBlockContext +import org.hyperledger.besu.plugin.services.BesuEvents +import org.hyperledger.besu.plugin.services.mining.MiningService +import org.hyperledger.besu.plugin.services.p2p.P2PService +import org.hyperledger.besu.plugin.services.sync.SynchronizationService +import java.util.concurrent.atomic.AtomicBoolean + +class RecoveryModeManager( + private val synchronizationService: SynchronizationService, + private val p2pService: P2PService, + private val miningService: MiningService, + private val recoveryStatePersistence: RecoveryStatusPersistence +) : + BesuEvents.BlockAddedListener { + private val log: Logger = LogManager.getLogger(RecoveryModeManager::class.java.name) + private val triggered = AtomicBoolean(false) + private var currentBlockNumber: ULong = 0u + val targetBlockNumber: ULong? + get() = recoveryStatePersistence.getRecoveryStartBlockNumber() + + val headBlockNumber: ULong + get() = currentBlockNumber + + // Enum representing the states of recovery mode + private enum class RecoveryModeState { + NORMAL_MODE, + RECOVERY_MODE + } + + private var recoveryModeState = RecoveryModeState.NORMAL_MODE + + /** + * Called when a block is added. + * + * @param addedBlockContext the context of the added block + */ + @Synchronized + override fun onBlockAdded(addedBlockContext: AddedBlockContext) { + val blockNumber = addedBlockContext.blockHeader.number + currentBlockNumber = blockNumber.toULong() + if (!triggered.get() && hasReachedTargetBlock()) { + switchToRecoveryMode() + } + } + + private fun hasReachedTargetBlock(): Boolean { + return currentBlockNumber >= ((targetBlockNumber ?: ULong.MAX_VALUE) - 1u) + } + + /** + * Sets the target block number for switching to recovery mode. + * + * @param targetBlockNumber the target block number to set + */ + @Synchronized + fun setTargetBlockNumber(targetBlockNumber: ULong) { + check(!triggered.get()) { + "Cannot set target block number after recovery mode has been triggered" + } + val effectiveRecoveryStartBlockNumber = if (targetBlockNumber <= currentBlockNumber + 1u) { + log.warn( + "targetBlockNumber={} is less than or equal to headBlockNumber={}" + + " enabling recovery mode immediately at blockNumber={}", + targetBlockNumber, + currentBlockNumber, + currentBlockNumber + 1u + + ) + switchToRecoveryMode() + currentBlockNumber + 1u + } else { + targetBlockNumber + } + recoveryStatePersistence.saveRecoveryStartBlockNumber(effectiveRecoveryStartBlockNumber) + } + + /** Switches the node to recovery mode. */ + private fun switchToRecoveryMode() { + check(recoveryModeState == RecoveryModeState.NORMAL_MODE) { + "Cannot switch to recovery mode from state: $recoveryModeState" + } + log.warn("Stopping synchronization service") + synchronizationService.stop() + + log.warn("Stopping P2P discovery service") + p2pService.disableDiscovery() + + log.warn("Stopping mining service") + miningService.stop() + + log.info( + "Switched to state recovery mode at block={}", + headBlockNumber + ) + triggered.set(true) + recoveryModeState = RecoveryModeState.RECOVERY_MODE + } +} diff --git a/state-recover/besu-plugin/src/main/kotlin/linea/staterecover/plugin/TransactionMapper.kt b/state-recover/besu-plugin/src/main/kotlin/linea/staterecover/plugin/TransactionMapper.kt new file mode 100644 index 000000000..b609f2e3d --- /dev/null +++ b/state-recover/besu-plugin/src/main/kotlin/linea/staterecover/plugin/TransactionMapper.kt @@ -0,0 +1,75 @@ +package linea.staterecover.plugin + +import linea.staterecover.TransactionFromL1RecoveredData +import linea.staterecover.TransactionFromL1RecoveredData.AccessTuple +import net.consensys.encodeHex +import net.consensys.toBigInteger +import org.apache.tuweni.bytes.Bytes +import org.hyperledger.besu.crypto.SECPSignature +import org.hyperledger.besu.datatypes.AccessListEntry +import org.hyperledger.besu.datatypes.Address +import org.hyperledger.besu.datatypes.Wei +import org.hyperledger.besu.ethereum.core.Transaction +import java.math.BigInteger +import java.util.* + +fun ByteArray.toBesuAddress(): Address = Address.wrap(Bytes.wrap(this)) + +object TransactionMapper { + /** + * Constructs a Transaction object from the given Transaction recovered from L1 and chainId. + * + * @param transaction the parameters for the transaction + * @param chainId the chain ID for the transaction + * @return a constructed Transaction object + */ + fun mapToBesu( + transaction: TransactionFromL1RecoveredData, + chainId: ULong + ): Transaction { + val builder = Transaction.builder() + + builder + .sender(Address.fromHexString(transaction.from.encodeHex())) + .gasLimit(transaction.gasLimit.toLong()) + .value(Wei.of(transaction.value)) + .payload(Bytes.wrap()) + .chainId(chainId.toBigInteger()) + + transaction.data?.let { data -> builder.payload(Bytes.wrap(data)) } + transaction.to?.let { builder.to(Address.fromHexString(it.encodeHex())) } + transaction.gasPrice?.let { builder.gasPrice(Wei.of(it)) } + transaction.maxPriorityFeePerGas?.let { builder.maxPriorityFeePerGas(Wei.of(it)) } + transaction.maxFeePerGas?.let { builder.maxFeePerGas(Wei.of(it)) } + transaction.accessList?.let { builder.accessList(mapAccessListEntries(it)) } + builder.signature(SECPSignature(BigInteger.ZERO, BigInteger.ZERO, 0.toByte())) + return builder.build() + } + + private fun mapAccessListEntries( + accessList: List? + ): List? { + return accessList + ?.map { accessTupleParameter -> + AccessListEntry.createAccessListEntry( + accessTupleParameter.address.toBesuAddress(), + accessTupleParameter.storageKeys.map { it.encodeHex() } + ) + } + } + + /** + * Converts a list of TransactionParameters from an ImportBlockFromBlobParameter into a list of + * Transactions. + * + * @param importBlockFromBlobParameter the import block parameter containing transactions + * @param defaultChainId the default chain ID to use for transactions + * @return a list of constructed Transaction objects + */ + fun mapToBesu( + transactions: List, + defaultChainId: ULong + ): List { + return transactions.map { tx -> mapToBesu(tx, defaultChainId) } + } +} diff --git a/state-recover/besu-plugin/src/main/resources/META-INF/services/org.hyperledger.besu.plugin.BesuPlugin b/state-recover/besu-plugin/src/main/resources/META-INF/services/org.hyperledger.besu.plugin.BesuPlugin new file mode 100644 index 000000000..2b678e147 --- /dev/null +++ b/state-recover/besu-plugin/src/main/resources/META-INF/services/org.hyperledger.besu.plugin.BesuPlugin @@ -0,0 +1 @@ +linea.staterecover.plugin.LineaStateRecoverPlugin diff --git a/state-recover/clients/blobscan-client/build.gradle b/state-recover/clients/blobscan-client/build.gradle index caa6d00f8..f497bd97e 100644 --- a/state-recover/clients/blobscan-client/build.gradle +++ b/state-recover/clients/blobscan-client/build.gradle @@ -21,7 +21,7 @@ dependencies { implementation("io.vertx:vertx-web-client:${libs.versions.vertx}") testImplementation "com.github.tomakehurst:wiremock-jre8:${libs.versions.wiremock.get()}" - testImplementation "org.slf4j:slf4j-api:1.7.30" + testImplementation "org.slf4j:slf4j-api:${libs.versions.slf4j.get()}" testImplementation "org.apache.logging.log4j:log4j-slf4j-impl:${libs.versions.log4j}" testImplementation "org.apache.logging.log4j:log4j-core:${libs.versions.log4j}" } diff --git a/state-recover/clients/blobscan-client/src/main/kotlin/build/linea/staterecover/clients/blobscan/BlobScanClient.kt b/state-recover/clients/blobscan-client/src/main/kotlin/linea/staterecover/clients/blobscan/BlobScanClient.kt similarity index 82% rename from state-recover/clients/blobscan-client/src/main/kotlin/build/linea/staterecover/clients/blobscan/BlobScanClient.kt rename to state-recover/clients/blobscan-client/src/main/kotlin/linea/staterecover/clients/blobscan/BlobScanClient.kt index 0091c94b0..c881c623d 100644 --- a/state-recover/clients/blobscan-client/src/main/kotlin/build/linea/staterecover/clients/blobscan/BlobScanClient.kt +++ b/state-recover/clients/blobscan-client/src/main/kotlin/linea/staterecover/clients/blobscan/BlobScanClient.kt @@ -1,10 +1,10 @@ -package build.linea.staterecover.clients.blobscan +package linea.staterecover.clients.blobscan -import build.linea.staterecover.clients.BlobFetcher import io.vertx.core.Vertx import io.vertx.core.json.JsonObject import io.vertx.ext.web.client.WebClient import io.vertx.ext.web.client.WebClientOptions +import linea.staterecover.BlobFetcher import net.consensys.decodeHex import net.consensys.encodeHex import net.consensys.linea.jsonrpc.client.RequestRetryConfig @@ -41,14 +41,18 @@ class BlobScanClient( fun create( vertx: Vertx, endpoint: URI, - requestRetryConfig: RequestRetryConfig + requestRetryConfig: RequestRetryConfig, + logger: Logger = LogManager.getLogger(BlobScanClient::class.java), + responseLogMaxSize: UInt? = 1000u ): BlobScanClient { val restClient = VertxRestClient( vertx = vertx, webClient = WebClient.create(vertx, WebClientOptions().setDefaultsFrom(endpoint)), responseParser = { it.toJsonObject() }, retryableErrorCodes = setOf(429, 503, 504), - requestRetryConfig = requestRetryConfig + requestRetryConfig = requestRetryConfig, + log = logger, + responseLogMaxSize = responseLogMaxSize ) return BlobScanClient(restClient) } diff --git a/state-recover/clients/blobscan-client/src/main/kotlin/build/linea/staterecover/clients/blobscan/VertxRestClient.kt b/state-recover/clients/blobscan-client/src/main/kotlin/linea/staterecover/clients/blobscan/VertxRestClient.kt similarity index 52% rename from state-recover/clients/blobscan-client/src/main/kotlin/build/linea/staterecover/clients/blobscan/VertxRestClient.kt rename to state-recover/clients/blobscan-client/src/main/kotlin/linea/staterecover/clients/blobscan/VertxRestClient.kt index e3b581d0e..7a4f08041 100644 --- a/state-recover/clients/blobscan-client/src/main/kotlin/build/linea/staterecover/clients/blobscan/VertxRestClient.kt +++ b/state-recover/clients/blobscan-client/src/main/kotlin/linea/staterecover/clients/blobscan/VertxRestClient.kt @@ -1,4 +1,4 @@ -package build.linea.staterecover.clients.blobscan +package linea.staterecover.clients.blobscan import io.vertx.core.Vertx import io.vertx.core.buffer.Buffer @@ -8,6 +8,9 @@ import io.vertx.ext.web.client.WebClient import net.consensys.linea.async.AsyncRetryer import net.consensys.linea.async.toSafeFuture import net.consensys.linea.jsonrpc.client.RequestRetryConfig +import org.apache.logging.log4j.Level +import org.apache.logging.log4j.LogManager +import org.apache.logging.log4j.Logger import tech.pegasys.teku.infrastructure.async.SafeFuture // TODO: move to a common module @@ -33,7 +36,11 @@ class VertxRestClient( timeout = requestRetryConfig.timeout, vertx = vertx ), - private val requestHeaders: Map = mapOf("Accept" to "application/json") + private val requestHeaders: Map = mapOf("Accept" to "application/json"), + private val log: Logger = LogManager.getLogger(VertxRestClient::class.java), + private val requestResponseLogLevel: Level = Level.TRACE, + private val failuresLogLevel: Level = Level.DEBUG, + private val responseLogMaxSize: UInt? = null ) : RestClient { private fun makeRequestWithRetry( request: HttpRequest @@ -44,7 +51,10 @@ class VertxRestClient( response.statusCode() !in retryableErrorCodes } ) { + logRequest(request) request.send().toSafeFuture() + .thenPeek { response -> logResponse(request, response) } + .whenException { error -> logResponse(request = request, failureCause = error) } } } @@ -60,6 +70,46 @@ class VertxRestClient( } } + private fun logRequest(request: HttpRequest, level: Level = requestResponseLogLevel) { + log.log(level, "--> {} {}", request.method(), request.uri()) + } + + private fun logResponse( + request: HttpRequest, + response: HttpResponse? = null, + failureCause: Throwable? = null + ) { + val isError = response?.statusCode()?.let(::isNotSuccessStatusCode) ?: true + val logLevel = if (isError) failuresLogLevel else requestResponseLogLevel + if (isError && log.level != requestResponseLogLevel) { + // in case of error, log the request that originated the error + // to help replicate and debug later + logRequest(request, logLevel) + } + + val responseToLog = response?.bodyAsString()?.let { bodyStr -> + if (responseLogMaxSize != null) { + bodyStr.take(responseLogMaxSize.toInt()) + "..." + "(contentLength=${response.getHeader("Content-Length")})" + } else { + bodyStr + } + } + + log.log( + logLevel, + "<-- {} {} {} {} {}", + request.method(), + request.uri(), + response?.statusCode(), + responseToLog, + failureCause?.message ?: "" + ) + } + + private fun isNotSuccessStatusCode(statusCode: Int): Boolean { + return statusCode !in 200..299 + } + companion object { val DEFAULT_RETRY_HTTP_CODES = setOf(429, 500, 503, 504) } diff --git a/state-recover/clients/blobscan-client/src/test/kotlin/build/linea/staterecover/clients/blobscan/BlobScanClientTest.kt b/state-recover/clients/blobscan-client/src/test/kotlin/linea/staterecover/clients/blobscan/BlobScanClientTest.kt similarity index 99% rename from state-recover/clients/blobscan-client/src/test/kotlin/build/linea/staterecover/clients/blobscan/BlobScanClientTest.kt rename to state-recover/clients/blobscan-client/src/test/kotlin/linea/staterecover/clients/blobscan/BlobScanClientTest.kt index a8ab315fe..660aa8e2f 100644 --- a/state-recover/clients/blobscan-client/src/test/kotlin/build/linea/staterecover/clients/blobscan/BlobScanClientTest.kt +++ b/state-recover/clients/blobscan-client/src/test/kotlin/linea/staterecover/clients/blobscan/BlobScanClientTest.kt @@ -1,4 +1,4 @@ -package build.linea.staterecover.clients.blobscan +package linea.staterecover.clients.blobscan import com.github.tomakehurst.wiremock.WireMockServer import com.github.tomakehurst.wiremock.client.WireMock diff --git a/state-recover/clients/eth-api/build.gradle b/state-recover/clients/eth-api/build.gradle new file mode 100644 index 000000000..61ff45635 --- /dev/null +++ b/state-recover/clients/eth-api/build.gradle @@ -0,0 +1,11 @@ +plugins { + id 'net.consensys.zkevm.kotlin-library-conventions' +} + +dependencies { + implementation(project(':jvm-libs:generic:extensions:kotlin')) + implementation(project(':jvm-libs:linea:web3j-extensions')) + implementation(project(':jvm-libs:generic:serialization:jackson')) + api(project(':jvm-libs:generic:json-rpc')) + implementation(project(':state-recover:appcore:clients-interfaces')) +} diff --git a/state-recover/clients/eth-api/src/main/kotlin/linea/build/staterecover/clients/VertxTransactionDetailsClient.kt b/state-recover/clients/eth-api/src/main/kotlin/linea/build/staterecover/clients/VertxTransactionDetailsClient.kt new file mode 100644 index 000000000..4ec7cf22c --- /dev/null +++ b/state-recover/clients/eth-api/src/main/kotlin/linea/build/staterecover/clients/VertxTransactionDetailsClient.kt @@ -0,0 +1,50 @@ +package linea.build.staterecover.clients + +import com.fasterxml.jackson.databind.JsonNode +import com.github.michaelbull.result.Err +import linea.staterecover.TransactionDetailsClient +import net.consensys.decodeHex +import net.consensys.linea.jsonrpc.client.JsonRpcClientFactory +import net.consensys.linea.jsonrpc.client.JsonRpcV2Client +import net.consensys.linea.jsonrpc.client.RequestRetryConfig +import org.apache.logging.log4j.LogManager +import org.apache.logging.log4j.Logger +import tech.pegasys.teku.infrastructure.async.SafeFuture +import java.net.URI + +class VertxTransactionDetailsClient internal constructor( + private val jsonRpcClient: JsonRpcV2Client +) : TransactionDetailsClient { + + companion object { + fun create( + jsonRpcClientFactory: JsonRpcClientFactory, + endpoint: URI, + retryConfig: RequestRetryConfig, + logger: Logger = LogManager.getLogger(TransactionDetailsClient::class.java) + ): VertxTransactionDetailsClient { + return VertxTransactionDetailsClient( + jsonRpcClientFactory.createJsonRpcV2Client( + endpoints = listOf(endpoint), + retryConfig = retryConfig, + log = logger + ) + ) + } + } + + override fun getBlobVersionedHashesByTransactionHash(transactionHash: ByteArray): SafeFuture> { + return jsonRpcClient.makeRequest( + "eth_getTransactionByHash", + listOf(transactionHash), + shallRetryRequestPredicate = { it is Err }, + resultMapper = { + it as JsonNode + it.get("blobVersionedHashes") + ?.toList() + ?.map { it.asText().decodeHex() } + ?: emptyList() + } + ) + } +} diff --git a/state-recover/clients/execution-layer-json-rpc-client/src/main/kotlin/build/linea/staterecover/clients/el/ExecutionLayerJsonRpcClient.kt b/state-recover/clients/execution-layer-json-rpc-client/src/main/kotlin/build/linea/staterecover/clients/el/ExecutionLayerJsonRpcClient.kt index 813c0e2ed..c2792c413 100644 --- a/state-recover/clients/execution-layer-json-rpc-client/src/main/kotlin/build/linea/staterecover/clients/el/ExecutionLayerJsonRpcClient.kt +++ b/state-recover/clients/execution-layer-json-rpc-client/src/main/kotlin/build/linea/staterecover/clients/el/ExecutionLayerJsonRpcClient.kt @@ -1,17 +1,24 @@ package build.linea.staterecover.clients.el +import build.linea.s11n.jackson.InstantAsHexNumberDeserializer +import build.linea.s11n.jackson.InstantAsHexNumberSerializer import build.linea.s11n.jackson.ethApiObjectMapper -import build.linea.staterecover.BlockL1RecoveredData -import build.linea.staterecover.clients.ExecutionLayerClient +import com.fasterxml.jackson.annotation.JsonInclude import com.fasterxml.jackson.databind.JsonNode +import com.fasterxml.jackson.databind.module.SimpleModule +import kotlinx.datetime.Instant +import linea.staterecover.BlockFromL1RecoveredData +import linea.staterecover.ExecutionLayerClient +import linea.staterecover.StateRecoveryStatus import net.consensys.decodeHex -import net.consensys.encodeHex import net.consensys.fromHexString import net.consensys.linea.BlockNumberAndHash import net.consensys.linea.BlockParameter import net.consensys.linea.jsonrpc.client.JsonRpcClientFactory import net.consensys.linea.jsonrpc.client.JsonRpcV2Client import net.consensys.linea.jsonrpc.client.RequestRetryConfig +import org.apache.logging.log4j.LogManager +import org.apache.logging.log4j.Logger import tech.pegasys.teku.infrastructure.async.SafeFuture import java.net.URI @@ -33,38 +40,65 @@ class ExecutionLayerJsonRpcClient internal constructor( } } - override fun lineaEngineImportBlocksFromBlob(blocks: List): SafeFuture { + override fun lineaEngineImportBlocksFromBlob(blocks: List): SafeFuture { return rpcClient .makeRequest( - method = "linea_engine_importBlocksFromBlob", + method = "linea_importBlocksFromBlob", params = blocks, resultMapper = { Unit } ) } - override fun lineaEngineForkChoiceUpdated( - headBlockHash: ByteArray, - finalizedBlockHash: ByteArray - ): SafeFuture { + override fun lineaGetStateRecoveryStatus(): SafeFuture { return rpcClient .makeRequest( - method = "linea_engine_importForkChoiceUpdated", - params = listOf(headBlockHash, finalizedBlockHash).map { it.encodeHex() }, - resultMapper = { Unit } + method = "linea_getStateRecoveryStatus", + params = emptyList(), + resultMapper = ::stateRecoveryStatusFromJsonNode + ) + } + + override fun lineaEnableStateRecovery(stateRecoverStartBlockNumber: ULong): SafeFuture { + return rpcClient + .makeRequest( + method = "linea_enableStateRecovery", + params = listOf(stateRecoverStartBlockNumber), + resultMapper = ::stateRecoveryStatusFromJsonNode ) } companion object { + fun stateRecoveryStatusFromJsonNode(result: Any?): StateRecoveryStatus { + @Suppress("UNCHECKED_CAST") + result as JsonNode + return StateRecoveryStatus( + headBlockNumber = ULong.fromHexString(result.get("headBlockNumber").asText()), + stateRecoverStartBlockNumber = result.get("recoveryStartBlockNumber") + ?.let { if (it.isNull) null else ULong.fromHexString(it.asText()) } + ) + } + fun create( rpcClientFactory: JsonRpcClientFactory, endpoint: URI, - requestRetryConfig: RequestRetryConfig + requestRetryConfig: RequestRetryConfig, + logger: Logger = LogManager.getLogger(ExecutionLayerJsonRpcClient::class.java) ): ExecutionLayerClient { + val objectManager = ethApiObjectMapper + .copy() + .registerModules( + SimpleModule().apply { + this.addSerializer(Instant::class.java, InstantAsHexNumberSerializer) + this.addDeserializer(Instant::class.java, InstantAsHexNumberDeserializer) + } + ) + .setSerializationInclusion(JsonInclude.Include.NON_NULL) return ExecutionLayerJsonRpcClient( rpcClient = rpcClientFactory.createJsonRpcV2Client( endpoints = listOf(endpoint), retryConfig = requestRetryConfig, - requestObjectMapper = ethApiObjectMapper + requestObjectMapper = objectManager, + log = logger ) ) } diff --git a/state-recover/clients/execution-layer-json-rpc-client/src/test/kotlin/build/linea/staterecover/clients/el/ExecutionLayerJsonRpcClientTest.kt b/state-recover/clients/execution-layer-json-rpc-client/src/test/kotlin/build/linea/staterecover/clients/el/ExecutionLayerJsonRpcClientTest.kt index 9b4ddad4d..f59bd27c1 100644 --- a/state-recover/clients/execution-layer-json-rpc-client/src/test/kotlin/build/linea/staterecover/clients/el/ExecutionLayerJsonRpcClientTest.kt +++ b/state-recover/clients/execution-layer-json-rpc-client/src/test/kotlin/build/linea/staterecover/clients/el/ExecutionLayerJsonRpcClientTest.kt @@ -1,9 +1,5 @@ package build.linea.staterecover.clients.el -import build.linea.staterecover.BlockExtraData -import build.linea.staterecover.BlockL1RecoveredData -import build.linea.staterecover.TransactionL1RecoveredData -import build.linea.staterecover.clients.ExecutionLayerClient import com.github.tomakehurst.wiremock.WireMockServer import com.github.tomakehurst.wiremock.client.WireMock.containing import com.github.tomakehurst.wiremock.client.WireMock.post @@ -12,6 +8,11 @@ import com.github.tomakehurst.wiremock.core.WireMockConfiguration import io.micrometer.core.instrument.simple.SimpleMeterRegistry import io.vertx.junit5.VertxExtension import kotlinx.datetime.Instant +import linea.staterecover.BlockFromL1RecoveredData +import linea.staterecover.BlockHeaderFromL1RecoveredData +import linea.staterecover.ExecutionLayerClient +import linea.staterecover.StateRecoveryStatus +import linea.staterecover.TransactionFromL1RecoveredData import net.consensys.decodeHex import net.consensys.linea.BlockNumberAndHash import net.consensys.linea.BlockParameter @@ -108,7 +109,7 @@ class ExecutionLayerJsonRpcClientTest { } @Test - fun `lineaEngineImportBlocksFromBlob`() { + fun `lineaImportBlocksFromBlob`() { replyRequestWith( 200, """ @@ -119,18 +120,21 @@ class ExecutionLayerJsonRpcClientTest { } """.trimIndent() ) - val block1 = BlockL1RecoveredData( - blockNumber = 0xa001u, - blockHash = "0xa011".decodeHex(), - coinbase = "0xa022".decodeHex(), - blockTimestamp = Instant.parse("2024-07-01T11:22:33Z"), - gasLimit = 0x1c9c380u, - difficulty = 0u, - extraData = BlockExtraData(beneficiary = "0x6265617665726275696c642e6f7267".decodeHex()), + + val block1 = BlockFromL1RecoveredData( + header = BlockHeaderFromL1RecoveredData( + blockNumber = 0xa001u, + blockHash = "0xa011".decodeHex(), + coinbase = "0x6265617665726275696c642e6f7267".decodeHex(), + blockTimestamp = Instant.fromEpochSeconds(1719828000), // 2024-07-01T11:00:00Z UTC + gasLimit = 0x1c9c380u, + difficulty = 0u + ), transactions = listOf( - TransactionL1RecoveredData( + TransactionFromL1RecoveredData( type = 0x01u, nonce = 0xb010u, + gasPrice = null, maxPriorityFeePerGas = "b010011".toBigInteger(16), maxFeePerGas = "b0100ff".toBigInteger(16), gasLimit = 0xb0100aau, @@ -139,11 +143,24 @@ class ExecutionLayerJsonRpcClientTest { value = 123.toBigInteger(), data = "0xb013".decodeHex(), accessList = listOf( - TransactionL1RecoveredData.AccessTuple( + TransactionFromL1RecoveredData.AccessTuple( address = "0xb014".decodeHex(), storageKeys = listOf("0xb015".decodeHex(), "0xb015".decodeHex()) ) ) + ), + TransactionFromL1RecoveredData( + type = 0x0u, + nonce = 0xb020u, + gasPrice = "b0100ff".toBigInteger(16), + maxPriorityFeePerGas = null, + maxFeePerGas = null, + gasLimit = 0xb0100aau, + from = "0xb011".decodeHex(), + to = "0xb012".decodeHex(), + value = 123.toBigInteger(), + data = null, + accessList = null ) ) ) @@ -156,16 +173,15 @@ class ExecutionLayerJsonRpcClientTest { """{ "jsonrpc":"2.0", "id":"${'$'}{json-unit.any-number}", - "method":"linea_engine_importBlocksFromBlob", + "method":"linea_importBlocksFromBlob", "params":[{ - "blockNumber": "0xa001", - "blockHash": "0xa011", - "coinbase": "0xa022", - "blockTimestamp": "2024-07-01T11:22:33Z", - "gasLimit": "0x1c9c380", - "difficulty": "0x0", - "extraData": { - "beneficiary": "0x6265617665726275696c642e6f7267" + "header": { + "blockNumber": "0xa001", + "blockHash": "0xa011", + "coinbase": "0x6265617665726275696c642e6f7267", + "blockTimestamp": "0x66827e20", + "gasLimit": "0x1c9c380", + "difficulty": "0x0" }, "transactions": [{ "type": "0x01", @@ -186,12 +202,101 @@ class ExecutionLayerJsonRpcClientTest { ] } ] + }, { + "type": "0x00", + "nonce": "0xb020", + "gasPrice": "0xb0100ff", + "gasLimit": "0xb0100aa", + "from": "0xb011", + "to": "0xb012", + "value": "0x7b" }] }] }""" ) } + @Test + fun `lineaGetStateRecoveryStatus_enabledStatus`() { + replyRequestWith( + 200, + """{"jsonrpc": "2.0", "id": 1, "result": { "recoveryStartBlockNumber": "0x5", "headBlockNumber": "0xa"}}""" + ) + + assertThat(client.lineaGetStateRecoveryStatus().get()) + .isEqualTo( + StateRecoveryStatus( + headBlockNumber = 0xa.toULong(), + stateRecoverStartBlockNumber = 0x5.toULong() + ) + ) + + val requestJson = wiremock.serveEvents.serveEvents.first().request.bodyAsString + assertThatJson(requestJson) + .isEqualTo( + """{ + "jsonrpc":"2.0", + "id":"${'$'}{json-unit.any-number}", + "method":"linea_getStateRecoveryStatus", + "params":[] + }""" + ) + } + + @Test + fun `lineaGetStateRecoveryStatus_disabledStatus`() { + replyRequestWith( + 200, + """{"jsonrpc": "2.0", "id": 1, "result": { "recoveryStartBlockNumber": null, "headBlockNumber": "0xa"}}""" + ) + + assertThat(client.lineaGetStateRecoveryStatus().get()) + .isEqualTo( + StateRecoveryStatus( + headBlockNumber = 0xa.toULong(), + stateRecoverStartBlockNumber = null + ) + ) + + val requestJson = wiremock.serveEvents.serveEvents.first().request.bodyAsString + assertThatJson(requestJson) + .isEqualTo( + """{ + "jsonrpc":"2.0", + "id":"${'$'}{json-unit.any-number}", + "method":"linea_getStateRecoveryStatus", + "params":[] + }""" + ) + } + + @Test + fun `lineaEnableStateRecoveryStatus`() { + replyRequestWith( + 200, + """{"jsonrpc": "2.0", "id": 1, "result": { "recoveryStartBlockNumber": "0xff", "headBlockNumber": "0xa"}}""" + ) + + assertThat(client.lineaEnableStateRecovery(stateRecoverStartBlockNumber = 5UL).get()) + .isEqualTo( + StateRecoveryStatus( + headBlockNumber = 0xa.toULong(), + stateRecoverStartBlockNumber = 0xff.toULong() + ) + ) + + val requestJson = wiremock.serveEvents.serveEvents.first().request.bodyAsString + assertThatJson(requestJson) + .isEqualTo( + """{ + "jsonrpc":"2.0", + "id":"${'$'}{json-unit.any-number}", + "method":"linea_enableStateRecovery", + "params":["0x5"] + }""" + ) + } + private fun replyRequestWith(statusCode: Int, body: String?) { wiremock.stubFor( post("/") diff --git a/state-recover/test-cases/build.gradle b/state-recover/test-cases/build.gradle new file mode 100644 index 000000000..658a2cca5 --- /dev/null +++ b/state-recover/test-cases/build.gradle @@ -0,0 +1,82 @@ +import org.gradle.api.tasks.testing.logging.TestExceptionFormat +import org.gradle.api.tasks.testing.logging.TestLogEvent + +plugins { + id 'net.consensys.zkevm.kotlin-library-conventions' +} + +group = 'build.linea.staterecover' + +dependencies { + implementation("io.vertx:vertx-core:${libs.versions.vertx.get()}") + api(project(':jvm-libs:generic:extensions:kotlin')) + api(project(':jvm-libs:linea:core:domain-models')) + api(project(':jvm-libs:linea:core:long-running-service')) + api(project(':jvm-libs:linea:clients:interfaces')) + api(project(':jvm-libs:linea:clients:linea-l1-contract-client')) + api(project(':jvm-libs:linea:clients:linea-state-manager')) + api(project(':jvm-libs:linea:blob-decompressor')) + api(project(':state-recover:appcore:clients-interfaces')) + api(project(':state-recover:appcore:domain-models')) + api(project(':state-recover:appcore:logic')) + + implementation project(':jvm-libs:linea:besu-libs') + implementation(testFixtures(project(':jvm-libs:generic:json-rpc'))) + implementation(project(':state-recover:clients:eth-api')) + implementation(project(':state-recover:clients:blobscan-client')) + implementation(project(':state-recover:clients:execution-layer-json-rpc-client')) + implementation(project(':coordinator:clients:smart-contract-client')) + implementation(project(':jvm-libs:linea:linea-contracts:l1-rollup')) + implementation('build.linea:l1-rollup-contract-client:6.0.0') + implementation(project(':coordinator:core')) + implementation(project(":coordinator:ethereum:test-utils")) + implementation(project(":jvm-libs:linea:testing:l1-blob-and-proof-submission")) + implementation(testFixtures(project(":jvm-libs:linea:blob-compressor"))) + testImplementation("io.vertx:vertx-junit5") +} + +sourceSets { + integrationTest { + kotlin { + compileClasspath += sourceSets.main.output + sourceSets.main.compileClasspath + sourceSets.test.compileClasspath + runtimeClasspath += sourceSets.main.output + sourceSets.main.runtimeClasspath + sourceSets.test.runtimeClasspath + } + compileClasspath += sourceSets.main.output + sourceSets.main.compileClasspath + sourceSets.test.compileClasspath + runtimeClasspath += sourceSets.main.output + sourceSets.main.runtimeClasspath + sourceSets.test.runtimeClasspath + } +} + +test { + systemProperty "vertx.parameter.filename", project.projectDir.toPath() + .resolve("src/test/resources/vertx-options.json") + .toAbsolutePath().toString() +} + +task integrationTest(type: Test) { test -> + systemProperty "vertx.parameter.filename", project.projectDir.toPath() + .resolve("src/test/resources/vertx-options.json") + .toAbsolutePath().toString() + + description = "Runs integration tests." + group = "verification" + useJUnitPlatform() + + classpath = sourceSets.integrationTest.runtimeClasspath + testClassesDirs = sourceSets.integrationTest.output.classesDirs + + // dependsOn(":localStackForStateRecoverComposeUp") + + testLogging { + events TestLogEvent.FAILED, + TestLogEvent.SKIPPED, + TestLogEvent.STANDARD_ERROR, + TestLogEvent.STARTED, + TestLogEvent.PASSED + exceptionFormat TestExceptionFormat.FULL + showCauses true + showExceptions true + showStackTraces true + // set showStandardStreams if you need to see test logs + showStandardStreams true + } +} diff --git a/state-recover/clients/smartcontract/src/integrationTest/kotlin/linea/build/staterecover/clients/smartcontract/LineaSubmissionEventsClientIntTest.kt b/state-recover/test-cases/src/integrationTest/kotlin/linea/staterecover/LineaSubmissionEventsClientIntTest.kt similarity index 88% rename from state-recover/clients/smartcontract/src/integrationTest/kotlin/linea/build/staterecover/clients/smartcontract/LineaSubmissionEventsClientIntTest.kt rename to state-recover/test-cases/src/integrationTest/kotlin/linea/staterecover/LineaSubmissionEventsClientIntTest.kt index 745032e07..41e1af26d 100644 --- a/state-recover/clients/smartcontract/src/integrationTest/kotlin/linea/build/staterecover/clients/smartcontract/LineaSubmissionEventsClientIntTest.kt +++ b/state-recover/test-cases/src/integrationTest/kotlin/linea/staterecover/LineaSubmissionEventsClientIntTest.kt @@ -1,15 +1,13 @@ -package linea.build.staterecover.clients.smartcontract +package linea.staterecover import build.linea.contract.l1.LineaContractVersion -import build.linea.staterecover.clients.DataFinalizedV3 -import build.linea.staterecover.clients.DataSubmittedV3 -import build.linea.staterecover.clients.LineaRollupSubmissionEventsClient import io.vertx.core.Vertx import io.vertx.junit5.Timeout import io.vertx.junit5.VertxExtension import io.vertx.junit5.VertxTestContext +import linea.domain.RetryConfig +import linea.web3j.Web3JLogsSearcher import net.consensys.linea.BlockParameter -import net.consensys.linea.contract.Web3JLogsClient import net.consensys.linea.testing.submission.AggregationAndBlobs import net.consensys.linea.testing.submission.loadBlobsAndAggregationsSortedAndGrouped import net.consensys.linea.testing.submission.submitBlobsAndAggregations @@ -24,7 +22,8 @@ import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith import java.util.concurrent.TimeUnit -import kotlin.time.Duration.Companion.seconds +import kotlin.time.Duration.Companion.milliseconds +import kotlin.time.Duration.Companion.minutes import kotlin.time.toJavaDuration @ExtendWith(VertxExtension::class) @@ -57,18 +56,19 @@ class LineaSubmissionEventsClientIntTest { requestResponseLogLevel = Level.INFO, failuresLogLevel = Level.WARN ) - submissionEventsFetcher = LineaSubmissionEventsClientWeb3jIpml( - logsClient = Web3JLogsClient( + submissionEventsFetcher = LineaSubmissionEventsClientImpl( + logsSearcher = Web3JLogsSearcher( vertx = vertx, web3jClient = eventsFetcherWeb3jClient, - config = Web3JLogsClient.Config( - timeout = 30.seconds, - backoffDelay = 1.seconds, - lookBackRange = 100 + config = Web3JLogsSearcher.Config( + backoffDelay = 1.milliseconds, + requestRetryConfig = RetryConfig.noRetries ) ), smartContractAddress = rollupDeploymentResult.contractAddress, - mostRecentBlockTag = BlockParameter.Tag.LATEST + l1EarliestSearchBlock = BlockParameter.Tag.EARLIEST, + l1LatestSearchBlock = BlockParameter.Tag.LATEST, + logsBlockChunkSize = 100 ) } @@ -96,7 +96,7 @@ class LineaSubmissionEventsClientIntTest { // wait for all finalizations Txs to be mined Web3jClientManager.l1Client.waitForTxReceipt( txHash = submissionTxHashes.aggregationTxHashes.last(), - timeout = 20.seconds + timeout = 2.minutes ) val expectedSubmissionEventsToFind: List>> = @@ -110,7 +110,7 @@ class LineaSubmissionEventsClientIntTest { l2StartBlockNumberInclusive = expectedFinalizationEvent.startBlockNumber ) ) - .succeedsWithin(30.seconds.toJavaDuration()) + .succeedsWithin(1.minutes.toJavaDuration()) .extracting { submissionEvents -> val dataFinalizedEvent = submissionEvents?.dataFinalizedEvent?.event val dataSubmittedEvents = submissionEvents?.dataSubmittedEvents?.map { it.event } diff --git a/state-recover/test-cases/src/integrationTest/kotlin/linea/staterecover/StateRecoverAppIntTest.kt b/state-recover/test-cases/src/integrationTest/kotlin/linea/staterecover/StateRecoverAppIntTest.kt new file mode 100644 index 000000000..26d225be8 --- /dev/null +++ b/state-recover/test-cases/src/integrationTest/kotlin/linea/staterecover/StateRecoverAppIntTest.kt @@ -0,0 +1,207 @@ +package linea.staterecover + +import build.linea.clients.StateManagerClientV1 +import build.linea.clients.StateManagerV1JsonRpcClient +import build.linea.contract.l1.LineaContractVersion +import build.linea.contract.l1.LineaRollupSmartContractClientReadOnly +import build.linea.contract.l1.Web3JLineaRollupSmartContractClientReadOnly +import build.linea.staterecover.clients.el.ExecutionLayerJsonRpcClient +import io.micrometer.core.instrument.simple.SimpleMeterRegistry +import io.vertx.core.Vertx +import io.vertx.junit5.VertxExtension +import linea.build.staterecover.clients.VertxTransactionDetailsClient +import linea.domain.RetryConfig +import linea.log4j.configureLoggers +import linea.staterecover.clients.blobscan.BlobScanClient +import linea.web3j.Web3JLogsSearcher +import net.consensys.linea.BlockParameter +import net.consensys.linea.jsonrpc.client.RequestRetryConfig +import net.consensys.linea.jsonrpc.client.VertxHttpJsonRpcClientFactory +import net.consensys.linea.testing.submission.AggregationAndBlobs +import net.consensys.linea.testing.submission.loadBlobsAndAggregationsSortedAndGrouped +import net.consensys.linea.testing.submission.submitBlobsAndAggregations +import net.consensys.zkevm.coordinator.clients.smartcontract.LineaRollupSmartContractClient +import net.consensys.zkevm.ethereum.ContractsManager +import net.consensys.zkevm.ethereum.Web3jClientManager +import net.consensys.zkevm.ethereum.waitForTxReceipt +import org.apache.logging.log4j.Level +import org.apache.logging.log4j.LogManager +import org.assertj.core.api.Assertions.assertThat +import org.awaitility.Awaitility.await +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import java.net.URI +import kotlin.time.Duration.Companion.milliseconds +import kotlin.time.Duration.Companion.minutes +import kotlin.time.Duration.Companion.seconds +import kotlin.time.toJavaDuration + +@ExtendWith(VertxExtension::class) +class StateRecoverAppIntTest { + private val log = LogManager.getLogger("test.case.StateRecoverAppIntTest") + private lateinit var stateRecoverApp: StateRecoverApp + private lateinit var aggregationsAndBlobs: List + private lateinit var executionLayerClient: ExecutionLayerClient + private lateinit var stateManagerClient: StateManagerClientV1 + private lateinit var transactionDetailsClient: TransactionDetailsClient + private lateinit var lineaContractClient: LineaRollupSmartContractClientReadOnly + + private lateinit var contractClientForSubmissions: LineaRollupSmartContractClient + + private val testDataDir = "testdata/coordinator/prover/v3/" + + private val l1RpcUrl = "http://localhost:8445" + private val blobScanUrl = "http://localhost:4001" + private val executionClientUrl = "http://localhost:9145" + private val stateManagerUrl = "http://localhost:8890" + + @BeforeEach + fun beforeEach(vertx: Vertx) { + val jsonRpcFactory = VertxHttpJsonRpcClientFactory(vertx = vertx, meterRegistry = SimpleMeterRegistry()) + aggregationsAndBlobs = loadBlobsAndAggregationsSortedAndGrouped( + blobsResponsesDir = "$testDataDir/compression/responses", + aggregationsResponsesDir = "$testDataDir/aggregation/responses" + ) + executionLayerClient = ExecutionLayerJsonRpcClient.create( + rpcClientFactory = jsonRpcFactory, + endpoint = URI(executionClientUrl), + requestRetryConfig = RequestRetryConfig( + backoffDelay = 10.milliseconds, + timeout = 2.seconds, + maxRetries = 4u, + failuresWarningThreshold = 1U + ), + logger = LogManager.getLogger("test.clients.l1.executionlayer") + ) + stateManagerClient = StateManagerV1JsonRpcClient.create( + rpcClientFactory = jsonRpcFactory, + endpoints = listOf(URI(stateManagerUrl)), + maxInflightRequestsPerClient = 1U, + requestRetry = RequestRetryConfig( + backoffDelay = 10.milliseconds, + timeout = 2.seconds + ), + zkStateManagerVersion = "2.3.0", + logger = LogManager.getLogger("test.clients.l1.state-manager") + ) + transactionDetailsClient = VertxTransactionDetailsClient.create( + jsonRpcClientFactory = jsonRpcFactory, + endpoint = URI(l1RpcUrl), + retryConfig = RequestRetryConfig( + backoffDelay = 10.milliseconds, + timeout = 2.seconds + ), + logger = LogManager.getLogger("test.clients.l1.transaction-details") + ) + + val rollupDeploymentResult = ContractsManager.get() + .deployLineaRollup(numberOfOperators = 2, contractVersion = LineaContractVersion.V6).get() + + lineaContractClient = Web3JLineaRollupSmartContractClientReadOnly( + web3j = Web3jClientManager.buildL1Client( + log = LogManager.getLogger("test.clients.l1.linea-contract"), + requestResponseLogLevel = Level.INFO, + failuresLogLevel = Level.WARN + ), + contractAddress = rollupDeploymentResult.contractAddress + ) + val logsSearcher = run { + val log = LogManager.getLogger("test.clients.l1.events-fetcher") + Web3JLogsSearcher( + vertx = vertx, + web3jClient = Web3jClientManager.buildL1Client( + log = log, + requestResponseLogLevel = Level.TRACE, + failuresLogLevel = Level.WARN + ), + Web3JLogsSearcher.Config( + backoffDelay = 1.milliseconds, + requestRetryConfig = RetryConfig.noRetries + ), + log = log + ) + } + + contractClientForSubmissions = rollupDeploymentResult.rollupOperatorClient + val blobScanClient = BlobScanClient.create( + vertx = vertx, + endpoint = URI(blobScanUrl), + requestRetryConfig = RequestRetryConfig( + backoffDelay = 10.milliseconds, + timeout = 2.seconds + ), + logger = LogManager.getLogger("test.clients.l1.blobscan") + ) + + configureLoggers( + rootLevel = Level.INFO, + "test.clients.l1.executionlayer" to Level.INFO, + "test.clients.l1.web3j-default" to Level.INFO, + "test.clients.l1.state-manager" to Level.INFO, + "test.clients.l1.transaction-details" to Level.INFO, + "test.clients.l1.linea-contract" to Level.INFO, + "test.clients.l1.events-fetcher" to Level.INFO, + "test.clients.l1.blobscan" to Level.INFO, + "net.consensys.linea.contract.l1" to Level.INFO + ) + + stateRecoverApp = StateRecoverApp( + vertx = vertx, + elClient = executionLayerClient, + blobFetcher = blobScanClient, + ethLogsSearcher = logsSearcher, + stateManagerClient = stateManagerClient, + transactionDetailsClient = transactionDetailsClient, + blockHeaderStaticFields = BlockHeaderStaticFields.localDev, + lineaContractClient = lineaContractClient, + config = StateRecoverApp.Config( + l1LatestSearchBlock = BlockParameter.Tag.LATEST, + l1PollingInterval = 5.seconds, + executionClientPollingInterval = 1.seconds, + smartContractAddress = lineaContractClient.getAddress(), + logsBlockChunkSize = 100_000u + ) + ) + } + + @Test + fun `state recovery from genesis`() { + stateRecoverApp.start().get() + + val submissionTxHashes = submitBlobsAndAggregations( + contractClient = contractClientForSubmissions, + aggregationsAndBlobs = aggregationsAndBlobs, + blobChunksSize = 6 + ) + + val lastAggregation = aggregationsAndBlobs.findLast { it.aggregation != null }!!.aggregation!! + log.info("Waiting for finalization={} tx to be executed on L1", lastAggregation.intervalString()) + Web3jClientManager.l1Client.waitForTxReceipt( + txHash = submissionTxHashes.aggregationTxHashes.last(), + timeout = 2.minutes + ).also { + assertThat(it.status).isEqualTo("0x1") + .withFailMessage( + "finalization=${lastAggregation.intervalString()} tx failed! " + + "replay data is not consistent with L1 state, potential cause: " + + "data has L1 -> L2 anchoring messages and misses L1 Rolling Hash: tx=$it" + ) + log.info("finalization={} executed on l1 tx={}", lastAggregation.intervalString(), it) + } + await() + .atMost(4.minutes.toJavaDuration()) + .untilAsserted { + assertThat(stateRecoverApp.lastSuccessfullyRecoveredFinalization?.event?.endBlockNumber) + .isEqualTo(lastAggregation.endBlockNumber) + } + + assertThat(executionLayerClient.lineaGetStateRecoveryStatus().get()) + .isEqualTo( + StateRecoveryStatus( + headBlockNumber = lastAggregation.endBlockNumber, + stateRecoverStartBlockNumber = 1UL + ) + ) + } +} diff --git a/state-recover/test-cases/src/integrationTest/kotlin/linea/staterecover/StateRecoverAppWithFakeExecutionClientIntTest.kt b/state-recover/test-cases/src/integrationTest/kotlin/linea/staterecover/StateRecoverAppWithFakeExecutionClientIntTest.kt new file mode 100644 index 000000000..bffa35618 --- /dev/null +++ b/state-recover/test-cases/src/integrationTest/kotlin/linea/staterecover/StateRecoverAppWithFakeExecutionClientIntTest.kt @@ -0,0 +1,298 @@ +package linea.staterecover + +import build.linea.contract.l1.LineaContractVersion +import build.linea.contract.l1.LineaRollupSmartContractClientReadOnly +import build.linea.contract.l1.Web3JLineaRollupSmartContractClientReadOnly +import io.micrometer.core.instrument.simple.SimpleMeterRegistry +import io.vertx.core.Vertx +import io.vertx.junit5.VertxExtension +import linea.build.staterecover.clients.VertxTransactionDetailsClient +import linea.domain.RetryConfig +import linea.log4j.configureLoggers +import linea.staterecover.clients.blobscan.BlobScanClient +import linea.staterecover.test.FakeExecutionLayerClient +import linea.staterecover.test.FakeStateManagerClient +import linea.staterecover.test.FakeStateManagerClientBasedOnBlobsRecords +import linea.web3j.Web3JLogsSearcher +import net.consensys.linea.BlockNumberAndHash +import net.consensys.linea.BlockParameter +import net.consensys.linea.jsonrpc.client.RequestRetryConfig +import net.consensys.linea.jsonrpc.client.VertxHttpJsonRpcClientFactory +import net.consensys.linea.testing.submission.AggregationAndBlobs +import net.consensys.linea.testing.submission.loadBlobsAndAggregationsSortedAndGrouped +import net.consensys.linea.testing.submission.submitBlobsAndAggregations +import net.consensys.zkevm.coordinator.clients.smartcontract.LineaRollupSmartContractClient +import net.consensys.zkevm.ethereum.ContractsManager +import net.consensys.zkevm.ethereum.Web3jClientManager +import net.consensys.zkevm.ethereum.waitForTxReceipt +import org.apache.logging.log4j.Level +import org.apache.logging.log4j.LogManager +import org.assertj.core.api.Assertions.assertThat +import org.awaitility.Awaitility.await +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import java.net.URI +import kotlin.time.Duration.Companion.milliseconds +import kotlin.time.Duration.Companion.minutes +import kotlin.time.Duration.Companion.seconds +import kotlin.time.toJavaDuration + +@ExtendWith(VertxExtension::class) +class StateRecoverAppWithFakeExecutionClientIntTest { + private val log = LogManager.getLogger("test.case.StateRecoverAppWithFakeExecutionClientIntTest") + private lateinit var stateRecoverApp: StateRecoverApp + private lateinit var aggregationsAndBlobs: List + private lateinit var executionLayerClient: FakeExecutionLayerClient + private lateinit var fakeStateManagerClient: FakeStateManagerClient + private lateinit var transactionDetailsClient: TransactionDetailsClient + private lateinit var lineaContractClient: LineaRollupSmartContractClientReadOnly + + private lateinit var contractClientForSubmissions: LineaRollupSmartContractClient + private val testDataDir = run { + "testdata/coordinator/prover/v3" + } + + private val l1RpcUrl = "http://localhost:8445" + private val blobScanUrl = "http://localhost:4001" + + @BeforeEach + fun beforeEach(vertx: Vertx) { + val jsonRpcFactory = VertxHttpJsonRpcClientFactory(vertx = vertx, meterRegistry = SimpleMeterRegistry()) + aggregationsAndBlobs = loadBlobsAndAggregationsSortedAndGrouped( + blobsResponsesDir = "$testDataDir/compression/responses", + aggregationsResponsesDir = "$testDataDir/aggregation/responses" + ) + executionLayerClient = FakeExecutionLayerClient( + headBlock = BlockNumberAndHash(number = 0uL, hash = ByteArray(32) { 0 }), + initialStateRecoverStartBlockNumber = null, + loggerName = "test.fake.clients.l1.fake-execution-layer" + ) + fakeStateManagerClient = + FakeStateManagerClientBasedOnBlobsRecords(blobRecords = aggregationsAndBlobs.flatMap { it.blobs }) + transactionDetailsClient = VertxTransactionDetailsClient.create( + jsonRpcClientFactory = jsonRpcFactory, + endpoint = URI(l1RpcUrl), + retryConfig = RequestRetryConfig( + backoffDelay = 10.milliseconds, + timeout = 2.seconds + ), + logger = LogManager.getLogger("test.clients.l1.transaction-details") + ) + + val rollupDeploymentResult = ContractsManager.get() + .deployLineaRollup(numberOfOperators = 2, contractVersion = LineaContractVersion.V6).get() + + lineaContractClient = Web3JLineaRollupSmartContractClientReadOnly( + web3j = Web3jClientManager.buildL1Client( + log = LogManager.getLogger("test.clients.l1.linea-contract"), + requestResponseLogLevel = Level.INFO, + failuresLogLevel = Level.WARN + ), + contractAddress = rollupDeploymentResult.contractAddress + ) + val logsSearcher = Web3JLogsSearcher( + vertx = vertx, + web3jClient = Web3jClientManager.buildL1Client( + log = LogManager.getLogger("test.clients.l1.events-fetcher"), + requestResponseLogLevel = Level.TRACE, + failuresLogLevel = Level.WARN + ), + Web3JLogsSearcher.Config( + backoffDelay = 1.milliseconds, + requestRetryConfig = RetryConfig.noRetries + ), + log = LogManager.getLogger("test.clients.l1.events-fetcher") + ) + + contractClientForSubmissions = rollupDeploymentResult.rollupOperatorClient + val blobScanClient = BlobScanClient.create( + vertx = vertx, + endpoint = URI(blobScanUrl), + requestRetryConfig = RequestRetryConfig( + backoffDelay = 10.milliseconds, + timeout = 2.seconds + ), + responseLogMaxSize = 1000u, + logger = LogManager.getLogger("test.clients.l1.blobscan") + ) + + stateRecoverApp = StateRecoverApp( + vertx = vertx, + elClient = executionLayerClient, + blobFetcher = blobScanClient, + ethLogsSearcher = logsSearcher, + stateManagerClient = fakeStateManagerClient, + transactionDetailsClient = transactionDetailsClient, + blockHeaderStaticFields = BlockHeaderStaticFields.localDev, + lineaContractClient = lineaContractClient, + config = StateRecoverApp.Config( + l1LatestSearchBlock = BlockParameter.Tag.LATEST, + l1PollingInterval = 5.seconds, + executionClientPollingInterval = 1.seconds, + smartContractAddress = lineaContractClient.getAddress() + ) + ) + + configureLoggers( + rootLevel = Level.INFO, + log.name to Level.INFO, + "test.clients.l1.executionlayer" to Level.DEBUG, + "test.clients.l1.web3j-default" to Level.INFO, + "test.clients.l1.state-manager" to Level.INFO, + "test.clients.l1.transaction-details" to Level.INFO, + "test.clients.l1.linea-contract" to Level.INFO, + "test.clients.l1.events-fetcher" to Level.INFO, + "test.clients.l1.blobscan" to Level.INFO, + "net.consensys.linea.contract.l1" to Level.INFO + ) + } + + private fun submitDataToL1ContactAndWaitExecution( + contractClient: LineaRollupSmartContractClient = contractClientForSubmissions, + aggregationsAndBlobs: List = this.aggregationsAndBlobs, + blobChunksSize: Int = 6 + ) { + val submissionTxHashes = submitBlobsAndAggregations( + contractClient = contractClient, + aggregationsAndBlobs = aggregationsAndBlobs, + blobChunksSize = blobChunksSize + ) + + Web3jClientManager.l1Client.waitForTxReceipt( + txHash = submissionTxHashes.aggregationTxHashes.last(), + timeout = 2.minutes + ) + } + + /* + 1. when state recovery disabled: enables with lastFinalizedBlock + 1 + 1.1 no finalizations and start from genesis + 1.2 headBlockNumber > lastFinalizedBlock -> enable with headBlockNumber + 1 + 1.3 headBlockNumber < lastFinalizedBlock -> enable with lastFinalizedBlock + 1 + + 2. when state recovery enabled: + 2.1 recoveryStartBlockNumber > headBlockNumber: pull for head block number until is reached and start recovery there + 2.2 recoveryStartBlockNumber <= headBlockNumber: resume recovery from headBlockNumber + */ + @Test + fun `when state recovery disabled and is starting from genesis`() { + stateRecoverApp.start().get() + submitDataToL1ContactAndWaitExecution() + + val lastAggregation = aggregationsAndBlobs.findLast { it.aggregation != null }!!.aggregation + await() + .atMost(1.minutes.toJavaDuration()) + .untilAsserted { + assertThat(stateRecoverApp.lastSuccessfullyRecoveredFinalization?.event?.endBlockNumber) + .isEqualTo(lastAggregation!!.endBlockNumber) + } + + assertThat(executionLayerClient.lineaGetStateRecoveryStatus().get()) + .isEqualTo( + StateRecoveryStatus( + headBlockNumber = lastAggregation!!.endBlockNumber, + stateRecoverStartBlockNumber = 1UL + ) + ) + } + + @Test + fun `when recovery is disabled and headBlock is before lastFinalizedBlock resumes from lastFinalizedBlock+1`() { + val finalizationToResumeFrom = aggregationsAndBlobs.get(1).aggregation!! + // assert that the finalization event to resume from has at least 1 middle block + assertThat(finalizationToResumeFrom.endBlockNumber) + .isGreaterThan(finalizationToResumeFrom.startBlockNumber + 1UL) + .withFailMessage("finalizationEventToResumeFrom must at least 3 blocks for this test") + + val finalizationsBeforeCutOff = aggregationsAndBlobs + .filter { it.aggregation != null } + .filter { it.aggregation!!.endBlockNumber < finalizationToResumeFrom.startBlockNumber } + + val finalizationsAfterCutOff = aggregationsAndBlobs + .filter { it.aggregation != null } + .filter { it.aggregation!!.startBlockNumber >= finalizationToResumeFrom.startBlockNumber } + + log.debug( + "finalizations={} finalizationToStartRecoveryFrom={}", + aggregationsAndBlobs.map { it.aggregation?.intervalString() }, + finalizationToResumeFrom.intervalString() + ) + + submitDataToL1ContactAndWaitExecution( + aggregationsAndBlobs = finalizationsBeforeCutOff + ) + + executionLayerClient.lastImportedBlock = BlockNumberAndHash( + number = 1UL, + hash = ByteArray(32) { 0 } + ) + + stateRecoverApp.start().get() + + val lastAggregation = aggregationsAndBlobs.findLast { it.aggregation != null }!!.aggregation + await() + .atMost(4.minutes.toJavaDuration()) + .pollInterval(1.seconds.toJavaDuration()) + .untilAsserted { + assertThat(executionLayerClient.stateRecoverStatus).isEqualTo( + StateRecoveryStatus( + headBlockNumber = 1UL, + stateRecoverStartBlockNumber = finalizationsBeforeCutOff.last().aggregation!!.endBlockNumber + 1UL + ) + ) + log.info("stateRecoverStatus={}", executionLayerClient.stateRecoverStatus) + } + + // simulate that execution client has synced up to the last finalized block through P2P network + executionLayerClient.lastImportedBlock = BlockNumberAndHash( + number = finalizationToResumeFrom.endBlockNumber, + hash = ByteArray(32) { 0 } + ) + + // continue finalizing the rest of the aggregations + submitDataToL1ContactAndWaitExecution( + aggregationsAndBlobs = finalizationsAfterCutOff + ) + + await() + .atMost(1.minutes.toJavaDuration()) + .pollInterval(1.seconds.toJavaDuration()) + .untilAsserted { + assertThat( + executionLayerClient.lineaGetStateRecoveryStatus().get() + ) + .isEqualTo( + StateRecoveryStatus( + headBlockNumber = lastAggregation!!.endBlockNumber, + stateRecoverStartBlockNumber = finalizationsBeforeCutOff.last().aggregation!!.endBlockNumber + 1UL + ) + ) + } + } + + @Test + fun `should stop recovery as soon as stateroot mismatches`() { + fakeStateManagerClient.setBlockStateRootHash( + aggregationsAndBlobs[1].aggregation!!.endBlockNumber, + ByteArray(32) { 1 } + ) + log.debug( + "aggregations={} forcedMismatchAggregation={}", + aggregationsAndBlobs.map { it.aggregation?.intervalString() }, + aggregationsAndBlobs[1].aggregation!!.intervalString() + ) + + stateRecoverApp.start().get() + submitDataToL1ContactAndWaitExecution() + + await() + .atMost(1.minutes.toJavaDuration()) + .untilAsserted { + assertThat(stateRecoverApp.stateRootMismatchFound).isTrue() + } + + assertThat(executionLayerClient.lastImportedBlock.number) + .isEqualTo(aggregationsAndBlobs[1].aggregation!!.endBlockNumber) + } +} diff --git a/state-recover/test-cases/src/integrationTest/kotlin/linea/staterecover/StateRecoveryManualReplayToLocalStackIntTest.kt b/state-recover/test-cases/src/integrationTest/kotlin/linea/staterecover/StateRecoveryManualReplayToLocalStackIntTest.kt new file mode 100644 index 000000000..54b75acda --- /dev/null +++ b/state-recover/test-cases/src/integrationTest/kotlin/linea/staterecover/StateRecoveryManualReplayToLocalStackIntTest.kt @@ -0,0 +1,152 @@ +package linea.staterecover + +import build.linea.clients.StateManagerClientV1 +import build.linea.clients.StateManagerV1JsonRpcClient +import build.linea.contract.l1.LineaContractVersion +import build.linea.domain.BlockInterval +import io.micrometer.core.instrument.simple.SimpleMeterRegistry +import io.vertx.core.Vertx +import io.vertx.junit5.VertxExtension +import linea.log4j.configureLoggers +import linea.web3j.createWeb3jHttpClient +import net.consensys.linea.BlockParameter +import net.consensys.linea.jsonrpc.client.RequestRetryConfig +import net.consensys.linea.jsonrpc.client.VertxHttpJsonRpcClientFactory +import net.consensys.linea.testing.submission.AggregationAndBlobs +import net.consensys.linea.testing.submission.loadBlobsAndAggregationsSortedAndGrouped +import net.consensys.linea.testing.submission.submitBlobsAndAggregations +import net.consensys.toULong +import net.consensys.zkevm.ethereum.ContractsManager +import net.consensys.zkevm.ethereum.LineaRollupDeploymentResult +import net.consensys.zkevm.ethereum.Web3jClientManager +import net.consensys.zkevm.ethereum.waitForTxReceipt +import org.apache.logging.log4j.Level +import org.apache.logging.log4j.LogManager +import org.assertj.core.api.Assertions.assertThat +import org.awaitility.Awaitility.await +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import java.net.URI +import kotlin.time.Duration.Companion.milliseconds +import kotlin.time.Duration.Companion.minutes +import kotlin.time.Duration.Companion.seconds +import kotlin.time.toJavaDuration + +@ExtendWith(VertxExtension::class) +class StateRecoveryManualReplayToLocalStackIntTest { + private val log = LogManager.getLogger("test.case.StateRecoverAppWithLocalStackIntTest") + private lateinit var stateManagerClient: StateManagerClientV1 + private val testDataDir = "testdata/coordinator/prover/v3" + + private val stateManagerUrl = "http://localhost:8890" + + @BeforeEach + fun beforeEach(vertx: Vertx) { + val jsonRpcFactory = VertxHttpJsonRpcClientFactory(vertx = vertx, meterRegistry = SimpleMeterRegistry()) + + stateManagerClient = StateManagerV1JsonRpcClient.create( + rpcClientFactory = jsonRpcFactory, + endpoints = listOf(URI(stateManagerUrl)), + maxInflightRequestsPerClient = 1U, + requestRetry = RequestRetryConfig( + backoffDelay = 10.milliseconds, + timeout = 2.seconds + ), + zkStateManagerVersion = "2.3.0", + logger = LogManager.getLogger("test.clients.l1.state-manager") + ) + } + + private lateinit var rollupDeploymentResult: LineaRollupDeploymentResult + + @Test + fun setupDeployContractForL2L1StateReplay() { + configureLoggers( + rootLevel = Level.INFO, + "test.clients.l1.executionlayer" to Level.INFO, + "test.clients.l1.web3j-default" to Level.INFO, + "test.clients.l1.state-manager" to Level.DEBUG, + "test.clients.l1.transaction-details" to Level.INFO, + "test.clients.l1.linea-contract" to Level.INFO, + "test.clients.l1.events-fetcher" to Level.INFO, + "test.clients.l1.blobscan" to Level.INFO, + "net.consensys.linea.contract.l1" to Level.INFO + ) + val aggregationsAndBlobs: List = loadBlobsAndAggregationsSortedAndGrouped( + blobsResponsesDir = "$testDataDir/compression/responses", + aggregationsResponsesDir = "$testDataDir/aggregation/responses" + ) + + this.rollupDeploymentResult = ContractsManager.get() + .deployLineaRollup(numberOfOperators = 2, contractVersion = LineaContractVersion.V6).get() + log.info("""LineaRollup address=${rollupDeploymentResult.contractAddress}""") + log.info( + """ + Start state recovery besu and shomei with the following configuration: + + ./gradlew state-recover:besu-plugin:shadowJar \ + && docker compose -f docker/compose.yml down zkbesu-shomei-sr shomei-sr \ + && L1_ROLLUP_CONTRACT_ADDRESS=${rollupDeploymentResult.contractAddress} docker compose -f docker/compose.yml up zkbesu-shomei-sr shomei-sr + + """.trimIndent() + ) + + val web3jElClient = createWeb3jHttpClient("http://localhost:9145") + + // wait for statemanager to be up and running + await() + .pollInterval(1.seconds.toJavaDuration()) + .atMost(5.minutes.toJavaDuration()) + .untilAsserted { + kotlin.runCatching { + assertThat(web3jElClient.ethBlockNumber().send().blockNumber.toLong()).isGreaterThanOrEqualTo(0L) + }.getOrElse { + log.info("could not connect to stateManager $stateManagerUrl") + throw AssertionError("could not connect to stateManager $stateManagerUrl", it) + } + } + + // wait until state recovery Besu and Shomei are up + val submissionTxHashes = submitBlobsAndAggregations( + contractClient = rollupDeploymentResult.rollupOperatorClient, + aggregationsAndBlobs = aggregationsAndBlobs, + blobChunksSize = 6 + ) + + val lastAggregationAndBlobs = aggregationsAndBlobs.findLast { it.aggregation != null }!! + val lastAggregation = lastAggregationAndBlobs.aggregation!! + + Web3jClientManager.l1Client.waitForTxReceipt( + txHash = submissionTxHashes.aggregationTxHashes.last(), + timeout = 2.minutes + ).also { + assertThat(it.status).isEqualTo("0x1") + .withFailMessage( + "finalization=${lastAggregation.intervalString()} tx failed! " + + "replay data is not consistent with L1 state, potential cause: " + + "data has L1 -> L2 anchoring messages and misses L1 Rolling Hash: tx=$it" + ) + log.info("finalization={} executed on l1 tx={}", lastAggregation.intervalString(), it) + } + + await() + .untilAsserted { + assertThat( + rollupDeploymentResult.rollupOperatorClient + .finalizedL2BlockNumber(blockParameter = BlockParameter.Tag.LATEST).get() + ).isGreaterThanOrEqualTo(lastAggregation.endBlockNumber) + } + + val expectedZkEndStateRootHash = lastAggregationAndBlobs.blobs.last().blobCompressionProof!!.finalStateRootHash + await() + .atMost(5.minutes.toJavaDuration()) + .untilAsserted { + assertThat(web3jElClient.ethBlockNumber().send().blockNumber.toULong()) + .isGreaterThanOrEqualTo(lastAggregation.endBlockNumber) + val blockInterval = BlockInterval(lastAggregation.endBlockNumber, lastAggregation.endBlockNumber) + assertThat(stateManagerClient.rollupGetStateMerkleProof(blockInterval).get().zkEndStateRootHash) + .isEqualTo(expectedZkEndStateRootHash) + } + } +} diff --git a/state-recover/test-cases/src/integrationTest/resources/log4j2.xml b/state-recover/test-cases/src/integrationTest/resources/log4j2.xml new file mode 100644 index 000000000..dfe733a31 --- /dev/null +++ b/state-recover/test-cases/src/integrationTest/resources/log4j2.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/state-recover/test-cases/src/main/kotlin/linea/staterecover/test/FakeExecutionLayerClient.kt b/state-recover/test-cases/src/main/kotlin/linea/staterecover/test/FakeExecutionLayerClient.kt new file mode 100644 index 000000000..bcea25fa3 --- /dev/null +++ b/state-recover/test-cases/src/main/kotlin/linea/staterecover/test/FakeExecutionLayerClient.kt @@ -0,0 +1,73 @@ +package linea.staterecover.test + +import linea.staterecover.BlockFromL1RecoveredData +import linea.staterecover.ExecutionLayerClient +import linea.staterecover.StateRecoveryStatus +import net.consensys.linea.BlockNumberAndHash +import net.consensys.linea.BlockParameter +import net.consensys.linea.CommonDomainFunctions +import org.apache.logging.log4j.LogManager +import tech.pegasys.teku.infrastructure.async.SafeFuture + +class FakeExecutionLayerClient( + headBlock: BlockNumberAndHash = BlockNumberAndHash(number = 0uL, hash = ByteArray(32) { 0 }), + initialStateRecoverStartBlockNumber: ULong? = null, + loggerName: String? = null +) : ExecutionLayerClient { + private val log = loggerName + ?.let { LogManager.getLogger(loggerName) } + ?: LogManager.getLogger(FakeExecutionLayerClient::class.java) + + @get:Synchronized @set:Synchronized + var lastImportedBlock: BlockNumberAndHash = headBlock + + @get:Synchronized @set:Synchronized + var stateRecoverStartBlockNumber = initialStateRecoverStartBlockNumber + + @get:Synchronized + val stateRecoverStatus: StateRecoveryStatus + get() = StateRecoveryStatus( + headBlockNumber = lastImportedBlock.number, + stateRecoverStartBlockNumber = stateRecoverStartBlockNumber + ) + + @Synchronized + override fun lineaEngineImportBlocksFromBlob( + blocks: List + ): SafeFuture { + if (log.isTraceEnabled) { + log.trace("lineaEngineImportBlocksFromBlob($blocks)") + } else { + val interval = CommonDomainFunctions.blockIntervalString( + blocks.first().header.blockNumber, + blocks.last().header.blockNumber + ) + log.debug("lineaEngineImportBlocksFromBlob(interval=$interval)") + } + lastImportedBlock = blocks.last().let { BlockNumberAndHash(it.header.blockNumber, it.header.blockHash) } + return SafeFuture.completedFuture(Unit) + } + + @Synchronized + override fun getBlockNumberAndHash( + blockParameter: BlockParameter + ): SafeFuture { + log.debug("getBlockNumberAndHash($blockParameter)") + return SafeFuture.completedFuture(lastImportedBlock) + } + + @Synchronized + override fun lineaGetStateRecoveryStatus(): SafeFuture { + log.debug("lineaGetStateRecoveryStatus()= $stateRecoverStatus") + return SafeFuture.completedFuture(stateRecoverStatus) + } + + @Synchronized + override fun lineaEnableStateRecovery( + stateRecoverStartBlockNumber: ULong + ): SafeFuture { + this.stateRecoverStartBlockNumber = stateRecoverStartBlockNumber + log.debug("lineaEnableStateRecovery($stateRecoverStartBlockNumber) = $stateRecoverStatus") + return SafeFuture.completedFuture(stateRecoverStatus) + } +} diff --git a/state-recover/test-cases/src/main/kotlin/linea/staterecover/test/FakeStateManagerClientBasedOnBlobsRecords.kt b/state-recover/test-cases/src/main/kotlin/linea/staterecover/test/FakeStateManagerClientBasedOnBlobsRecords.kt new file mode 100644 index 000000000..4f2a15ac5 --- /dev/null +++ b/state-recover/test-cases/src/main/kotlin/linea/staterecover/test/FakeStateManagerClientBasedOnBlobsRecords.kt @@ -0,0 +1,91 @@ +package linea.staterecover.test + +import build.linea.clients.GetZkEVMStateMerkleProofResponse +import build.linea.clients.StateManagerClientV1 +import build.linea.clients.StateManagerErrorType +import build.linea.domain.BlockInterval +import com.fasterxml.jackson.databind.node.ArrayNode +import com.github.michaelbull.result.Ok +import com.github.michaelbull.result.Result +import linea.EthLogsSearcher +import linea.staterecover.DataFinalizedV3 +import net.consensys.linea.BlockParameter +import net.consensys.linea.errors.ErrorResponse +import net.consensys.toHexStringUInt256 +import net.consensys.zkevm.domain.BlobRecord +import tech.pegasys.teku.infrastructure.async.SafeFuture + +open class FakeStateManagerClient( + private val blocksStateRootHashes: MutableMap = mutableMapOf(), + var headBlockNumber: ULong = blocksStateRootHashes.keys.maxOrNull() ?: 0UL +) : StateManagerClientV1 { + + fun setBlockStateRootHash(blockNumber: ULong, stateRootHash: ByteArray) { + blocksStateRootHashes[blockNumber] = stateRootHash + headBlockNumber = blocksStateRootHashes.keys.maxOrNull() ?: 0UL + } + + open fun getStateRootHash(blockNumber: ULong): SafeFuture { + return blocksStateRootHashes[blockNumber] + ?.let { SafeFuture.completedFuture(it) } + ?: SafeFuture.failedFuture(RuntimeException("StateRootHash not found for block=$blockNumber")) + } + + override fun rollupGetHeadBlockNumber(): SafeFuture { + return SafeFuture.completedFuture(headBlockNumber) + } + + override fun rollupGetStateMerkleProofWithTypedError( + blockInterval: BlockInterval + ): SafeFuture>> { + // For state recovery, we just need the endStateRootHash + return getStateRootHash(blockInterval.endBlockNumber) + .thenApply { stateRootHash -> + Ok( + GetZkEVMStateMerkleProofResponse( + zkStateMerkleProof = ArrayNode(null), + zkParentStateRootHash = ByteArray(32), + zkEndStateRootHash = stateRootHash, + zkStateManagerVersion = "fake-version" + ) + ) + } + } +} + +class FakeStateManagerClientBasedOnBlobsRecords( + val blobRecords: List +) : FakeStateManagerClient( + blocksStateRootHashes = blobRecords + .associate { it.endBlockNumber to it.blobCompressionProof!!.finalStateRootHash }.toMutableMap() +) + +class FakeStateManagerClientReadFromL1( + headBlockNumber: ULong, + val logsSearcher: EthLogsSearcher, + val contractAddress: String +) : FakeStateManagerClient( + headBlockNumber = headBlockNumber +) { + + override fun getStateRootHash(blockNumber: ULong): SafeFuture { + return super + .getStateRootHash(blockNumber) + .exceptionallyCompose { + logsSearcher + .getLogs( + fromBlock = BlockParameter.Tag.EARLIEST, + toBlock = BlockParameter.Tag.FINALIZED, + address = contractAddress, + topics = listOf( + DataFinalizedV3.topic, + null, + blockNumber.toHexStringUInt256() + ) + ).thenApply { logs -> + val logEvent = DataFinalizedV3.fromEthLog(logs.first()) + logEvent.event.finalStateRootHash + } + } + } +} diff --git a/state-recover/test-cases/src/test/kotlin/linea/staterecover/StateRecoverSepoliaWithFakeExecutionClientIntTest.kt b/state-recover/test-cases/src/test/kotlin/linea/staterecover/StateRecoverSepoliaWithFakeExecutionClientIntTest.kt new file mode 100644 index 000000000..6daddd144 --- /dev/null +++ b/state-recover/test-cases/src/test/kotlin/linea/staterecover/StateRecoverSepoliaWithFakeExecutionClientIntTest.kt @@ -0,0 +1,173 @@ +package linea.staterecover + +import build.linea.clients.StateManagerClientV1 +import build.linea.contract.l1.LineaRollupSmartContractClientReadOnly +import build.linea.contract.l1.Web3JLineaRollupSmartContractClientReadOnly +import io.micrometer.core.instrument.simple.SimpleMeterRegistry +import io.vertx.core.Vertx +import io.vertx.junit5.VertxExtension +import linea.EthLogsSearcher +import linea.build.staterecover.clients.VertxTransactionDetailsClient +import linea.domain.RetryConfig +import linea.log4j.configureLoggers +import linea.staterecover.clients.blobscan.BlobScanClient +import linea.staterecover.test.FakeExecutionLayerClient +import linea.staterecover.test.FakeStateManagerClientReadFromL1 +import linea.web3j.Web3JLogsSearcher +import net.consensys.linea.BlockNumberAndHash +import net.consensys.linea.BlockParameter +import net.consensys.linea.jsonrpc.client.RequestRetryConfig +import net.consensys.linea.jsonrpc.client.VertxHttpJsonRpcClientFactory +import net.consensys.zkevm.ethereum.Web3jClientManager.buildWeb3Client +import org.apache.logging.log4j.Level +import org.apache.logging.log4j.LogManager +import org.assertj.core.api.Assertions.assertThat +import org.awaitility.Awaitility.await +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import java.net.URI +import kotlin.time.Duration.Companion.milliseconds +import kotlin.time.Duration.Companion.minutes +import kotlin.time.Duration.Companion.seconds +import kotlin.time.toJavaDuration + +@ExtendWith(VertxExtension::class) +class StateRecoverSepoliaWithFakeExecutionClientIntTest { + private val log = LogManager.getLogger("test.case.StateRecoverSepoliaWithFakeExecutionClientIntTest") + private lateinit var stateRecoverApp: StateRecoverApp + private lateinit var logsSearcher: EthLogsSearcher + private lateinit var executionLayerClient: FakeExecutionLayerClient + private lateinit var blobFetcher: BlobFetcher + private lateinit var fakeStateManagerClient: StateManagerClientV1 + private lateinit var transactionDetailsClient: TransactionDetailsClient + private lateinit var lineaContractClient: LineaRollupSmartContractClientReadOnly + private val infuraAppKey = System.getenv("INFURA_APP_KEY") + .also { + assertThat(it) + .withFailMessage("Please define INFURA_APP_KEY environment variable") + .isNotEmpty() + } + private val l1RpcUrl = "https://sepolia.infura.io/v3/$infuraAppKey" + private val blobScanUrl = "https://api.sepolia.blobscan.com/" + + @BeforeEach + fun beforeEach(vertx: Vertx) { + val jsonRpcFactory = VertxHttpJsonRpcClientFactory(vertx = vertx, meterRegistry = SimpleMeterRegistry()) + executionLayerClient = FakeExecutionLayerClient( + headBlock = BlockNumberAndHash(number = 0uL, hash = ByteArray(32) { 0 }), + initialStateRecoverStartBlockNumber = null, + loggerName = "test.fake.clients.execution-layer" + ) + blobFetcher = BlobScanClient.create( + vertx = vertx, + endpoint = URI(blobScanUrl), + requestRetryConfig = RequestRetryConfig( + backoffDelay = 10.milliseconds, + timeout = 5.seconds + ), + logger = LogManager.getLogger("test.clients.l1.blobscan"), + responseLogMaxSize = 100u + ) + logsSearcher = Web3JLogsSearcher( + vertx = vertx, + web3jClient = buildWeb3Client( + rpcUrl = l1RpcUrl, + log = LogManager.getLogger("test.clients.l1.events-fetcher"), + requestResponseLogLevel = Level.TRACE, + failuresLogLevel = Level.DEBUG + ), + Web3JLogsSearcher.Config( + backoffDelay = 400.milliseconds, + requestRetryConfig = RetryConfig( + backoffDelay = 1.seconds + ) + ), + log = LogManager.getLogger("test.clients.l1.events-fetcher") + ) + fakeStateManagerClient = FakeStateManagerClientReadFromL1( + headBlockNumber = ULong.MAX_VALUE, + logsSearcher = logsSearcher, + contractAddress = StateRecoverApp.Config.lineaSepolia.smartContractAddress + ) + transactionDetailsClient = VertxTransactionDetailsClient.create( + jsonRpcClientFactory = jsonRpcFactory, + endpoint = URI(l1RpcUrl), + retryConfig = RequestRetryConfig( + backoffDelay = 1.seconds + ), + logger = LogManager.getLogger("test.clients.l1.transaction-details") + ) + + lineaContractClient = Web3JLineaRollupSmartContractClientReadOnly( + web3j = buildWeb3Client( + rpcUrl = l1RpcUrl, + log = LogManager.getLogger("test.clients.l1.linea-contract"), + requestResponseLogLevel = Level.INFO, + failuresLogLevel = Level.DEBUG + ), + contractAddress = StateRecoverApp.Config.lineaSepolia.smartContractAddress + ) + + stateRecoverApp = StateRecoverApp( + vertx = vertx, + elClient = executionLayerClient, + blobFetcher = blobFetcher, + ethLogsSearcher = logsSearcher, + stateManagerClient = fakeStateManagerClient, + transactionDetailsClient = transactionDetailsClient, + blockHeaderStaticFields = BlockHeaderStaticFields.localDev, + lineaContractClient = lineaContractClient, + config = StateRecoverApp.Config( + l1LatestSearchBlock = BlockParameter.Tag.LATEST, + l1PollingInterval = 5.seconds, + executionClientPollingInterval = 1.seconds, + smartContractAddress = lineaContractClient.getAddress(), + logsBlockChunkSize = 5000u + ) + ) + configureLoggers( + rootLevel = Level.INFO, + "test.clients.l1.execution-layer" to Level.INFO, + "test.clients.l1.web3j-default" to Level.DEBUG, + "test.clients.l1.transaction-details" to Level.INFO, + "test.clients.l1.linea-contract" to Level.INFO, + "test.clients.l1.events-fetcher" to Level.DEBUG, + "test.clients.l1.blobscan" to Level.INFO, + "net.consensys.linea.contract.l1" to Level.DEBUG + ) + } + + // "Disabled because it is for local testing and debug purposes" + @Test + fun `simulate recovery from given point`() { +// println("L1 is $l1RpcUrl") + val finalizationEvents = logsSearcher + .getLogs( + fromBlock = BlockParameter.Tag.EARLIEST, + toBlock = BlockParameter.Tag.LATEST, + address = lineaContractClient.getAddress(), + topics = listOf(DataFinalizedV3.topic) + ) + .get() + val firstFinalizationEvent = DataFinalizedV3.fromEthLog(finalizationEvents.first()) + val lastFinalizationEvent = DataFinalizedV3.fromEthLog(finalizationEvents.last()) + log.info("First finalization event: $firstFinalizationEvent") + log.info("Latest finalization event: $lastFinalizationEvent") + + executionLayerClient.lastImportedBlock = BlockNumberAndHash( + number = firstFinalizationEvent.event.startBlockNumber - 1UL, + hash = ByteArray(32) { 0 } + ) + stateRecoverApp.trySetRecoveryModeAtBlockHeight(firstFinalizationEvent.event.startBlockNumber).get() + stateRecoverApp.start().get() + + await() + .atMost(10.minutes.toJavaDuration()) + .pollInterval(10.seconds.toJavaDuration()) + .untilAsserted { + val updatedStatus = executionLayerClient.lineaGetStateRecoveryStatus().get() + assertThat(updatedStatus.headBlockNumber).isGreaterThan(lastFinalizationEvent.event.endBlockNumber) + } + } +} diff --git a/state-recover/test-cases/src/test/resources/vertx-options.json b/state-recover/test-cases/src/test/resources/vertx-options.json new file mode 100644 index 000000000..15cb81ab6 --- /dev/null +++ b/state-recover/test-cases/src/test/resources/vertx-options.json @@ -0,0 +1,15 @@ +{ + "blockedThreadCheckInterval": 5, + "blockedThreadCheckIntervalUnit": "MINUTES", + "maxEventLoopExecuteTime": 2, + "maxEventLoopExecuteTimeUnit": "MINUTES", + "maxWorkerExecuteTime": 5, + "maxWorkerExecuteTimeUnit": "MINUTES", + "metricsOptions": { + "enabled": true, + "prometheusOptions": { + "publishQuantiles": true, + "enabled": true + } + } +} diff --git a/testdata/coordinator/prover/v3/aggregation/responses/1-3-c582331fee9d97bf39b11a6681579c5478097d4af5eb2c97e872c798b03287eb-getZkAggregatedProof.json b/testdata/coordinator/prover/v3/aggregation/responses/1-3-c582331fee9d97bf39b11a6681579c5478097d4af5eb2c97e872c798b03287eb-getZkAggregatedProof.json new file mode 100644 index 000000000..ad848c214 --- /dev/null +++ b/testdata/coordinator/prover/v3/aggregation/responses/1-3-c582331fee9d97bf39b11a6681579c5478097d4af5eb2c97e872c798b03287eb-getZkAggregatedProof.json @@ -0,0 +1 @@ +{"finalShnarf":"0xc185fbadf462de3a6c8517cbac3ba7402a14e939e1d77e3a515ca1c8a3f7d977","parentAggregationFinalShnarf":"0x47452a1b9ebadfe02bdd02f580fa1eba17680d57eec968a591644d05d78ee84f","aggregatedProof":"0x2fce59e8ff9585ec54b9a65ef16689ac01b95a970b87f453621a67a6e43598ea13e050036085b8976063645febf63e6bd68711de8074aca1e50844a541a13e1706342123781363103b4d11463e4e19b399c6b2bc0aa0a958ecf17c5f6052adb612b100900ab5a6fbdcb8bd8771d94a3c152a551bb449f140196dba27f2b5f4591af3af628c1cc32eda5450d9281542198df8c799ab79b17d35e84b81ae116c701eaf6a1f1c406d505167c42b9536dc4bb4cddba008358481cd899ff43a72eaba14861c88cbb5c8b346ae3b89720b828f8019d488fe7218c1fa2bf6c7ee83d8c927a7131ff16fe07fad81aacf3d30a2a7b7b6d1c3cfbd8d76fec0e801aac9b05926e55a1c68af58690f81b1f4901249055b6ac6a0b07c161d0bd1ec2d7810febe2ab6d0aac357996416eef005dfa6eed5b84217734a4ec35f5e0f6a93cd3e922c1a78230a1f77fe4119004a36e6f8102268351daced3a1400e8dbc31fdab7e9ed233b54717044c411575b622db9911ea357618c9756f9e159db55503c1d9249d80b5f797925359e87ef33584af680fef9b03fa484596c864c858a83608f3359f51472226a15cab2906a875d74f7a3b1bf78a2c5c5f13e5781076590c5d083719929ba53673b8ddc3562fa2af2c16e9da83c71d7a1d28a49c210b45cea3dc593d22ca8d13342f07f98fc3170e035254c4732c8c9fc0a489c97fd38d11b6f765ca82e37b29c1dda62b6734f96373761fa242ec920a1919e837bfdd96b778832140f0067a3f503680e53a94157865bdd6dc5631b06900dc74b99488ed9ca2008f265030fcf8ede7ecfdc474063f163f00c3c879d58d3b56909632cb29be9035b9eac15c76a0b16c1a548379336da4d1109c570ce8e376448fe9788df96fcf7261b08249d6bebe9c2962c47b0ac0a8e9c83d7c42e129182001089e5791b72994bfd01242d887d15f028c7c5b7429d8b84eadc76253569b09f040335ec8736e601256b0c67c4529a046fab2ed1ef8128f27a531bf8c978dfacdbb2d45b57f638159d8d16c3b8c0238c6b019715cfd406ee4a43fdff2c1ddb494c4851c57ead7c87a57a02cc50a74782bb3806bdfffc5a63e4c416ea087d5d864687915491076cea7a572d22d5fd79af0e8397e8cee8153655b0b277e9cf08e29b3d1e603e1f6ff27ae722910b6cc936a66e7ed831280fdf22fb3b308a5ea19582a20b796dbb4bbbc310","aggregatedProverVersion":"3.0.0","aggregatedVerifierIndex":0,"aggregatedProofPublicInput":"0x0ba9370c3f9cd0e53ec8d54dd1db4cfcdc058586bd3d96ebb2c7fbed5e52b8ec","dataHashes":["0x01f48456f10caa5029fed9b89cc5d2b3853af3a1b76f0deae6ebb5a2dd1e9ea2"],"dataParentHash":"0x0000000000000000000000000000000000000000000000000000000000000000","parentStateRootHash":"0x072ead6777750dc20232d1cee8dc9a395c2d350df4bbaa5096c6f59b214dcecd","parentAggregationLastBlockTimestamp":1683325137,"lastFinalizedBlockNumber":0,"finalTimestamp":1736794040,"finalBlockNumber":3,"l1RollingHash":"0x0000000000000000000000000000000000000000000000000000000000000000","l1RollingHashMessageNumber":0,"l2MerkleRoots":[],"l2MerkleTreesDepth":5,"l2MessagingBlocksOffsets":"0x"} diff --git a/testdata/coordinator/prover/v3/aggregation/responses/11-13-523fe0caa8ea09a3787268f8bc8cfdbf9005d1e527ed656c4efd1ec39e60dee1-getZkAggregatedProof.json b/testdata/coordinator/prover/v3/aggregation/responses/11-13-523fe0caa8ea09a3787268f8bc8cfdbf9005d1e527ed656c4efd1ec39e60dee1-getZkAggregatedProof.json new file mode 100644 index 000000000..e5d37d4e9 --- /dev/null +++ b/testdata/coordinator/prover/v3/aggregation/responses/11-13-523fe0caa8ea09a3787268f8bc8cfdbf9005d1e527ed656c4efd1ec39e60dee1-getZkAggregatedProof.json @@ -0,0 +1 @@ +{"finalShnarf":"0xe5f194ad53779deb52c2455e216ca447a842026238fd8143cbb7911f7aefd9e7","parentAggregationFinalShnarf":"0xe6a7703511076e3789cc25059b468940b2e91df262f11b95b9005f758482aed7","aggregatedProof":"0x24a4e08e2510e67497a9bf54aeb7dcb4e332dde5d9cb7adccba02bb84cbc4b1726dcae96eb0d405af285c3d74e734ca03f86e756bd6fe8ef1debca98aa8e57320d52ce7fb0dfa443e3f83f03a0eda48a6ca4519a98847696b534a5dbb73d1c3410623dffdb10e816a1e60b42c748fcc75b8130ff36d0df6f37f431beafb10fe20e2f610c2dbef1cf7ae6be41442583d02f5781eaae326b0e05156caccb0ef8ef152945136a3fd7b2d4f5b578eb5ba0a47a8e0ba792baa8e26b6c5736335088ee10ac33056a58d18a85747936cb2a8d35f80ba24bbddbd71e39774ffbe3de37ae26dc6a391d549a2bce509a754aac4b19d898905ff9bd2b8bc95272322c501be717f680a296bb049da5d2aaaa5c2869f5bb6e50a956b9d409adee84aead6b831001a623f3ba483d00028a2ae874bc3f3b0a720b3df5bdda5cf18433bea97d21f21c3b6ed2af242fe42443a7805e2c1b8c806be9a374aeaccf59126e63170fc9c82a2a9aba194ec376e917288ba3158a48f7bc7c73cc0277cd81356a58497562bc16dee2091f035d9e3fd384dd1ebbaae08f39fc0c54681583c30dfe531c5576362c7ac33ae42859454dad8bb0368ae6251763d42179b1b32e71f7eacb2d9c9ac72f2aad843d875ee2fcfa6678f11bd398b3484979cec2074bbe4973ed2c5168030ec9913624814a1592c3e1657bf1c8752df6577f686bacfecb51d2817bc13e51163c5f64fe1b28b0df2873bdf9c4bf7415d4092c69b879f91b07fe19d9801b4225526b1a10af347bb0f3108a18b47ada60522c1c3485a7ef9657fa6753c5b0c51a015870ecc86f6b28a437f5cdd02666e1cc6d1636b4aeaeef525c9f5f98343616f20c994c94f84f0bd7630c30cc910e55b225c1e05125ac7365ad5cb2da23c92b8c3b7284190fc1553e3bcc0f6110f689bca2bd100e74046e92af842d84f78f2c10b572e8313875b537c9c8a60c4d81c09985f1734314f889643997457e4ef81b022c04a4aa593553c63985ee25db2b4b609b7775bddff0e09c24d7c62204ef0635355fa248defec23d7ec4654b564570b4cce30f1ee79d65eb490ae977a5321ebf7a482ba551a5e801998c6f1c4af44de96f2b25a7719ccba69f90fcfee5212619753e68c001a24926de6c0ccd20d43757021d0aa915998d66cb0b5dcb9ff10c2c9daa1ab74083542ad6064b5a9d84ddc46f642a6a7305289c7a38ed63c459","aggregatedProverVersion":"3.0.0","aggregatedVerifierIndex":0,"aggregatedProofPublicInput":"0x2a00a4c1d13bc8f8034ebcf9723e330967c7a08289b9475539bb3c01ca0d6985","dataHashes":["0x01f05738e04c668af5ca1887f52528ccb9eef7cc90afd73c9c23c14550021323"],"dataParentHash":"0x01c993ae52495203ab88827c3111fcf3b09c16655c392dbdaac614dc00473c32","parentStateRootHash":"0x06dfd5bf00ac76bece68984bced5f376d4a62abc03b56472959bf804c547d574","parentAggregationLastBlockTimestamp":1736794163,"lastFinalizedBlockNumber":10,"finalTimestamp":1736794176,"finalBlockNumber":13,"l1RollingHash":"0x0000000000000000000000000000000000000000000000000000000000000000","l1RollingHashMessageNumber":0,"l2MerkleRoots":[],"l2MerkleTreesDepth":5,"l2MessagingBlocksOffsets":"0x"} diff --git a/testdata/coordinator/prover/v3/aggregation/responses/14-16-193b46cfdb687e208772c266f87c91e78a3edb1e02de9888b0ed37bf8560eb30-getZkAggregatedProof.json b/testdata/coordinator/prover/v3/aggregation/responses/14-16-193b46cfdb687e208772c266f87c91e78a3edb1e02de9888b0ed37bf8560eb30-getZkAggregatedProof.json new file mode 100644 index 000000000..34892c047 --- /dev/null +++ b/testdata/coordinator/prover/v3/aggregation/responses/14-16-193b46cfdb687e208772c266f87c91e78a3edb1e02de9888b0ed37bf8560eb30-getZkAggregatedProof.json @@ -0,0 +1 @@ +{"finalShnarf":"0x8de7b2d25ebb3dd54040cc30cbe3a6333053816812bb33dca470e945eff7044c","parentAggregationFinalShnarf":"0xe5f194ad53779deb52c2455e216ca447a842026238fd8143cbb7911f7aefd9e7","aggregatedProof":"0x12594e0c4b4af367a2b24f097cb834477248479b2036687d3133112dc93364740718680307433007f39d2b6641fc451a7c8efa3cc5bd25a3ce01f2087ad4161c0c729a0f996b90bea7939b4cdc5692651679167e4b4744f55d3e8262f97e8f981bb01b9f6ffb5a253c40ae0a90980cf32578b364029a7cd7f57d78e27e88082d2f27271285e4e092c67f08a2aed485ce6e9f80a0c4cd8e8879616160c3faed300724963bc87d12e8e9403df2fd576ac5e4580b64c810fb0788e34fcc992520f40ef8cda4e3dd51129a2a82a45dac501c42e7dc8a9c0316f56626e47ee242cbb91d3dc8e18ee276f2fb9b84551bb11b584d4662fa703f4efa9a050ead916ef708038f49aa25ac389fa29bff91930747ac1ca378aa16a494a620d5b1d98125dc8716441b728afe09ce6b08753517076f52a40d90423a8ac9e0e10f73310d18642005cb2e9ce7acfc99dcaee41d28236248d8f79e144eab14a0e2aa318bbdac930c1e5b0c7c986c9d9df0da2bd84258bc422e0bb6704b3b8f2e03a475790ebefe44005d95028da5aacf102e19caceb2ed3973beec18b65966b7e83a35178191cdf42510edc449e51c3646417034733451635f3842df96668d7997d444cbf648ce5204cd7dc27b7dbb795e1d429ed949c4089daf38b202af7f3b7321aaa0d6d6c8972617451f3ae97386a88572e4a748b59eb10299b2638ee8548d35c2ce9f02d02c1afdb6fac9df48c936206e013fece225e97fccf483c6609839c80ca83401d578301a89aba444d1f4494c8ac11b933c71605ad718778c0b8570de450fe2f24f0125166ed94151cf455f81539d77832ff2fd6c2ce3738900710095a37e21a0686b0a5b24376437fed1f3700776bf9d0f829d20836f5170da3bb8b630dac8be5154054ee536afcb92ec353e4a2354c9a291ba134c1cd33564ecb7f160aa0a67af3b09fb710442e57342dac3941045d412d0fa2ebe17a331f5fb83697cff45002bb02e5027aefbbd95ef8c79b71c65a123f3ac9d55521272ca5f7f2f8912be7098482b0452a8efcc295fa06b81daa1ca6cdae18d45622d013e9ae528cb267c750b9105b464fcf8ac9310ba53c479c698ebd3cb93823535519bc06537515028c858ce11fe9a193cf833b6df7c96da1fc6c7dde75f7e4be18eaf0409a258e46aff9a012b3002a445063d2711453d94858130569d002f0a1935b161328d4a072df8ff82","aggregatedProverVersion":"3.0.0","aggregatedVerifierIndex":0,"aggregatedProofPublicInput":"0x213e0703c2e3906c3be01622e765c4c65ba823b38c907692be17df3eaf5052b0","dataHashes":["0x0117ba7a785df44964e79ee97cf056d3af4ab463f1a4f30ae273f37cd5caf211"],"dataParentHash":"0x01f05738e04c668af5ca1887f52528ccb9eef7cc90afd73c9c23c14550021323","parentStateRootHash":"0x093fd331edcf516c7e6805250bb7b6b56131fc20921916096e4a8a71d0612167","parentAggregationLastBlockTimestamp":1736794176,"lastFinalizedBlockNumber":13,"finalTimestamp":1736794188,"finalBlockNumber":16,"l1RollingHash":"0x0000000000000000000000000000000000000000000000000000000000000000","l1RollingHashMessageNumber":0,"l2MerkleRoots":[],"l2MerkleTreesDepth":5,"l2MessagingBlocksOffsets":"0x"} diff --git a/testdata/coordinator/prover/v3/aggregation/responses/17-19-b615854a9075e73fdbdb0f22367d8e48c36997b28857712f018ba10e05f52759-getZkAggregatedProof.json b/testdata/coordinator/prover/v3/aggregation/responses/17-19-b615854a9075e73fdbdb0f22367d8e48c36997b28857712f018ba10e05f52759-getZkAggregatedProof.json new file mode 100644 index 000000000..e6b198ff7 --- /dev/null +++ b/testdata/coordinator/prover/v3/aggregation/responses/17-19-b615854a9075e73fdbdb0f22367d8e48c36997b28857712f018ba10e05f52759-getZkAggregatedProof.json @@ -0,0 +1 @@ +{"finalShnarf":"0x343fef4cdcb6d0ab0db8ea7da91820c8d21a80135608b990c0b4f40c8f48b837","parentAggregationFinalShnarf":"0x8de7b2d25ebb3dd54040cc30cbe3a6333053816812bb33dca470e945eff7044c","aggregatedProof":"0x0edf53a96a2e976e3d6b53d6bc915136815b322a6a5e585abb4b02d46a3e62cc056d1147586f036627fa7a814845a0a932270ca94bc74cb507a0100c977621261e8334bf6c1a7ff2d67215f3cbfd04be0312b5bd0fbe8dd479e6dc4ad745f4a41718dea11a13a50e7402b630b00daff9c8e251cde4596f53734ab488e56800f32686b1d8fe6ea469c6d37173e25eaea6c609c79fdf3402dd399f4d40944d342e2dd5e16c82ebfbd9ac041f1d0695c904bd0025ca8215eb8f737c66e5a7a15f2e0e1c8c5b817b132bc2928213fb0689db24641d56cb3cd9900aec1e4f14d17e0827e8eefb7b4e5469283e29a125bc69ed0fd06d73be2d243e5b75b9ded4d959721b416b64722b52ad3e67aada91b41e97fb36d025572f0bd4b02080d3647dbf44125a3b4591112c459f91785c0515699d3e7a0cf8efde11c882b171493a8f73f113f9fa2a36ce1da183ea1e8b85ca56fd5685c8ba808a31427e64c2364b25d61b21bbe92558fad3a7d5625e827ff57ee4c1a3bba4cb5336a33bbaa1583b5cb6b605e585339289d33047ed85963e7d8b7b57a6eaa13af83debe692d7ef9ded956d2bfed7685f60d5f1bd0f9a2fb1e5d788525abf450086ed82ac9c3f24904325a01d31f4b0310d0f0da51b1fe4ad5a2393bfe5287ee07ab9d8b35ffd65297b8b4424d4825c022e75891a81d1dc156bc2783355134f6b1864b3133f6391db1d256e25246502cd491073beca3bafe84b0b215454f586c916c07702ea3014a80be8772a5afc2dca1693af1aa908630e892140e685ed8b5852e03aa15f98a5373c79901a76bad0d8076fc20d421e62aeb182d6881d829b1770c2cd5be02a6dceb4ed0704587f81188cf93de74d1389d454d73a0e7c47d0d5bd786df7e1cfc1da51414913efea98a6d90a9f29a18047d7a3849eb649e23e047b2b5a89ccda39766d43240788699a39ab5e7c65fbe0fbc4c70f9705b8babc79e1c3b3d3dd99e87b922ca921afb351a94c16556098454c545fe618b8ed4f80ffa4e1a7cc78f43c225d87980af32f5895a7eafece87f1d4ee3febf294adc915146dccdd7f07905b40f3d85203bffab40af6c19b736d6a4651102c3fb735601525ca0e36bebf5e88984e2f59254b4b5d91374755a58820770416eb12c020df54d8f5de00e1d62e129cedb3bb230eadbe5bb0d8f065e51acd7f694f8dee6bf1a7607a91851c0fbb75f28bd255","aggregatedProverVersion":"3.0.0","aggregatedVerifierIndex":0,"aggregatedProofPublicInput":"0x29b9d593344364a7c40bc0d045897a8187213391a50af436df38c60f8f7bbb48","dataHashes":["0x011494f735f62294281086b6b718118dc25868b6df1ee20fea3a37d254c3f1c1"],"dataParentHash":"0x0117ba7a785df44964e79ee97cf056d3af4ab463f1a4f30ae273f37cd5caf211","parentStateRootHash":"0x026a0d5bb730f4867e5e9d696d6dcb4a028cbb918549565e9cdcb6b42f839573","parentAggregationLastBlockTimestamp":1736794188,"lastFinalizedBlockNumber":16,"finalTimestamp":1736794200,"finalBlockNumber":19,"l1RollingHash":"0x0000000000000000000000000000000000000000000000000000000000000000","l1RollingHashMessageNumber":0,"l2MerkleRoots":[],"l2MerkleTreesDepth":5,"l2MessagingBlocksOffsets":"0x"} diff --git a/testdata/coordinator/prover/v3/aggregation/responses/20-22-9e033347194ecf686585d4ddc81a602edc9afa61c9d8437c69a1f0981e66fb78-getZkAggregatedProof.json b/testdata/coordinator/prover/v3/aggregation/responses/20-22-9e033347194ecf686585d4ddc81a602edc9afa61c9d8437c69a1f0981e66fb78-getZkAggregatedProof.json new file mode 100644 index 000000000..74c0b6a98 --- /dev/null +++ b/testdata/coordinator/prover/v3/aggregation/responses/20-22-9e033347194ecf686585d4ddc81a602edc9afa61c9d8437c69a1f0981e66fb78-getZkAggregatedProof.json @@ -0,0 +1 @@ +{"finalShnarf":"0xaea706d4657966f8e30e918e1097ffa0da19513b0be56a243cabd7d3a32358c7","parentAggregationFinalShnarf":"0x343fef4cdcb6d0ab0db8ea7da91820c8d21a80135608b990c0b4f40c8f48b837","aggregatedProof":"0x2230b32e3a65e9592595864aebe3d985e2acc2524a17f20f9cd8f0d28894cc3f0dbc5786ca09449661e6696385b6fc165ac27a0b64848ef98ff1d0ef627dd59a1070e81062466d84feb95356e8317f4770610afa13c636779b3b00de491915780a2b5df0944142092d73a32a4ac56e479b0ded304feb00be9aa674ebf153d7f11d1e15548655f51eef49a2f19cd198edcfbca80df8df3c309224c838a715158d00c83b5bd9fc710400ebe8e0b6169d66a9dfce0db0fb493bdeb90f3c29cdfafd0930d710d2430039358be5b36df0f5edaf630bb3c3c8f12e94a273e79f2a46f81899152085c9bbaafc653c495e35aaa24fca7ff2355821665bffd4c167cee2f711e42d43f468d71a0427e96746239733a95d43da022eb1dfcee0f38e063d6735086fe08a9b7acf7da4a576e3070ee5dbdd1b30040af7e6cfb18f4fb855bccf952e72981a6f0eae07154d91cd6c8b4e34747ff7a8641281f4ffcda9f8c7fb4cf527a15e8f2eb68f56c4532f217630345db20408e6b7622ef0aaf88fb53d584902256e3612bb40a8c680763406b8baa315d250c840fab1e1b00699608929031b5112b5712bb925806f22afb6c82078bb9939228247e8f5fb34fee153e0e4bb10d3094d514114bb6832bc9b43bad66f1004ce90509e1ef6e268aa9e9ed46e9f6bed0378e994d8d0a15d9e4199b3a88cf0e7f9b47f008e04e3d219124915b3de2d5d0d9854b43d92f0af4f96d23f954775b9c4fde7e3e3928e5e957f0ceb97a81852147c326b51ced6ccd1992087555aa7f4d9b9624610c6771f5ce9b74b5fcc66681f6711b65319c3768709aa028f1cea7f3751b2cedcf6065de0f9b64d0a52c08f0b29b80fbb9e4d2b3e332f34e07156f5934fdbd1603740261a8a1fd449f786a41ebec7f529195879a38cc8fc773a8fc285cebb370a8489e268853bce28a11d280deb1dcc80389a0b426cce069718b90f066acb0a8e0fabf3862f76b957d205750a8d3af9ad462e36791c62d6db7c2608e2f62dcf56b0e74b5ea3082cbc6eb5e3140ef004a0bf32e3946f134326ac51d22702de96b2a18c6f6d78508036d3169f01313a4b4316017a54f9de635490da4ac1bc02027d31fcb4832df5a28b608bc22e4c3639c48a272a85c1c7d993951d6b7ae044b381e1d4b38f586ed45927b0f6246b99b4e85d044c7ad9d61786e7868e90ead53754c56572041eb464d06b55bc","aggregatedProverVersion":"3.0.0","aggregatedVerifierIndex":0,"aggregatedProofPublicInput":"0x28d8d27645cf1f2bb8527770fb5810c016ded63deafa33d385ea7610da4f6f45","dataHashes":["0x0146d216177763b2ddaf338614ac3c621b193019f04145d45ea58dc381c910b1"],"dataParentHash":"0x011494f735f62294281086b6b718118dc25868b6df1ee20fea3a37d254c3f1c1","parentStateRootHash":"0x0cdab0bfb220ab9c5b2199486f2e828cc1c2b350410dad11102dc3e1f333dfb8","parentAggregationLastBlockTimestamp":1736794200,"lastFinalizedBlockNumber":19,"finalTimestamp":1736794213,"finalBlockNumber":22,"l1RollingHash":"0x0000000000000000000000000000000000000000000000000000000000000000","l1RollingHashMessageNumber":0,"l2MerkleRoots":[],"l2MerkleTreesDepth":5,"l2MessagingBlocksOffsets":"0x"} diff --git a/testdata/coordinator/prover/v3/aggregation/responses/23-25-1cdd5b5dd6cf38f123b1de80eb1d86ce47ba28a9689930db69175cc9976f4fa4-getZkAggregatedProof.json b/testdata/coordinator/prover/v3/aggregation/responses/23-25-1cdd5b5dd6cf38f123b1de80eb1d86ce47ba28a9689930db69175cc9976f4fa4-getZkAggregatedProof.json new file mode 100644 index 000000000..d0555d391 --- /dev/null +++ b/testdata/coordinator/prover/v3/aggregation/responses/23-25-1cdd5b5dd6cf38f123b1de80eb1d86ce47ba28a9689930db69175cc9976f4fa4-getZkAggregatedProof.json @@ -0,0 +1 @@ +{"finalShnarf":"0x268a263e550eb02c8196d4b9e3cc06a55d87018f2e20ed7304da5f2f3f6bbe5b","parentAggregationFinalShnarf":"0xaea706d4657966f8e30e918e1097ffa0da19513b0be56a243cabd7d3a32358c7","aggregatedProof":"0x1b1ffc9faa35df9ca75c70806193dcdfebc2674b7d9bbd3fd98c51ff8ffd0b2321a587e8112706244802a9a461e9a374c85272be5627d4baee48f763795411cb268164698dede7b284796427f22a6d1336d37bcf946bc6234b1398ce9f7b4e6814158401076cd470571a97f9d8737750d70e21e6449520cc42de4a107531bbe8082e5ead0b128facfd749de504e98ab99f322a04b01d6a32d8a90e1c139d8b4b2264119c174627a59ddca3b94bee51e00e5b82780846947c07411376f1f907280e480eb6cd0de73c5ead2d5d6250757e315014a6a8afea8339e298daad0e625b01397f8c6183b60993480ecaf794236507ae9e5b167dcc013e522d918c9bf50208cb16689e2a0475a394f421a62e51126b3552745410253f3fd72aff21c825931a231a770fdecaffd51c1d3fe6f0fa7ef78a25adf501f59a661482d20fbb51d5185f080c4644b00227d4c7439f73b763cdd3ba90bf4c1ba39d716582d75599152690f2ec8c5c71bf5a4e221fe42b61d0f3818c95cba3fda91c03aea056610e7d047453c276e60985f97bf8b06117dd2e8d5f9cd61bcb5ba77a811cceba76f3460c8158a23676ea3de96dd6d888d45d49450a1f81e9b27fe8ad7137f695aabed72b22ad39385e7b5bc97735a787511ea395046f00dac60fdb05611d44851e1fc92c6362892536a9329b905f14a9dac0fcfb86d6b9a853a64665303f6da8ae959e0da84f5219477242a2d2b66f214f91711cccd1080647cfd0ada288cb6f69db741065e63aa901e09bd447ced598fef91f4d4afe7ac903f6f2997cc58191d7888c263456e64179ab53d37e5098bf431d8d4b4e3953e1d771e351634f7b730b6e3420b2dedfcae4e9d833fc9f7d64de05ce00d707e25aab821016619e5e554952490006059506061e641d58946b52606ae810154e38de8c65b4ea8441dd4654c26f03dc1cea0d66a394caaa260ba0bddee02f411d89f5468a23a53a3fcae6c6fb7b1b95709b8371f24b9289f69ba2652f94c9847ff33ecf946a588236cd4af82c0e16a103a37b3f2abe4285922963c3b974a5eabe96779a9152d23d8e559457edd61be5083e4f3426c2e69bbc5c823872bfbf2769238310e0220ae52d209f2cb5b423b82bb90b671bdd70ce60874dd6709df57df42874b861e552e24713776bfa730c718f7e7db9c9ec6d4dd47e6c53831d4e305d41871e0c23b356df7c047a583b","aggregatedProverVersion":"3.0.0","aggregatedVerifierIndex":0,"aggregatedProofPublicInput":"0x05e4bd2b1655c0d801dae28d6acd4b2813c04638bf0c3b5c92ba9fd9b62c3255","dataHashes":["0x011c205cb61ad36b464d88916e02f3979b79b042c8cab3658900d36046c4aaf1"],"dataParentHash":"0x0146d216177763b2ddaf338614ac3c621b193019f04145d45ea58dc381c910b1","parentStateRootHash":"0x0bab6a28cfabc29cf1e284145b39f5b37ad04ca0d85cf878943fd066b3c8fb10","parentAggregationLastBlockTimestamp":1736794213,"lastFinalizedBlockNumber":22,"finalTimestamp":1736794225,"finalBlockNumber":25,"l1RollingHash":"0x0000000000000000000000000000000000000000000000000000000000000000","l1RollingHashMessageNumber":0,"l2MerkleRoots":[],"l2MerkleTreesDepth":5,"l2MessagingBlocksOffsets":"0x"} diff --git a/testdata/coordinator/prover/v3/aggregation/responses/26-28-655573aeabb826867531dedc1510fd1c7540e871ce2da96641b2e59ca659669a-getZkAggregatedProof.json b/testdata/coordinator/prover/v3/aggregation/responses/26-28-655573aeabb826867531dedc1510fd1c7540e871ce2da96641b2e59ca659669a-getZkAggregatedProof.json new file mode 100644 index 000000000..9130be99c --- /dev/null +++ b/testdata/coordinator/prover/v3/aggregation/responses/26-28-655573aeabb826867531dedc1510fd1c7540e871ce2da96641b2e59ca659669a-getZkAggregatedProof.json @@ -0,0 +1 @@ +{"finalShnarf":"0x06851ec1f1ba875ffd3a08fa5b2f0d88ac9426c9ccd852973abe73bd9afc921d","parentAggregationFinalShnarf":"0x268a263e550eb02c8196d4b9e3cc06a55d87018f2e20ed7304da5f2f3f6bbe5b","aggregatedProof":"0x0c8d8a4fce1dc63af90bd6a1b42f2dc179a8b26cdfb84b3918f15db6a26e0aad0f546bee463e0d31619fd294163103d73e23c04d74f0c72de1d2b86e09d27b360db752631205422657c134135b5b85f781341548886d177c2c62abfd9562d28a1c40ddcbcda071b65b514d742124918d2d2d505856765ceb7ccd882929734d122cf1003251c80dbf6db9dbcb6213b2a4678fc3fb73c5fcb89f3278476989f98d2f336baef3d1bf1cb321079ac35c7ca19c536e01a385513e32f270e5757995bd2eee67d1cfcdc604a14d442d39b6eea8ab1d70387b47944bd15f60981482e1e11d7d42e7a61f6909b62e170ab5ea24de56c6cb7f3ea071ff0953be3fbc84301c24434f62b2bb9800759a5d270d1a3dc73fc98f6985ce5f4b9626c5f2a2204d0f2d5840b46d4703324623d8b5eb1db08816952f5202900a2b5a1a62b15912304e2448d55ca7cd0cc57d31d4282ff256d45cbabd1f9d58651c2c1af61cbcc8aaf8228a4611eefd1722bca1935c379149bab6e9db6538106ef18fe7c2a5d366777c1317e7ca505579cc3ca99a2936009d4a7b4e84d964700fe400c35a305adf87a615167ecc73f685922dabc170a798f28c72303214b5759f6ae79395df3a27e5da2208bbdb8a9609887a4ab859edf8a02b48e4f114b37e2b5b9c01f5fc29a6e9fb0acf253763440a59ceeb34e77a267b90a27ea86b1a1c952db48307922c7b27401b57f798520c64e593bc220c5878dddb9b6661b103f685c113e0d44cd9c348bd015380a937b6060e9da216f8c2edfabd500e1a9020961c4f28d08fcee20d60eb0750a46ce2d4c8877cf81fdee89df6aa7a338faf65fe598f905d82b0edc2fac50ad66950c554c77875481d19c52419684f30ee8aa0906d2482e02bd69672399a14134c8aad90b4614487784ee14c2f6da543d19ade5cc0cb80252396b74bf07c027e93ca5bacfe6f64f9f7d409e5a987d65aa49419a058eec16bec19c1bc37b921c9bc0c5ef210f64c2e31e91d12d5b83da0d2bf56f9dad7ce8bf23407e81beb1aaaedd527cb8ef7964e0fa61d5f7a9f403125bc25a6c066fc6a36b26650acdc1bcafadc2d267a4526fd294bbf2cdd5040f86da7c9929b98de06d0ceb8dc53dd182e5b4eb0c2385de9d9bb7ee758e187aa21611793e9e27bd994988d9d9389bb2c39cfd59a4635e8ccccd6da21b99234d31fb10dd2904f29d6645ed160584cfc","aggregatedProverVersion":"3.0.0","aggregatedVerifierIndex":0,"aggregatedProofPublicInput":"0x0fe1ef2bbc51ac7b6a60b74ab010168ff75c9f752acf5aea8642b2e9cb1582e2","dataHashes":["0x01a4531284372a882e18672608435a88af99893b303a0238bbe3f8c95d44e18e"],"dataParentHash":"0x011c205cb61ad36b464d88916e02f3979b79b042c8cab3658900d36046c4aaf1","parentStateRootHash":"0x0fbfde9208962103fca09983aa7a7692edf9a9db2376cfcb92f6b4ad19bda51f","parentAggregationLastBlockTimestamp":1736794225,"lastFinalizedBlockNumber":25,"finalTimestamp":1736794242,"finalBlockNumber":28,"l1RollingHash":"0x0000000000000000000000000000000000000000000000000000000000000000","l1RollingHashMessageNumber":0,"l2MerkleRoots":[],"l2MerkleTreesDepth":5,"l2MessagingBlocksOffsets":"0x"} diff --git a/testdata/coordinator/prover/v3/aggregation/responses/29-31-411b174b8760f03354ec0ae215a6caae21472b0788600ab1df3d6da896186a1e-getZkAggregatedProof.json b/testdata/coordinator/prover/v3/aggregation/responses/29-31-411b174b8760f03354ec0ae215a6caae21472b0788600ab1df3d6da896186a1e-getZkAggregatedProof.json new file mode 100644 index 000000000..9284f2541 --- /dev/null +++ b/testdata/coordinator/prover/v3/aggregation/responses/29-31-411b174b8760f03354ec0ae215a6caae21472b0788600ab1df3d6da896186a1e-getZkAggregatedProof.json @@ -0,0 +1 @@ +{"finalShnarf":"0x0602578e3a61f2be5afdd3ee34c6ac99e1e36a50450c75ef9dd78e50dddd3f8c","parentAggregationFinalShnarf":"0x06851ec1f1ba875ffd3a08fa5b2f0d88ac9426c9ccd852973abe73bd9afc921d","aggregatedProof":"0x09d7081d343e34b72625a7fcd1467d939e8b421e8330d804b9582bb55f1a859716fdb1e4882a40b10b8fdb58170506537a187e0334f95a387a05d708d36d450c0c98c42d5af3fe6689df96ce786c52242d8b7dcd062c1a35f9cc5875605723b10a7625accfce23bf5a3f5216966f2e93c2c2c6e90a7b608a546e73676097af8e2b3381194d8f2b24c1e628850a885ca9194ba531b2f7e03a241b6b0b11dd82db159452fae5cb3fef9baed07e7736c31112c7c6cff5c7dfbd3aa112d3bc99adce1e930d16eaf0d07ada518d829275e9537c977af6fab33fe6a76bd2b42696d6a9235201371f53bbbca9040333bd42d0921377861a53dc0f702491e3f3870ae9eb2956f6000f9ea8464c0fbac8f922fb9819eaf65658e8a655842e1832b24001802cd356a9f0195f64a5a7a189d86832de8844297d2bbebc9ab54576911c0c0dd31fc7329218557a228a0e15e43c1a225f1a73eeaeb0514163d2c7198fdbe4794614f72b106154eecfdeffb289b94583c0bf890bbc76566dd6f1c319ebe210897a04dc786a2e850b024f842a2912a1381aa153b91e9a463d8207bdfdca25b39628266cff483901cdc3625b3a333516008465c86a49bf840e10468c3cae4b52f27c12d9bd1416190ca6221a44832d39c9b38a2a40606956f25cd7f47595e7f4ff9904c921115780c45ec485e90f3fe446befc56bc4bb486ca2f74281457ddffc1780931f5876f2ffaea03fdb79082ebc598f07969cc0bafcaf273f06617633de8ac0cf40a7e354ceccb69b9720d075d55669efaaa85fda62b7089e3aa57c832c8852142a10920cdd642834aacb041a7af735092860e9a8f00fe3407ce95f8db327e0b6eb3e1b7d5f518631c5027556191fb6f7600183cd729a19d1a1559e9b560520b471ed25a176d811d3c62369492bbd31927325cd4cb76bdf1ff9ac6739916f411b2bb1d16a629a782d8c108b87c46894f745cee40483ca9af47b9f506e518851f3d81d54dd38213aa0145fabcddf1b17bf84b61af3d62e56413eeb2f6a3ab3002a81a95dc9b09299b4a09930159f5f2cfcc9b89b04578aa0aea6c0cc6a5065e1859dfd5febc12c79eb301dafa2ee6627e14f72a23e832814a924096f387865707b5fa41d04663ef43bafcaaf14e82966c04958ac03b169ccb50e3aba2822f8d1b0fe4fea81b4024ed435fc006f7607c4033c1cee780891b2393c23e7700b694","aggregatedProverVersion":"3.0.0","aggregatedVerifierIndex":0,"aggregatedProofPublicInput":"0x18ebcb749b91d7ce895bdf0e4918426e4b417a47fe1c39a84dbd02e3b086d8e2","dataHashes":["0x01354941e62722510ef8c530586b3f4edff05009634df244e6df56f131ff1c13"],"dataParentHash":"0x01a4531284372a882e18672608435a88af99893b303a0238bbe3f8c95d44e18e","parentStateRootHash":"0x04e223e961d59de5d0cd6ecf9d78359cc9d72b4261d851557b1e974d90b71a7e","parentAggregationLastBlockTimestamp":1736794242,"lastFinalizedBlockNumber":28,"finalTimestamp":1736794254,"finalBlockNumber":31,"l1RollingHash":"0x0000000000000000000000000000000000000000000000000000000000000000","l1RollingHashMessageNumber":0,"l2MerkleRoots":[],"l2MerkleTreesDepth":5,"l2MessagingBlocksOffsets":"0x"} diff --git a/testdata/coordinator/prover/v3/aggregation/responses/32-34-bb1a9a83d812c5a46ade32842936de46f693f72c2a2f314abfb166d316bd4825-getZkAggregatedProof.json b/testdata/coordinator/prover/v3/aggregation/responses/32-34-bb1a9a83d812c5a46ade32842936de46f693f72c2a2f314abfb166d316bd4825-getZkAggregatedProof.json new file mode 100644 index 000000000..f44d82484 --- /dev/null +++ b/testdata/coordinator/prover/v3/aggregation/responses/32-34-bb1a9a83d812c5a46ade32842936de46f693f72c2a2f314abfb166d316bd4825-getZkAggregatedProof.json @@ -0,0 +1 @@ +{"finalShnarf":"0xa646621c48d374488e214c7e02a64d431ae0712f3bc817a3d5943914f2246831","parentAggregationFinalShnarf":"0x0602578e3a61f2be5afdd3ee34c6ac99e1e36a50450c75ef9dd78e50dddd3f8c","aggregatedProof":"0x292cffd9adba0c6c620307cc9ecc73f82b1145c7b4dda6ad9571ffabe508163b2a48791c59a6f3be9ef5b8081ac4f3d0df27b24443e74a3e7d734d12d8db756b245cf38abd47a4b10194fddc77f0be5921ed80d39eeb7f34b9d0d7adf575b1f81e8f1c6bec4b53b463e045e2bacd4f263d783c659d5fa2c228cb3cb15bdfb41725db2349b3ff2b4211ce2b3158e0c3a8380abada7d499a474f403dd3d75f99431a9c3b348808ff4a474fb9aa39b6fbbbafe85bc7b01429b9532e07ad01256ea8018b7f0f4f9c1571b86bfc925fe1de5dbb2d97f805ce0eb69079d4a7cf2dcf0401279e091d49bdf561d116f314caa6ea3af47c079cc8cc94432cfa1b3813a73005712ae6eb91f71ed735f39dbf5b60ef0058839e52bfe92b94d0871b55f32d132c11ade6f64323d152c89f0feb72bd202ad6aafe77746de1b3fe8e59e93860321f10e34ef795ec95583917a785a1e9b0eb8f97004f615bb5235955bce5a4759d2f218b537fed347bcee906eed072e2ead100f9dbd82f6cff77895a4012f021851d42cd1bd649b135ea7ef3dba5b673fe11f513f1d5e55cf514c8d4a1125f1071161aa9eeeec25a5a3d684d57b2672f3dc9584fd8ae090722831198e2555c739b20193779350f37872329e9723b795c5f1504a4430f8c1dc7179bdd0d94a59aa816ce5d9ee96ac246433e398cbc5c2338f9adce47166696aa38728c08d3dd01bc1df23063b23262c5ad07fc5ef6f23bad8b73301837aac53bee13bce935aecde3138c9af5bc32df2c09f1d24aa275f22ac44239ab4b5052044e8bcb69644b8a722233446e7242ef814a0aa1aa672f8d61459eaf6251fe8e092bf7a1c7b3105c3c24380aa842a350fb22719e0f92070e0fbafcc97845585dc5e5f83e95b5cb4c7729207b5bc399275612d938f8d17e7319de2010698a7eb286c26f91cbf105164f1edc0d2ecdb45e42803a34e09deee47af1a3754564f7e215d77ad44876029296168d43eb8c5d512aa94ca5ea8114904ef35a4c3850142994a380b7e07283d7d31190873bd4cf92a4d65bbb48171ccbf13b67aaf10eff78ab91a680fa47e348612ae9ed63d724488def59ce75d0e20a50caf8a9b646e0f95c03dfe6b98969467f0122dffaa4b62c2d3e900ba0de391571fae50ee2b1d647c0c29f3b52d3c83f6c1d77b372b1c88a8e82145aa301a82fd047fd9c9b2af83b963105cf90172c1022","aggregatedProverVersion":"3.0.0","aggregatedVerifierIndex":0,"aggregatedProofPublicInput":"0x27e6fca8713c6726033112459e10d773e7f07e04074091a34eb7a8eaf22d6591","dataHashes":["0x011531090261c2af287fb3f766eb58a8a11ec7fb958560efce58f8ec03e24e5d"],"dataParentHash":"0x01354941e62722510ef8c530586b3f4edff05009634df244e6df56f131ff1c13","parentStateRootHash":"0x072c29b2166fcbd110ef1648d38131ac98044e8f53516b2853289f6d615e74df","parentAggregationLastBlockTimestamp":1736794254,"lastFinalizedBlockNumber":31,"finalTimestamp":1736794266,"finalBlockNumber":34,"l1RollingHash":"0x0000000000000000000000000000000000000000000000000000000000000000","l1RollingHashMessageNumber":0,"l2MerkleRoots":[],"l2MerkleTreesDepth":5,"l2MessagingBlocksOffsets":"0x"} diff --git a/testdata/coordinator/prover/v3/aggregation/responses/35-37-061a9f803c029a06b7b594602ea76d6cf6d9737c25ee5215759ffca6bd3fed3c-getZkAggregatedProof.json b/testdata/coordinator/prover/v3/aggregation/responses/35-37-061a9f803c029a06b7b594602ea76d6cf6d9737c25ee5215759ffca6bd3fed3c-getZkAggregatedProof.json new file mode 100644 index 000000000..ac12a83c4 --- /dev/null +++ b/testdata/coordinator/prover/v3/aggregation/responses/35-37-061a9f803c029a06b7b594602ea76d6cf6d9737c25ee5215759ffca6bd3fed3c-getZkAggregatedProof.json @@ -0,0 +1 @@ +{"finalShnarf":"0x86dc4abc4be5dfa0ddf8f4b8b98783973bbcd82b5ceff8d39361fe151d4e2ee8","parentAggregationFinalShnarf":"0xa646621c48d374488e214c7e02a64d431ae0712f3bc817a3d5943914f2246831","aggregatedProof":"0x2ca28db6085342c26fd36420faf5af7e76f4acf70b96594e20c746f1866dd5792c06c96302255c358686cc3588fe5521e74308d5b3f914efa4ca89994631333411dbf4c113cc8e457d6e50db476ae4217eecbe5a5d5b37b88160e9544b68f8720bbf6ce9863b10c804c6f1d142c8a9c254980b0e4a6a957435acc6d48e10f60f28cf5fb85398d402a05bc026f93f6f51d58394e91a6e0b8c45a156d2dc645bc605997c0d93bfcc0489484ac438ff61e8289a84621a578fe1e23bd848c13e9ca018a753947c0dfd887e8b31f32bcb47bd0192e111f5de1c7e5e584db0b2382f3313adb486e06b1f52fbfd3160e47d9a48deb39caeb9694d788bd141c3913b14ef1531238e239313ddb0cdc2ab4209ab8f8ce1c7a2d21c89c74e0a96a00f57863c2e8852f2aa7831dc98cafed6d3bf01595b1b7c4ea2fcd5f1b93f35117a4b25b807fc3a646c03292509f83c84b83d3c9db655c03b9e0e5a7da17efe6ca57e3a0b0a5c5cc8285480d482cb65b82974924e8185d36c205b0d72f2908367b1d6ae7824b8a6311b900b6ef84bae250687838aed4bbda3a0c74f07e4c768c57e40cbe92dce5b863f0b5f484ff6c61ee345229de68cd14b3f624ebf2b6099135b8b15a12cac27d976ddb668d023a1956942abdd38c6d01af2a88cabeefc7ff1c403cfe5021a8f3383d310a0bf62d337ad66dd335a087509104a3599c6c55289f030325812c2b281eb79c62088343d5d2356873a3e20e11597456843e716e5012ee86f1b28c71403cfb7a7b82166bcd5233e52a6141447fabb7dfb2c58241156465e36e40f780c48e21a386417f97963304a81cf40f6cc1b2a9e4a360e2fcd6339cb64cb1c5dbe820e73f284b8cd9b2360d17702b952a304cc44ecd4d1c10b4034bd40ad212193fd4a8df15462c52bcade6231d9ad9fbbd1590891c1f20248762ac6189b05b680e2b70601f851ef92aae1e728eb391311c19a0c63fcee4e01f7ee3aebb508fe09a3736d1bb3abc58405491b0c5ae9f64a76a7cd402ea84d97b3a652c0350258e4254cdb32b7913f60f03eef7816c4b9e35e818672fd81ec648092f58f3e150250fdf14d5ea7619e31081906071eabdbf55400852a11272bf9dd2f407d871ff2e8be8ee31775f9f29fa4f369767eef6ba1f5a4f90fbfa196bc12720838ac031613863116f3b71be0826fe1ce4f38e6d51123750c4513388dda54f922eb07","aggregatedProverVersion":"3.0.0","aggregatedVerifierIndex":0,"aggregatedProofPublicInput":"0x053797ffdd18091275a9f9908330cc33cbc722ea90b8930747d067d10f17e27e","dataHashes":["0x010f6596abf90a103c9558772f56e652de5ea08805763035539bf14bf3c23674"],"dataParentHash":"0x011531090261c2af287fb3f766eb58a8a11ec7fb958560efce58f8ec03e24e5d","parentStateRootHash":"0x10556468275a46e1261bd2af01c421e81af255ab49f932de2b6352de9648727c","parentAggregationLastBlockTimestamp":1736794266,"lastFinalizedBlockNumber":34,"finalTimestamp":1736794279,"finalBlockNumber":37,"l1RollingHash":"0x0000000000000000000000000000000000000000000000000000000000000000","l1RollingHashMessageNumber":0,"l2MerkleRoots":[],"l2MerkleTreesDepth":5,"l2MessagingBlocksOffsets":"0x"} diff --git a/testdata/coordinator/prover/v3/aggregation/responses/38-40-5239c241ba71475fe11f8a4dfc04addf97c874a9bc2a371bb9cf5bc245e8982c-getZkAggregatedProof.json b/testdata/coordinator/prover/v3/aggregation/responses/38-40-5239c241ba71475fe11f8a4dfc04addf97c874a9bc2a371bb9cf5bc245e8982c-getZkAggregatedProof.json new file mode 100644 index 000000000..0829d20a0 --- /dev/null +++ b/testdata/coordinator/prover/v3/aggregation/responses/38-40-5239c241ba71475fe11f8a4dfc04addf97c874a9bc2a371bb9cf5bc245e8982c-getZkAggregatedProof.json @@ -0,0 +1 @@ +{"finalShnarf":"0xdec8e24af04a4aa184d63b3f68066b7633c2099aa042bcb37a234c5ce4210446","parentAggregationFinalShnarf":"0x86dc4abc4be5dfa0ddf8f4b8b98783973bbcd82b5ceff8d39361fe151d4e2ee8","aggregatedProof":"0x012978630474a98823d9eb9f165797a0b518d793496de832df09c51778b0509b0c3ba8f4102be732222728aaa2635bd44bbc263d03e9f016faffb8f259ef65062a503a7598dc0205098f1192561aef621c7e79533fb4c24316bf63f6909b18ea098afb81a29b9f3ea20e9a5e8bff2577e2dfa4df140d93078b44ce04cf88cb85178bb1469125eb39e1bcf98d13e272af54ad38ee0665aa8ea561555487ea1b4d099e24a19b7cc9b33319404d2b3067dcc75ed8c9f03a69ddbce4d39dd82699cc07da34d0713745650b39d6d8b8e00a42e6116cff5258db1de3c8cf9f26b535740ecac7087f424bbc7019d0ea5ee84db01da7bee0c9400d571d4b965c44c604cc0aafc7577c97601feb92710c7775a45707171aa7806f0b539e4bc6c26e3e2e7715f85f2a8259d665e2eb2b43235005f131ef2d8bbb3a472e8678cf794ae1ae202d216aae6c5a671037b5ea9e176ddbfcd99b59f0758e367fe3f913b21afa6b971a404e07882eb5de48326e75f3c80c542eb85a44453d42602df8c9d4ebc7f2fa10583da9fa476a4f01bd3753033f09267b2a13ccd28f1baece9467fffd8db9692805238235658f6c563f837082b138df503e60d16de215eba48fd7d3fdf235350f2bfb9b9d2faa3c9cdcb06f93e4f2eb53f51f2824c3f763e1e42c746096099e25539f43171360f9e167b9122c82bf811601db0c94440051c2350cb873179ea017831807a53e02ae2425a93e8712e72c4113505cd8b50d10c44eee0cd73091df16ad876a29ebd477bf64757a1b046a7d559c391ddaf96a328dd7807110425a7826e4f5558284bc6a8b9dc2054132bfa18ed38851d2d66dea6fa3b73b24b64b420013dca57de8130010f05c857b6cfc397ed3ca4bb516d14a5ea373e6c563c9cb276ca6e8e572c5251c2c81d736296892e01516e76bc5e4c21a9927ae180654cd148a6e1ad2dc35b3ac924adc9e3cea6f9e16535704651522dfeaa0b702de4a7e017ae2f22541f57ef77fafd89da642c9b087707d765e81f9ef0f4af9dc3177530e1354f1abc8cb04f2a660d41ed6dea9436e16e8528d52990c067ea88f32afdb1cc9229896b3410bb102ff8032dcdd4b259c6d9da82d8c3e93de3f4b162603b1096a240cb2100f814b30517ccb185ac7a05a7016d3453609677299fc77de209e25fdf7314c6c3e04a0cd92abe0475172944eef0f192a6c51ad06964485daf9f6","aggregatedProverVersion":"3.0.0","aggregatedVerifierIndex":0,"aggregatedProofPublicInput":"0x2de8094ed9b3da7a987ee1e073ed58e77068cf8cb0e37750ad3d0e8fd433efa1","dataHashes":["0x01e5edb2951948f86cc72f924c12e14428625fdd76461f50ffb63b71b0b673f6"],"dataParentHash":"0x010f6596abf90a103c9558772f56e652de5ea08805763035539bf14bf3c23674","parentStateRootHash":"0x038f427f164b4cbd3733505c5853d245d3ae4c25dc69716762f2f7f7df68be1f","parentAggregationLastBlockTimestamp":1736794279,"lastFinalizedBlockNumber":37,"finalTimestamp":1736794291,"finalBlockNumber":40,"l1RollingHash":"0x0000000000000000000000000000000000000000000000000000000000000000","l1RollingHashMessageNumber":0,"l2MerkleRoots":[],"l2MerkleTreesDepth":5,"l2MessagingBlocksOffsets":"0x"} diff --git a/testdata/coordinator/prover/v3/aggregation/responses/4-6-ef72701818f1320dce22734cac21e65af315dd84dbb57e4ad7ecf32710e3be87-getZkAggregatedProof.json b/testdata/coordinator/prover/v3/aggregation/responses/4-6-ef72701818f1320dce22734cac21e65af315dd84dbb57e4ad7ecf32710e3be87-getZkAggregatedProof.json new file mode 100644 index 000000000..3e3b92c47 --- /dev/null +++ b/testdata/coordinator/prover/v3/aggregation/responses/4-6-ef72701818f1320dce22734cac21e65af315dd84dbb57e4ad7ecf32710e3be87-getZkAggregatedProof.json @@ -0,0 +1 @@ +{"finalShnarf":"0x513ed85de5604294e15b683fb22532c07a25531d93f402f17bb4a4c83a91b025","parentAggregationFinalShnarf":"0xc185fbadf462de3a6c8517cbac3ba7402a14e939e1d77e3a515ca1c8a3f7d977","aggregatedProof":"0x19d0580bad76cddfce2897b579eddcc0b8203edb780be7b2f8db5c6d74644705132ae2b20a43f094f626c5213c4a1a11ced30cc296f74a85d32d42096ff473bb08d718ccc85010f9b422f23c89793923d47b0265c01d1b803715d185be7ff83522f0efbec29ff46ffcb72bed8663c0224e2a64e0ccea3ea4c13f9592f2d3fb0e002a17ac7d0b55c99718fa92dae918f914162e2ea45851e9f9e88c2737cee0250ee3c732f2033ae55ef0eb48928ce1adbc6b5a45f69965bcb198b69cb1018e300c66c6b7e5d3a5478a21c6781c8216495c80f3615e4f5fc5d3e37336ef0a98e123aa96727f7d09d983e0565adae02c9b5870c9d3d8a0e91b62e401ae55b5b0781c88bae9a8c091e5fddffedf9a83127b8f39493f2b97793dddacf472599d0e0c1ef12f2934fe72313c75775290728cc6d96493c458936e4b5a07f61b46f4314a051e943f372237476bc8ac7c79b1282a3a39af51f1e4b7fc101844149f46b2c02e005fb1befe07d79fefbcf4b307ec82d229da5b090db06096dffd8fe2bb6122285dc15f3d4ee627144108463a79bff113a58c89fa5f761663c98c1fce79e3402d431c36487c89b7cb0f28b83b71e9dae7cbc88da2d62bbf41f7ea6e44551aa624dc31eadaed177546262e83f00dc26d132518d1486d4c18c4f98d888335f3a42a7c73d14308b055caaf9685b8d4190b1b6092df8bfceddf726b301df5d819290c3416108501ebb13e5ca4d505d57d70392b559930289f4e4a7eed594b51f009250664df85d2f1f56b470fa43c6371294977bd1ce3ae466fe6240f411d8c1a042f51ecdf1f41263ba6a1b2be7695778dff9cff2c286711c196132784172f8bae23237f97758f88f5d33e8cf0c683acdc98f9b964d87072f9141d6c12ae4b48f411fec567799c4cd66c3ead5c1101ba5b0245b2b4e98a2bae57eb94cda11348c3285c9ed2d2d79bc964b4f728bef44b77cd8d0641327fa02f32a9ccbd51ad0ee22759846cb21754127ce418ad002b50888faf98cec40c34bd8fd2eccbd4c2abd70dbba5e33b690e9885698392a14cd5e72441be30acab51ac44a877f17de935d4083226283fb9e2aee207b5b1a20c0cb1f1ae4a6e7925f90d28422b08dc0e7c621490a2d62405477aa6ef529974b0a17eaba14b5376ff024de2f138ce414b7efe064d2fe347808144269af789f722c595aeae47824d8745863218e00d40f9352d","aggregatedProverVersion":"3.0.0","aggregatedVerifierIndex":0,"aggregatedProofPublicInput":"0x10f7aa7664c725eee6b7ae95d93afd41a5907e7689fcef803bedfedad7df8713","dataHashes":["0x01201000a6593e1362c41814298d3cefae56c41fb2726051d0d7638e355b5b15"],"dataParentHash":"0x01f48456f10caa5029fed9b89cc5d2b3853af3a1b76f0deae6ebb5a2dd1e9ea2","parentStateRootHash":"0x12992d60a0ff80d1c2089da74125c185a3bedafb1ff68e26e0cbfcbd9055b1f6","parentAggregationLastBlockTimestamp":1736794040,"lastFinalizedBlockNumber":3,"finalTimestamp":1736794054,"finalBlockNumber":6,"l1RollingHash":"0x0000000000000000000000000000000000000000000000000000000000000000","l1RollingHashMessageNumber":0,"l2MerkleRoots":[],"l2MerkleTreesDepth":5,"l2MessagingBlocksOffsets":"0x"} diff --git a/testdata/coordinator/prover/v3/aggregation/responses/41-43-c9a80177215ac57e589cf92189846270b286b70bd3845e8ed6f19734f5e0c88c-getZkAggregatedProof.json b/testdata/coordinator/prover/v3/aggregation/responses/41-43-c9a80177215ac57e589cf92189846270b286b70bd3845e8ed6f19734f5e0c88c-getZkAggregatedProof.json new file mode 100644 index 000000000..3bc8a653b --- /dev/null +++ b/testdata/coordinator/prover/v3/aggregation/responses/41-43-c9a80177215ac57e589cf92189846270b286b70bd3845e8ed6f19734f5e0c88c-getZkAggregatedProof.json @@ -0,0 +1 @@ +{"finalShnarf":"0x67b48d2e3c30f21caaffe8677e9c8a84f43ae1e7ee936f0f8c03c4941cf04695","parentAggregationFinalShnarf":"0xdec8e24af04a4aa184d63b3f68066b7633c2099aa042bcb37a234c5ce4210446","aggregatedProof":"0x2ec26cbe5e5ac9ca8fd8323c06aafb4f336f70460fc45cce70ff32436dd34f2e129af567eea63ba4290d0620d7f5b7775a261f631dc1877b84f7523285752e712f3e25560852a51fb322a9c2cdff1dd99c674d57439e5c96ac99aaba53eae7e208172a8e99c0f64cb916bb7b6d7e06a92be3a6924e43f30b66673a89543def30297ccd6de4bfd5db27528aab784841e0d742dd0ddeefb4c99622f255fa2aa92b2dbe36b718ffeec0a0498b4fd1dad7a4e425b0cd1fffc1286ead7fde67a78b16246af810973fc135004c256061438e856be47b709b93bc5394848e47c8e68d2c280648e0a642390afb12b0f36fe62d05ea952c6e7e8e0750fc4bfb2af12d3fae0f5cbeb6712f7fff9e4549a595b9841e58ef711e66ccb90321b2beae66feb4f51dc86d10042a1b30e7dc3cdfe3fbf0e22a44026be85a52027d4144c806c8876b14595cb7c9468391a10d3ce68ca33c41764e23d3481aa50a02cea104b7d82b5f218cd1bce8f9148e86582fec9ef799316ea04a2bde1d683646186a1efa10cb3c0b10ef46e9cc38459a3dadbd5431756a3a81095793a9e3169c8e0f75471c39610953713c58406902349b893e8cd680a3a2bfa183892930ea65066f934d31c6990572a0dfb751bc6aaa32061eb9142bed0e12226a9d7e1d0ffd986ae29a3df502045451021cfd8002e2c043418257468c3e1d3d8ff8fbdf553aa688c6feb9365902e5cd8a598ba5771f3853f2162003970c663af3251a971eaeb861fd329127aa0a46e316f196e9511adfe24457ea884ed48997dadbcabea908bbde0c9e1be95a18dfb5b8201b73f7a4373054113afe4ecda6f2d415af070b806f225f060354580755c563f70017dff15fd33f432ca55cca655dba91e6c72ddaef8ec5e6995a691d854f5d682860e4bbc9869bc3fb643af7ce5713d194677f4163169d86b71b2f1ef6c7653adec557a61bb1bacea00f9ed2171f901142f0582cddfc7a4291bd19003fcdee51c107e9c9f566ed4c64383fb3f0bc6aefd55948aa2f3a4b3fa9c86f2d5c73dceefc8ee337e7d1f6be60ed0c368f7251a9e49395e7f608b201f5273c235414acf1af6421cb08a277e2c51c85a285d2cd9e43a4ecbe5585f742658b4d2156b98441eea33d67ac76fbc1111ce2f95d9990e55f4d01e0e8a84c27ba79131fdc5e72cf9e1e7887edbdf5b77da58febb91100b085d107526828563177c0d5","aggregatedProverVersion":"3.0.0","aggregatedVerifierIndex":0,"aggregatedProofPublicInput":"0x1a7c84f1562fff23d3193e5d81f8b0968509da6bd9b6e3af4ef664f3b15b46d5","dataHashes":["0x01ab0956525f99b22c1ecaf9757afba9cc8e88b55e1e56385cb4f8bfeb986e78"],"dataParentHash":"0x01e5edb2951948f86cc72f924c12e14428625fdd76461f50ffb63b71b0b673f6","parentStateRootHash":"0x086b0a16469f68533a059d3dac85f21d2efaaff0da66110093f85b08623b2cbe","parentAggregationLastBlockTimestamp":1736794291,"lastFinalizedBlockNumber":40,"finalTimestamp":1736794303,"finalBlockNumber":43,"l1RollingHash":"0x0000000000000000000000000000000000000000000000000000000000000000","l1RollingHashMessageNumber":0,"l2MerkleRoots":[],"l2MerkleTreesDepth":5,"l2MessagingBlocksOffsets":"0x"} diff --git a/testdata/coordinator/prover/v3/aggregation/responses/44-46-78d88bad483bfe5a8f9e8fd1d3af3cb034d6248aa279b764b63279b2ba7f0f2c-getZkAggregatedProof.json b/testdata/coordinator/prover/v3/aggregation/responses/44-46-78d88bad483bfe5a8f9e8fd1d3af3cb034d6248aa279b764b63279b2ba7f0f2c-getZkAggregatedProof.json new file mode 100644 index 000000000..58bbc15e4 --- /dev/null +++ b/testdata/coordinator/prover/v3/aggregation/responses/44-46-78d88bad483bfe5a8f9e8fd1d3af3cb034d6248aa279b764b63279b2ba7f0f2c-getZkAggregatedProof.json @@ -0,0 +1 @@ +{"finalShnarf":"0xe3c210adb4a5b495db0a285094885c32b74bd6cc85bbe0e0b5a6cdf7e88387da","parentAggregationFinalShnarf":"0x67b48d2e3c30f21caaffe8677e9c8a84f43ae1e7ee936f0f8c03c4941cf04695","aggregatedProof":"0x1e7f1846e16c463f98d4d25e626bc6254c71ef92704550c762a894e2c8e57c2e2fa530d1e14067cde9b64fa5515de47c88528dfe93c18574991103110580779a1a3c8470218c78d7e0a56049b83cb5be156420dc10eb81414fa69dbedec3418424a081ae820def89970f88beb1e90e2553345a3c9a0a76b8720e28602f2cee940822672b20e3c204eda01a21aae03090f3130a66f10ff01cc524b8cb2c8ced2823c1c9bf3618564e0231b649bf846ee957e8b7a938dba700c5b09c7f8a6ecc430a670dcb8793ec4cb8cd326d2eab2716e333db502b44bc658809b11760279c6512c579f7c7a544d93805726f972092f24024a96294b2dd5c670e3a87d206c43712d27249faf0c2d087feb33a555cd6e1024e0fcf0a947ea7c5190e71d01c7036150994bd5f05d34db23dc3258e1ddac410103fd0045de727cf878008a9da862c2cf5c8c7d9e3b4f43bbb933febbcd83b5791a94c03ec71bdfdf9021ae3a1fdb82dd045afcd8adb4717963499ddac256836ae1f41867f2bb409d1998f7aab38a41af061a3f68c2f3f2bd0f55ccec9cebe5d3a011c71ca37b199b35b8abe4d3a2e3021cdc723f662ffb0aab12ad24c3f8fa9896cdfc495d9bb30fdf7d1d90d4bd505defb134e3eea6975b646890f8b055c198c28a72643b81748305b60a187c86000ff03008c5ddff59d270365aa90fc8bb9ca7d19236058e5fba0f3ed121957980e9918549d2342112e5d97d5811046bfa9dbbaf05961df232f2479701291e99e25bbf8d40bdee3fae594e276b56ae846ff04e505fce0b953622c2dc3edb3915d1ba57594a5e9a6a27ff160c17e0434858106ed030c953a742271e6d40fdf0d4d1b288195e45fc83416e3a64d554309e41654caa70c305f755477c00c2e6419531513e2b7828261ff1c060801af7902bb2c1f01f3b43e5788d7be23e8fa4e708e2d3903d846ac3e4fafb41896a548234f6f97921258a5fe89c1f6a235794f02ba219f6f23be3dbfbdceb63b75a96ed48243e26dade74e45393468931217a684f9180ac99fd093d95e0b906562122a2dfd268df0f7aed59a5aab2b68199e8e86221d970011a9d5d3001a9c57a0e2f2f393a664ae4692cb58fdd63515b910ada28e0a9e46eef84918a99b8b121126c4d527ce032736c87ee8971ede96ddf08b9a571ca25dd8f12356956c42c4ee29dd3b72396f43e0cd542b9ab8d0568d2bc7e96a","aggregatedProverVersion":"3.0.0","aggregatedVerifierIndex":0,"aggregatedProofPublicInput":"0x28aa01349a5542c4ab615233d756d5f472b283718c25619ee4d16bfd1d28267c","dataHashes":["0x0104998034ee589f662c8b801b219074675af50a522d9281f23e4ff8aea8df53"],"dataParentHash":"0x01ab0956525f99b22c1ecaf9757afba9cc8e88b55e1e56385cb4f8bfeb986e78","parentStateRootHash":"0x021f2681f4ce68e3b9f77c934ec0599899cfc96c873e6a9a7450e95c5de230b0","parentAggregationLastBlockTimestamp":1736794303,"lastFinalizedBlockNumber":43,"finalTimestamp":1736794316,"finalBlockNumber":46,"l1RollingHash":"0x0000000000000000000000000000000000000000000000000000000000000000","l1RollingHashMessageNumber":0,"l2MerkleRoots":[],"l2MerkleTreesDepth":5,"l2MessagingBlocksOffsets":"0x"} diff --git a/testdata/coordinator/prover/v3/aggregation/responses/7-7-aa133bea94f49f4edbfe7488b1a7394ed2559243139ca15097356d8baedc3e65-getZkAggregatedProof.json b/testdata/coordinator/prover/v3/aggregation/responses/7-7-aa133bea94f49f4edbfe7488b1a7394ed2559243139ca15097356d8baedc3e65-getZkAggregatedProof.json new file mode 100644 index 000000000..010fc59f6 --- /dev/null +++ b/testdata/coordinator/prover/v3/aggregation/responses/7-7-aa133bea94f49f4edbfe7488b1a7394ed2559243139ca15097356d8baedc3e65-getZkAggregatedProof.json @@ -0,0 +1 @@ +{"finalShnarf":"0x7db9a7cbfd21211ecd77d8791894eca4478be04c38002a415dce9eea9a7d39cb","parentAggregationFinalShnarf":"0x513ed85de5604294e15b683fb22532c07a25531d93f402f17bb4a4c83a91b025","aggregatedProof":"0x11a613fe3ad986ab03b5394279e3f1cc534bcb73b30eec6294d6e2273c2318821dec07cd9696aa5f83602e6dedbc4567b633ddd8d06ea7e9cbd81a6893068169126d7b80cf6100b7a532f3b8b513c5907018d9fb8c78a8fb922db80f775cd98f18796404b4ee522dfb6dea766402233414ee07e92df210bbc49583c37d3edebf2e918835cd42c7567786380fbadb285d24b38934efd46d105e2058c2678b531b0beb69fcc6a27a3b2b78140483b99a7a023caae352978d2b95c11e69f833127c23b5f8759f2be89407a9d15418032888f5729149dad85329175b7668dfa298262cac54185ce62346327840ba35c152950f1ba02e65d1fef63a3fd251de3b2de809498d7276b2f3f6b325d3b19bed24a6f8c23311c03cd42b920d64af7d89c37c25f20ce39ce6f105b8e1acf1720c2da8d11e44259d5af4bc7ca7f67ae2d504271eb705791ab3b2c81fd3499f88e96d2bace4fac1848688c9ee13d6e29db42e2a0329f6a61d57463f8fa89a21ca8e5556fcad6d21faa5bd6ae7791ad68c19d2890712fe045387749d1ded0af89820045050f4ed834ef60a9328e3e83e2e6019ff2dfffc9dc41cc712bda9c63c3f7a159f5f188f78f8141fc63d28ace6eceb575908f97a33911e09084fcd77e43eb0915baecd686f20d9c3bf2f729c82b78ceafa17489e9f4629c8bc1884d0ceb0c9836c7177b2d3e15659c9361864a3f6ca252d1f343af1a624cdc8e8b41df9121daa5ad2ea03d2920238a1effe0e3b883c23bf2ee92490ce86c1af69178580bf348c527e1aa781b46b416d11f493178a6de2c0071a180208b4453f102821425645e6bedef9ad4d5b0e67467e88f395176a85f620090404f882095c4dd15ac14de0af0f932acb5a4a640adadfcae8dfed9c48060cca71cb579ae8c83d88d5497507f8fb45c8d3842ae70aae75d139ed7e56ab7418a78b5d2ecded47173de3b9f544d926fc82bc110eda871a3295d2cc10d2baae1a54d166dd2dc77dfc06560b8958e5fc6698b201af666f28c63283493561e4861af86de533b0f2a7c9f1a2434b8f9b37a1201d62d469dba2c146515fc6023586207013e114a2209a6ac98211d2f7c274eb101cee1030d01f0e79a2ed9b2a37081520d216cf5cf257685aefe502102ed3b1f094b682bbb1f0d88ee65c11da6dcc2b3cdcb97ad0aa0e977c9af5a63d273e631a149c9f77e1575704ab7b1db3adc7","aggregatedProverVersion":"3.0.0","aggregatedVerifierIndex":0,"aggregatedProofPublicInput":"0x282e8b4d938c5c94a2eb2ae013ef129866527de5d42dfeba21262d68fb33d9a7","dataHashes":["0x0122ac92a79da67dca1dce1ee4bdc30c4e945e02664463d0924ae3b1b9c96594"],"dataParentHash":"0x01201000a6593e1362c41814298d3cefae56c41fb2726051d0d7638e355b5b15","parentStateRootHash":"0x0f603fc5fdb46043a8a04bab525d7f4d966ee254608468da2fef80dc27f54ba2","parentAggregationLastBlockTimestamp":1736794054,"lastFinalizedBlockNumber":6,"finalTimestamp":1736794059,"finalBlockNumber":7,"l1RollingHash":"0x0000000000000000000000000000000000000000000000000000000000000000","l1RollingHashMessageNumber":0,"l2MerkleRoots":[],"l2MerkleTreesDepth":5,"l2MessagingBlocksOffsets":"0x"} diff --git a/testdata/coordinator/prover/v3/aggregation/responses/8-10-487dc52c1e22d32a1c38917b99ed120ddffdcb5effa6c5ecca536dedd6d4e2ba-getZkAggregatedProof.json b/testdata/coordinator/prover/v3/aggregation/responses/8-10-487dc52c1e22d32a1c38917b99ed120ddffdcb5effa6c5ecca536dedd6d4e2ba-getZkAggregatedProof.json new file mode 100644 index 000000000..2b5f583f7 --- /dev/null +++ b/testdata/coordinator/prover/v3/aggregation/responses/8-10-487dc52c1e22d32a1c38917b99ed120ddffdcb5effa6c5ecca536dedd6d4e2ba-getZkAggregatedProof.json @@ -0,0 +1 @@ +{"finalShnarf":"0xe6a7703511076e3789cc25059b468940b2e91df262f11b95b9005f758482aed7","parentAggregationFinalShnarf":"0x7db9a7cbfd21211ecd77d8791894eca4478be04c38002a415dce9eea9a7d39cb","aggregatedProof":"0x185a68aa302796e41348e6933d26d44598ea5c1b7906d27e33f0724b62f60ac6043397e498ac1ef8d4d3cf79babbeef5b2449807f25949a303d3860b3d145a500cbc3af08d31021977b4074a1bb95e0b4393dee5d05ba624be48895544f15a91092857588f49829b66b4409c9779f2035762cccc89297d5d828d5bd3b6cc1c7d0e05f32d108d9287288bf7bdaa735463f6c3ae2a49c97b625bd6acaa821f9ab51d87c37a708aaa5d99b9cd80a08e059ef6b35dccef70ec7bf7d1e71f58beed6323e6f0e9f0d138a5d1d3eaae293c7f31dae2dd5538d597690e78540e9d30409d0b96cc6ea31bb22df01d6617d9bdd950d8f8cd1b99ca24ec3e15353d161fead308280f7f97e486154433e45d58cd9cc54ec13b9e8ab37492c0a22fbec85d631d10e7d1bd36af81d83b98376de046beb56d66cd420a00006f3c8cc35d5972ef0e1d8c64f54a6649fdab2eb15e0d7c506f4f07fe917134eb176a82cce25a6798bd0680cd5d462b6f9f4c255a54b2a4f6d903dd118c417c3a12baf6575bce8bb55e250fea5af78c05f51b860307c6b8188c9898ff9558b1a90073435a59c87d5bf029d35690facdc7e9da735286a8cebb3304388b1fc0d603f294545740168d332815f56bf9166646ca9501298b13e692949b256d1023b33f09e0757c20adbe82de156b3bcaa59bc245176fe7221ff03f065464c573794b12ab2a3be43141f5f45a209c3b1687f0e6d6da1f814bcbbcdc55a797ca7fd53b07a91608d654da8aee0f2dbd1e43b576a473ecbabb4f850ab53ac2b8ee8e40d998946e1edd5cb00b3a4302074c7b78206ee7abfdbb9ae8add9981bd44bcba14dfcd660921e2cdbe4242b0a7f77d2f5a93e5bda5f34c2a80fc38462fbad7ea1eb3a71fbcf9c90e4b874de2cdb0c75fd324523a73aaa6cc46ee8c95fb9a10a75617741eca1951acdf28482136f85727edc36597dc94935a38478161fe015e806ff6a9531e9c62ce2700090034bcfa77046eb8cb36c180f0860c6632a970851560fc081094635b6fe11feb31a9cf746c5f563b50c9bb70ccebafbdb3e6744e5c71e56211598d3cc2ceb70a9142bfd12d18aa1b6e38d5dac8beff40f9b07d2c4264446261592294166a8112929c1aadc708c11f790f59e44a5dfebb7ba5b1d168818e912c055af9fb8ce2a6821039e47e2671790b57e0ff83f40115c0eb404cef98bc2555e28a5cd5bac82e4","aggregatedProverVersion":"3.0.0","aggregatedVerifierIndex":0,"aggregatedProofPublicInput":"0x1e5331b68e9aff6e2e28103da6f0e98b78f911a05e9e7fc75fbede549e5855b9","dataHashes":["0x01c993ae52495203ab88827c3111fcf3b09c16655c392dbdaac614dc00473c32"],"dataParentHash":"0x0122ac92a79da67dca1dce1ee4bdc30c4e945e02664463d0924ae3b1b9c96594","parentStateRootHash":"0x00e974de2acac404377d2d3856a35cc1dee03cb25af603f111442cf8d8b0c700","parentAggregationLastBlockTimestamp":1736794059,"lastFinalizedBlockNumber":7,"finalTimestamp":1736794163,"finalBlockNumber":10,"l1RollingHash":"0x0000000000000000000000000000000000000000000000000000000000000000","l1RollingHashMessageNumber":0,"l2MerkleRoots":[],"l2MerkleTreesDepth":5,"l2MessagingBlocksOffsets":"0x"} diff --git a/testdata/coordinator/prover/v3/compression/responses/1-3-c185fbadf462de3a6c8517cbac3ba7402a14e939e1d77e3a515ca1c8a3f7d977-getZkBlobCompressionProof.json b/testdata/coordinator/prover/v3/compression/responses/1-3-c185fbadf462de3a6c8517cbac3ba7402a14e939e1d77e3a515ca1c8a3f7d977-getZkBlobCompressionProof.json new file mode 100644 index 000000000..45fda0a72 --- /dev/null +++ b/testdata/coordinator/prover/v3/compression/responses/1-3-c185fbadf462de3a6c8517cbac3ba7402a14e939e1d77e3a515ca1c8a3f7d977-getZkBlobCompressionProof.json @@ -0,0 +1 @@ +{"eip4844Enabled":true,"dataHash":"0x01f48456f10caa5029fed9b89cc5d2b3853af3a1b76f0deae6ebb5a2dd1e9ea2","compressedData":"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","commitment":"0xaa3634bf5a1ab3a4401cdf9461ba8d1c84a1913dec335e4e418aa51cf9e26d29b381d21a3073a89d6b11801a44e888ef","kzgProofContract":"0x97a6a81752725f5d99f018e9009f3a1e00802dc64acc586666c2c12333146b1d4fbcc030baf6f737c461a6e4a2b1a8f2","kzgProofSidecar":"0x8a8fba0fc862d02ecc0d883c51e74b1d215484e61904cedaa0c66d932c5aa07b5c6b938556a6f318645373f090ef8312","expectedX":"0x1549de5963f8c2b408a475ffa96ffc45ef0068f84b2f886fa88c1b421a2919ca","expectedY":"0x1c89bb91b772e4af1180a6b6b4d217f5305467af6729fe4e97e7a37ecd130068","snarkHash":"0x06b99868a5c7e80837668b54a265a6ae43a7877180af885453cd14180838ccb8","conflationOrder":{"startingBlockNumber":1,"upperBoundaries":[3]},"parentStateRootHash":"0x072ead6777750dc20232d1cee8dc9a395c2d350df4bbaa5096c6f59b214dcecd","finalStateRootHash":"0x12992d60a0ff80d1c2089da74125c185a3bedafb1ff68e26e0cbfcbd9055b1f6","parentDataHash":"0x0000000000000000000000000000000000000000000000000000000000000000","expectedShnarf":"0xc185fbadf462de3a6c8517cbac3ba7402a14e939e1d77e3a515ca1c8a3f7d977","prevShnarf":"0x47452a1b9ebadfe02bdd02f580fa1eba17680d57eec968a591644d05d78ee84f","proverVersion":"3.0.0","verifyingKeyShaSum":"0xc4a868954d361bf8c18d4b3699c4fa973a6b2e4543ddea0ce7970d6941f55758","decompressionProof":"0x000fed46812c635ab46cd5d8ba7022612755b2f660ebfe6efe0a34b329431365c94c5d1815ba2e551296952e3bd0e9ca009e2fe1a31ad6bce23e0644d53dfa9120870a86480ea1d86472a74ff971b564e37fa3d47ff995eee73135d81266cc84010662ceca7b4939b740951e44fda074ec818aa2bac1c5bf620ab15d6993d1446bdcaa92e39a308db3350a851839f5420138eccc039c1747df5ee60c12482958d1d3dcd6964bba08229a259e813eb2b8847aa885c8f8ae690fa7bff4517bdd9f012194e6499584bedcb9588d3722ce6f009b49aa82c857cfaaab0455c949a1b4ad434daab555cc2e7ea2fdf2dfa2e4d90176edc3330c412dbabdc275cb31114a17f50ee20ceafa87e9a40c139d7879b40d01588eda1d0870f73b4af594bbc33601810748aa346dc5fd9b255c0e3a76e7847ece5f8c723e7b4271a77a94ba0441fd6c76bfe9e968dccf5209ce44e6291b00f692a4cf30a5c6095965406aeaf2fec15befc02f77757c57b2357a12830dbd7ab076333c5791d066d2eed92fcb287100271e5a429ff8627e4c14e3fcba6da41159742b80c0339fc083114da5d5e5b7b589e6c1281f60e0abcf65f2fce9975c011503bd7e78b99e1271d1364345d038a168f428defb6715ee4a9230e2a2b6d05b771a3ddbe75ff0fe3b2941b1d31fdb00609b959f0b5c935551f4b45fdf1acc122473fc974f406b9e2529241cf1aae5e68a117c8687a70c77225e2ea251b1ed002f27d5360c4df2c88c99aef43e871445e8e3b69788cff30368ec1d0e5848468661b8d98320e6458ddbfebe1192804f0197c3d24eaa3f90ffb300f03f52d303328ea4b434c4650b840a0e583362ae5067340571966d37ef642d71d87a27cfb600dcbf2caffeebff2da46c76c2b4efd47ba89b45667872b1da863106c7eb242d49138374c1b952d6ad5092199a07da40004d24bf57d3d66312dd0491e66b6f980babd362bf90e4c37537f41b5678561166d6b8a314b4ed7e075f599ef1d0f3e6014cc433cfdfcc6534f2a7ab6bae22ac05ebaeee94c6033ae6734e4ec0e2a8298183ef71f5a6ca63757771660e5c0a44000000070ef9d319e191e85c9528ea6c162a38eb2ab6eafd354e9f08eb184fbfa22bc95f0c8cb237da03b3aa90785c43f8f5c6b60db4b1708e7b1921cf09fe0e86dc313e08c09acd09655f07a871df021b50bdc9552c1c48525c4155ea4635ac6c0197700bc2c60516e7693bdc2531c31165ad5ad181ac2e6f97f94fe80b2d6a2dd25cde0e721f1f6fd3769ef41546453780ffcbce1a1bf19f2207cc2842cacbc6f6a8dc030a24f823997e7fd0a7d94172010df2840145c648453dfe9aa521be7fbf1e1f040664f432d2e5655c0c146bab5957036de9a8deebd532ac8c04bc01a1f1a4ce00c4a01f540cc69ef958a5bede01fbebd1437b8b7f8c29c1ed947db0ec11b06e4bab3bf822798e1a0df6dd70d1e6742b003227d4edad4edde93c96fbd994713e5181a32c2808193d7ac4a46172b2a2e36b2b491227abe2e1cae1ca81dc9bb619008251ca94e5b0a3f5b78215dd7826688e0157e625037b43534a58baa177ba0f0000000100b24a31e1690f8c6a076c5b14640212401cb7cff26172bd40b9f86a017e9408e3d9c2f11b95eed3206c0a105699cbc7012a6d0bdbc07d7dce3af4b5ddd9b6c83c7f54c89f9f3b2571bf6c2d62789dc92c26c91b3928f04e0649aaef5c508559","debug":{"publicInput":"0x35cd9ba8b3411696feabdee21c5da23bc46d02c76ddd9f2f92c9f8fda1c0310"}} diff --git a/testdata/coordinator/prover/v3/compression/responses/11-13-e5f194ad53779deb52c2455e216ca447a842026238fd8143cbb7911f7aefd9e7-getZkBlobCompressionProof.json b/testdata/coordinator/prover/v3/compression/responses/11-13-e5f194ad53779deb52c2455e216ca447a842026238fd8143cbb7911f7aefd9e7-getZkBlobCompressionProof.json new file mode 100644 index 000000000..8e32f5217 --- /dev/null +++ b/testdata/coordinator/prover/v3/compression/responses/11-13-e5f194ad53779deb52c2455e216ca447a842026238fd8143cbb7911f7aefd9e7-getZkBlobCompressionProof.json @@ -0,0 +1 @@ +{"eip4844Enabled":true,"dataHash":"0x01f05738e04c668af5ca1887f52528ccb9eef7cc90afd73c9c23c14550021323","compressedData":"P//DLcOwI2FMHAnG660DHNnI+LSRoulBjHV4RF2osVYj9wAAEAAS8AAQAAAWeFYDiM/wACPjBDTmL7sjv77avwJJSLGJochT26YvajoSCrU/wAANWxdqsTmDBIVdWdNwKAHSaLeMGPFRfergXTBApyBwiy0F4B/AYAIHQSkESn8CYBOyQGB/AgDIeIzqmpUnqSrc8Jfu2Gxaseh2kYekmzLDgpKPWoZS8h4W/wwAyAn8SAMn8CAZKACdM5enlT/AABnIETILSG3IrW/BQ8HPEM3bqx6gRdefX0wM38MAZII/xIBkgP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==","commitment":"0xab9bd4750ad072d0b0c28c9db6bb1bd5986d221ff14bd6c85997e7990a56cf4c550ed7cd01de02eae52509c296e2c6ef","kzgProofContract":"0x90520cf3854258ea4f13ba64a4e0d3aabd1a8d4bed9bff4877f15e457ccd9cc7e75a8dcd212a971b3b7123c008c1da8d","kzgProofSidecar":"0xa16124869146821518d622e91eff576a8146fa9df3f8de7fb17887a738d21f66fa60f5e2bab8b8bb63360ff434f99b74","expectedX":"0x12e3267a707510edfa200e89a3a24ea0a7886963b6569e896c24dbca24c9b024","expectedY":"0x68886c7a35ee00ced0cebe8c6e31af2eba1fdf9b0fbb0878fd4f12c111d08b79","snarkHash":"0x0cd0552f984176295088ff7d8fa14cb63a67ed9c0faa9d6abdeea09ccbba363b","conflationOrder":{"startingBlockNumber":11,"upperBoundaries":[13]},"parentStateRootHash":"0x06dfd5bf00ac76bece68984bced5f376d4a62abc03b56472959bf804c547d574","finalStateRootHash":"0x093fd331edcf516c7e6805250bb7b6b56131fc20921916096e4a8a71d0612167","parentDataHash":"0x01c993ae52495203ab88827c3111fcf3b09c16655c392dbdaac614dc00473c32","expectedShnarf":"0xe5f194ad53779deb52c2455e216ca447a842026238fd8143cbb7911f7aefd9e7","prevShnarf":"0xe6a7703511076e3789cc25059b468940b2e91df262f11b95b9005f758482aed7","proverVersion":"3.0.0","verifyingKeyShaSum":"0xc4a868954d361bf8c18d4b3699c4fa973a6b2e4543ddea0ce7970d6941f55758","decompressionProof":"0x001094a84c082bac7cbc7b5dba7adef0b908dd908463bcd1e47168aa5cce2360a8a36a1c26c9a330cafe829a5e2696710068054d38ee428465537d9d86d433fe5bb5507170ed55a5a9276ead21833dfd0d9f1a8a7f46fbf7090bfbf74ea867f5014b9f3165d6388fa93a957c47588bd0f252919e1cf1a787e3a57c75dba06297e146c8b0a1a2e403e98c0ab73a3290ed0020e492acc262642aaf3f81f147e7d660a0e8c62bff7f4ab36aa13a595ba408a44ce27270f320e9e8c90e214b511c6001549de0e7c591fdd95e32167daef7bf40c3ace7c44063208ba68f7858765005f80b8d09251658ffe9839580771be3340139c2fe1aac5e9ab6695c36b9130a13024b0a6bd4673039fc96a1f735636a2a13175515a1f8b6880a10a01665e45bac003ee49c6c96ada5376c8a5fdc75aa30c76420a3eaa409cd78899e5a66015cd11039f3a84796c07127313712f1d6d11300da61950c34f79a49fe0252a531c5fd37ac8b1d929b32a2affcc3943a49ccc1396d769d151883e00154172a3af7819b0127008cedb69db746354b32bb3f1234224c24bd05d2e3e3d20ea87c33f676e62b2d40ec179323c06e9b351cbb00a0aa0068fa88123b0ea8f8f5f782168ca8095ae532c47a85e3f89e46a73c1af336fab466615b2985176a9c45e8c51877e4db0027bc9ea9828b2da3d57378ae1ae0cedf5b5c89f11987382e25e67beba73a44b80c42fb48262406f09975cac46ac0f5016acade07885dc5f183d6fe66f39620c65b49c27b95eb7465d77ba7e6b0c29b3c9d545c53a9f155af964f62be28715c0148a5fd0001b2cb40270dd79e015eab4e829e78c42dc4019bade78cd6dc0bec68c52dd01bb62d4964d68b97bb9f5a5601671368ec3b99efa547b270f6586cdc44252c46fbe300d6793de85577b9a3deaa6c27599a64d4e44bb5a0ba2c30b3f000d8f3e9e002c442ad163ecab080cf6b63b008dcdad37317d2ab51ef7e929e35549b15b34ca86bba762f034f30d314c9016143dc1b45b5edf13cfa4bcf16c19764123d12d1c22c4e60d128b2a84f52bc74b0cc2b514120103ccf59b0c6493ddb00000007025b5a8f4ffa38979c5b101fc3493ae83d1bbf4e1bf12ebc489d7094380e708e0f5832d95f958f59b8d91781ac6841122ad13c591ba1efc9bbe20f4e5d14919b0dfd2034149a2a3d3f1b8f1a8d3e1bfc8faf23ab3835d334985a39a5e62258900b0adce2b8d704fc3091c2e0cd18a838959b8890191cc946a1f33ae217d18e140206bf190f6af5e335b41fe6301843df9982d1e8164e7a24aeafcf6c45d80a7b0d937a2c2ac3930ee8a23d7129b48a8da9ae6f7ac4635cf17157fc31961473a10830957898e1fa291eb4307988d13cd089189d91b826464f9a8f87bfe45da9db015d4babd7534dcdf214f3a1aec2e248fbb2ccc9db564c6c86aa444616ccaea06b57b36bfba02fa71fde5a7b5f05eed6002878b9eaf52fcc4999494318e825d7252f92b653197bb108ab7a6a65070c7691013c2cad574d9171815e2f2851fc6d00887cffc4d048c3429f45b7c84ba3b18ca14c1d0ee3fe39418141dab71e5a540000000100a13bbcfa50fb7c66532ef12de2a214e0e8584d6505eb058d9a088fc3a59c8b9d4f8853a6d52ae70b9619f428b6e06501850b024c9b055fb89ec98343fcc6e2654459508e97a8a0451d18563ed03a93158872c6907f5f144813b2054b776876","debug":{"publicInput":"0x1138ce362611857fff908dd9230a832a2d5482887ea3dad679c95ea3a42731ae"}} diff --git a/testdata/coordinator/prover/v3/compression/responses/14-16-8de7b2d25ebb3dd54040cc30cbe3a6333053816812bb33dca470e945eff7044c-getZkBlobCompressionProof.json b/testdata/coordinator/prover/v3/compression/responses/14-16-8de7b2d25ebb3dd54040cc30cbe3a6333053816812bb33dca470e945eff7044c-getZkBlobCompressionProof.json new file mode 100644 index 000000000..6e2c80966 --- /dev/null +++ b/testdata/coordinator/prover/v3/compression/responses/14-16-8de7b2d25ebb3dd54040cc30cbe3a6333053816812bb33dca470e945eff7044c-getZkBlobCompressionProof.json @@ -0,0 +1 @@ +{"eip4844Enabled":true,"dataHash":"0x0117ba7a785df44964e79ee97cf056d3af4ab463f1a4f30ae273f37cd5caf211","compressedData":"P//DLcOwI2FMHAnG660DHNnI+LSRoulBjHV4RF2osVYj9wAAEAAS8AAQAAAWeFYEQ/brNRL/ovD4KIwEfOB/8AAYBWoZkXtJkFN9B/DB1Fh3R9kpTE5gwSFXVnTcKAHSGi3jBjxUX3q4F0wQKcg0IstBeAfwGACB0EpBEp/CYBMskBgfwIAyJHKwVYuGtyGUEMmXHQrLMtXhqe0dW0qGWDumBHrPEn5m/8MAMgP/EgDJ/AgGSmIIT6kcskJn7iZNM0AOfo2EHN+eIm5meR5WsShEnLAI7fwwBkhH8SAZI/w=","commitment":"0x98475a9c957d83b5524dfd7268be142f0e9acf1d987f87c381c3eb670cd0350390741cab7e010c6a43d9f632eec8d54e","kzgProofContract":"0xa81030a065c7ab52d321ca18c2009ce01d48b40435c2ec66d5e38ec743031648e4a963150f7b088cf2f710ff29acf219","kzgProofSidecar":"0xa547ab2520c84c2dcbdbed96f7f1029adb12a683b97c9c9dd6a3b8f1b7f37b79c721ccf44f8f8843e438418a755c3c8e","expectedX":"0x2861d2eecadab310e130d9f949469509a70f903ce709dcb9dd49fc2a7b386539","expectedY":"0x322e192bf54b7c56ec97cf3c71aada936fb7251989738ef11b3b90f5e9099e35","snarkHash":"0x0a8c6f82808aafbe9eaddf410a6097b0c19b72057f1a20fccf713b022edd7935","conflationOrder":{"startingBlockNumber":14,"upperBoundaries":[16]},"parentStateRootHash":"0x093fd331edcf516c7e6805250bb7b6b56131fc20921916096e4a8a71d0612167","finalStateRootHash":"0x026a0d5bb730f4867e5e9d696d6dcb4a028cbb918549565e9cdcb6b42f839573","parentDataHash":"0x01f05738e04c668af5ca1887f52528ccb9eef7cc90afd73c9c23c14550021323","expectedShnarf":"0x8de7b2d25ebb3dd54040cc30cbe3a6333053816812bb33dca470e945eff7044c","prevShnarf":"0xe5f194ad53779deb52c2455e216ca447a842026238fd8143cbb7911f7aefd9e7","proverVersion":"3.0.0","verifyingKeyShaSum":"0xc4a868954d361bf8c18d4b3699c4fa973a6b2e4543ddea0ce7970d6941f55758","decompressionProof":"0x0180db6baabb7dafd0bced27e46883af65030375cfdea8fb484949050c284674fafbd05c6b461f8348b747058e33cb2c0183c134715f4e4f2caf5b4147afde8f4b20330134f56757310d76a47d3fe2c865dbf93a33606cfa10c1678708abf0d8004504a2b490ae363789335ffe10fdfbe8cda1254594bdf1923ee602ecc18c3edfd64985fb1ecc0d8ac7e56164331dd400e5778c4dc788f359578f0975d0448b8267a3fbd0fdc991312a1e04a36f9a3604ab7be9db5939efb402fb1291c7f91000ab5e6b3a2c275784c44dc4e2cf0832ac6aa7997f67b0f0a9ba8ee032d8073d0d47e77b6475aece8ef657b2bca63f4500004d961cd77ab5cec7885dfd0bea22a5924789ddd622ea14ac9d932814091c606221ea516a5133d2e7db8b248d185b000548cf43642934e3b4961fb74fa11fc63f43c9c203bdd7ba6d98c6d0dec1e1b5d076e3d65b4a758747bdedae909bb6001bdc47d54332b575a0bf54405356a401d3dd0172b221cc18421fb6b986b982e386355cfe8b5e5ed2bf8ad77dfb53af016e3c2f2a5c24f7787fc64a0a669bbe773c4ec03ec12d94760dea0f4818d2c47e1e0837fac94b50b04ac9ebc79bdb8d00d1e71b9dc791ae630ceba3445252781d48e6d285cfedf1bec1cf41520aaec9c8e00b1fcb2d5b41dac9a43ebf743b24017a98ca6abdf5d5634181660508d7d69eb26a6d327c440b23c9d3aca6a568b5268ae17fe3ae74318e51c48f0cdf9a3f010581188e796f3d24f7e58160ebe7f9104fe6fa1974473238e437422a18e83a67719b3d1207c86f9e0f1edc59b2745e015a95f54d9a61466cfab60d391502e97c54681d17cf50cc5187e83b6e17095305cc7282efc2a9a56245495de8ddd85800c36c2ad6088c7bdca44603135ecd9f154b6723b1500314d8ad36acdd2aa1d40b81380c93adae287a1a2b445c430de7006ed89ba2f6158b8268131c4f2779452a79186690e60703e82398f3851643e287b57823a5e13fa281a76b18a75a5eb701565f92937b3e39b8b65bba434ad31dd95a4ee374c1f06beeb25e62013982c1fa5b0c87d55f6e824721030f0c0ad36000000007123b50ba658f8f23f4aaedda550f5c4beb6698de4cc155a51249865a57e626830b94fbff64ff87ac0af73afda7f5fb906e41f5d5ff6dba20d296d869b1a0626406bf05a4ddc94318dd7d41aae856e09476fa708c611013e85281a12a571ea4df10ce0782d7978779168ce57dc6f8a18f712ddb8f96c3f97bf47d88231698183a0cf5442f78e3bb9a0f6cde60ae69a4d9d488a8d68b0ca5780a2103c5e279e67b081b77269253488e8f5eb56a9773dfbd18ed0cafe7b5c5fc665246ae5f597e7002ebcf6ea433a3f2d861b1aa3501c46d6c3b9749e0004bcbce5d403af390195a01a85613ca44837ea9b8c4c196f3ae38e7da5979d4e40617e5f4ddb71848ccffe0b5f760abb381f8c877529c3ef3a5be01a110f950a20f248fa6bcb3c8714c39dfa24bcd7308d12b29217ba6d32f5c97516cfd01cc2968d66ebe9925e1727f4806d4d1aa94b09bf6db93e43bbdc9109c092cb84f88d53db4909d09e83278235100000001017d44773109ad09f95203a6397951f606de9fe6af43016748605344f41a73054046be1366ca8ac939d2f628531c8e7f0053fbc28d9f841607ca2296cfd4ca718fb92afdc4f89527917c55ba4246b6f6b9dc2929b2b3acd27a584caa0893a889","debug":{"publicInput":"0xf9c9c12d91bd06e0c96d9baa76cdf468caa8c9e545dddaa680d96674bcb9b97"}} diff --git a/testdata/coordinator/prover/v3/compression/responses/17-19-343fef4cdcb6d0ab0db8ea7da91820c8d21a80135608b990c0b4f40c8f48b837-getZkBlobCompressionProof.json b/testdata/coordinator/prover/v3/compression/responses/17-19-343fef4cdcb6d0ab0db8ea7da91820c8d21a80135608b990c0b4f40c8f48b837-getZkBlobCompressionProof.json new file mode 100644 index 000000000..ef8ff7dfd --- /dev/null +++ b/testdata/coordinator/prover/v3/compression/responses/17-19-343fef4cdcb6d0ab0db8ea7da91820c8d21a80135608b990c0b4f40c8f48b837-getZkBlobCompressionProof.json @@ -0,0 +1 @@ +{"eip4844Enabled":true,"dataHash":"0x011494f735f62294281086b6b718118dc25868b6df1ee20fea3a37d254c3f1c1","compressedData":"P//DLcOwI2FMHAnG660DHNnI+LSRoulBjHV4RF2osVYj9wAAEAAS8AAQAAAWeFYFDf9S5wKSFfeEMHYXG4FWgC/tsXIXsRUXOpC1oqkZQcm1icwYJCrqzpuFADpNFvGDB4qL71cC6YIFOQmEWWgvAP4DABA6CUgiU/hMAnZIDA84EAZFRz+Kkl3cfRMl4fksjVhDCNng7o86Al0uqE5YDy5ueLO3+GAGQK/iQBk/gQDJWCvK4lhBjji2sAfJlEdhIAazXoqnX458dE8IjnzFlZlCv4YAyQv+JAMn/AAAAAA=","commitment":"0xac028d2fafdbd4d7465971d424956c61f9954b6872c2339c306dc33472217c709dbbcb98bf5bfe6929eeed7b52b2d1ec","kzgProofContract":"0x85c5600e3b3cadd0de0c81c1f3a2d3ac7433f496d99be8d5d8e3153ca12b6fcdfaa6a612438d26e141afc638e58c2d80","kzgProofSidecar":"0x805862fc27949b24d8f07f27c2c4bf4bec7f2fc1a787e127a729014a426459ea6181de10b89f6248aca83e69da5a9a34","expectedX":"0x47aa0554f2afdd462d20f2aca386943dacc2ea779c459fe8da72968a4521fc24","expectedY":"0x6ff357fb8e0a9a0850fe6424910a019db3704cdfc63bd66696fb792501abcb4e","snarkHash":"0x10fe048afc960f2f8f07d446e77018438414730df3bd523a75e824940347ca5e","conflationOrder":{"startingBlockNumber":17,"upperBoundaries":[19]},"parentStateRootHash":"0x026a0d5bb730f4867e5e9d696d6dcb4a028cbb918549565e9cdcb6b42f839573","finalStateRootHash":"0x0cdab0bfb220ab9c5b2199486f2e828cc1c2b350410dad11102dc3e1f333dfb8","parentDataHash":"0x0117ba7a785df44964e79ee97cf056d3af4ab463f1a4f30ae273f37cd5caf211","expectedShnarf":"0x343fef4cdcb6d0ab0db8ea7da91820c8d21a80135608b990c0b4f40c8f48b837","prevShnarf":"0x8de7b2d25ebb3dd54040cc30cbe3a6333053816812bb33dca470e945eff7044c","proverVersion":"3.0.0","verifyingKeyShaSum":"0xc4a868954d361bf8c18d4b3699c4fa973a6b2e4543ddea0ce7970d6941f55758","decompressionProof":"0x006d4e2b1157fdbe7bd03f30d23b5ba82825ae4d1c562c085f35deee18f5a34a169347341c1c5a5bb5217f73a697c3100046698e96a3a603400931e239aac677e9e6e6ce94281f290f5a9b268874d9b1e254c13a382309dd57ec6b8d153aa7b1000b93cd408e98f0df2f9d8466a06a0c4ff157178afa3f1c6afff0662b23315d764620b748619b046aada4708122fd4c0020c8fab248bc403ea3c4d96e17e1c02f18e4b4cb0d06394a2470dadf8e6dbda547e7bbd6a529b91db0209d6ee4a179017e744cb0ad1b43159734026e25e42f4514ee6ba2bd14d627edc561d431193acb990e9d28186e090418aefdbb8ef6520070a8e71ef2725cbd53494ee5455f8aae950e17ed906ea7030f629f9ec844a4990825111443180f1ae17d58d86af7d100a091500f08a5d169863334ae69bb659492f134b98a9e148acfb988d54b74e34a2acb5e696678372bee22a3b4e9dabf00ccc104d9a0db4ddc2b7d21a0a401fe42b17866bb2c18038b914508206c8bdfd0ad87b4ffd3eb0482dc507bc9bac2f7001d8a02b6f4ca1c376cbea66b11b0854a11ea9129031b3c5c5a050ae1c15d498a105f12551e3c916a35b8d54b12d82e003520903ea2f20e16ed64224785f4ab185ffee3fd9c534d955714e58eaad386b2b2db18bf0c1146d383d6b859ea4b4f0143fc89037f509471eddb20c995ec9a9aa553b1ea01b2a2a5e60d5bd686def4f07d4c6bfce92a8c3c039479ee5e151c000c6adbece8f44fada8fee91a147911cb62316424cb430656317510c9e17da6f5ee720dd1bd34747e27b4727867874600a004258e8abdc04ba85d50b1df5cb9f7eeb45f4c46cecd20f3f3305c22728f7765d72532ce51d8bc37aa2acd9b57f901ad1856379036f9988d15352493d69614e57e12020b45467d279c3543dc20d11048ec14263d194ca223483a42f3e6910028249ee27c52f4c077d72196e93925b1d44f3fce3c45c7bd3b06812155db887511920c32d4a17a9a3f6b2b469369ec003d37b93ddb1c6679c00c532ed866cf9da6fad2696ff3217f8c50d262c718b511f47d757bb15d3a77b2fa8827752491000000070dcce03b494784ff0286245a45c8a08b0806ed34b2e26ea83bf798b7acf80a2605bbb29a40bcbdcfdce7a08e05460429d943f6876a90d8cd1e578cd1e4db5d2809e31e1f14845462b9a7ab9796ef01db6acdf9dcb0a582249f4dd709f1cca6370e03a25a13f976582eaebe966fbe2bf3627afee01381c75d44e02bdc4046978607de5dc5a0fc9eae4d1b7af226d404699c24a7897280e2c35d0fd98cb021c2a60248d62a385ed0bbac473bc0ad0ce0942b2c89248498c29386a70f91542d7dec07a7993d7e36b6dcce4fd2bcdd1d8cf14cadbb7aad83c8941b2504aeb959c035001a66fb3ed8217f7c73ba0bad289f760ebbc52854de155a54c449ee782af8c8ebbfc50019657b82b2a73f798db230e3013163d11b7cc2b6ac2f3a36e20fc7d33fcaf98d15a51e55035ba48011b127266e5b0673b5ca34ec2097d43a83767e5c0807129a41e2300859a8b169ddf29f6ffcec07e7e5d308054298a2c96032984e0000000100a6745cf67ba7f07c1df293cf486b461f6fdcf2fdad922edae048bece7c8bd795d9d92f45c560470bc74413147f77470187fe37a24c6d097da8ff712178e29df1b5509dee73b201d1568fa1f90d80eca9e1931d0b468e771cf0d81e96ae7dfc","debug":{"publicInput":"0xdd2d4884cb0df6c1006dfadad66c905bcbf2e4d70547ecfcfbfa1554f81d227"}} diff --git a/testdata/coordinator/prover/v3/compression/responses/20-22-aea706d4657966f8e30e918e1097ffa0da19513b0be56a243cabd7d3a32358c7-getZkBlobCompressionProof.json b/testdata/coordinator/prover/v3/compression/responses/20-22-aea706d4657966f8e30e918e1097ffa0da19513b0be56a243cabd7d3a32358c7-getZkBlobCompressionProof.json new file mode 100644 index 000000000..f3f0863f2 --- /dev/null +++ b/testdata/coordinator/prover/v3/compression/responses/20-22-aea706d4657966f8e30e918e1097ffa0da19513b0be56a243cabd7d3a32358c7-getZkBlobCompressionProof.json @@ -0,0 +1 @@ +{"eip4844Enabled":true,"dataHash":"0x0146d216177763b2ddaf338614ac3c621b193019f04145d45ea58dc381c910b1","compressedData":"P//DLcOwI2FMHAnG660DHNnI+LSRoulBjHV4RF2osVYj9wAAEAAS8AAQAAAWeFYFxRNrQhjU0OZ7SrG0kXjaSDQ9WKxwCaEvpw65DpQT0BE9icwYJCrqzpuFADpNFvGDB4qL71cC6YIFOQyEWWgvAP4DABA6CUgiU/hMAnZIDA84EAZGDC9c+IOnu2hsNEuhfnnsffdFehewqeIAO4HoAivgFSFL+GAGQN/iQBk/gQDJZeIOu9cpuRH7XITNvBKOE/1ksYd8cHoyX8rJ2P9lS3vsf4YAyQ7+JAMn/AAAAAA=","commitment":"0x95f187c9f4f061fa8607ad23b6961c8a700ad010ceadc028f7266b46a43377181441e9d4d62dbfaff557bf8f51c05ff9","kzgProofContract":"0x8575f10f08e8054fcc8a2934e92a97f1d93fd6a17eff289a8a3acfb6bbc3411e145671a9025a5ba7a470d25b47dfd834","kzgProofSidecar":"0xb3d0f8e421f5cc7c069e4ed907f86452d4fd2bce4a43fa9dea106014d60a98f506d25a2b7f7bb6d380d58548f093753b","expectedX":"0x2e70e031ca54716e9f1c3887fce8717b4f3cfe20070bcc11501da6065b7eae92","expectedY":"0x4f68f7f6f1b8977467e7485135b1621e07d06b134675ac2defface30b0fdb0b1","snarkHash":"0x05a68dbec5e3908d7fd746cfc69b99af7ce645711ff822f997e33e6fd1478bae","conflationOrder":{"startingBlockNumber":20,"upperBoundaries":[22]},"parentStateRootHash":"0x0cdab0bfb220ab9c5b2199486f2e828cc1c2b350410dad11102dc3e1f333dfb8","finalStateRootHash":"0x0bab6a28cfabc29cf1e284145b39f5b37ad04ca0d85cf878943fd066b3c8fb10","parentDataHash":"0x011494f735f62294281086b6b718118dc25868b6df1ee20fea3a37d254c3f1c1","expectedShnarf":"0xaea706d4657966f8e30e918e1097ffa0da19513b0be56a243cabd7d3a32358c7","prevShnarf":"0x343fef4cdcb6d0ab0db8ea7da91820c8d21a80135608b990c0b4f40c8f48b837","proverVersion":"3.0.0","verifyingKeyShaSum":"0xc4a868954d361bf8c18d4b3699c4fa973a6b2e4543ddea0ce7970d6941f55758","decompressionProof":"0x014960f75c1ef839b5050812fd56b709649dc3f2cfa61c436ccfb402e3aa93a8f7f4e6861dae0b27342346009de6d728014ebeba43466c6fdcfb0531e726d18899b0695c07aeb45398a80734c068d07b3a27cfd156c872f0f4a2637d3afb01af0030ca4687f4e13296f4bb2012ec1ab6d6a55d8465b391de95f1034d8138c906baef5ccf825121f320472cfdea67e5d6000d534885ef7e20d5fee27061b73c4ef62e7e94242b95dfbc294df4c76d40e477ba3e2b3d42333db0a726001c1888d50175c76ad08a2c9f7c9fc9410f2b0957b3317dd4be1d89b91dac27aaaa6d84da905cc2c20b9103b82171e3ee4c7d777401418eadc3d38232fd22b2292421734f08107f0bee56383eb58e32cbb90c48c7ccab9995b128f85928923da715a8a6780055dfaaa6ac6816a4c9b059cd735ea6469c09a710e12957d84e2f905f62b974118231dbffc270722f69b4efbe6c8b36002f0e931c31cfa27e33d5776716e02db28ee5db5365ba92c0c1c8220f2384c3997376a6a04035b18bef53f6e9c2506300b2aca3389e14fd67af286a8f1b2a9c75bfb3ba505149fe70f2fccc9fdab86501aed64a5bb7d722bbbe7dcea262c7b100c8a8c0d521404922ce44eff691faa4826db70c1826b16e2ecba2f4dbd745c53451634874c29d5dbf6ffd30c7b825d9002a63e7f3ebc7401e4560531bed3d3d07a3edece400ba440d887a21a0a6e744b2fbf1bc6c6f74b9826357d15af6bdac002455654f03363fae801b32e39927db128399b80db550d1c5ebb35dc22b2a91c541cfe5e74e7b2a0bbd81a11d9be6b5003fa32d1f7528e7dba39a7547ee4b2c2fdb7d73b00fd5a638a1c7f9390ea83c69dcf4bb34ff21fe7452003878e330270183a2b4c1c6ad856bdccac0ef276a692906bac040e70a1dccad433e4716f42a4d88e52e8a935c3ccee09709ff17950d009824fd6a6492ffb336d79e045c366731474477d4ac274b7ffd188520157d5785f8c6207789002a2d539c483ade11f301858001cf2ca3945fd38798d98f2aef6bc84b92b6c0b4a208eb1eec536cc33699160d335924ce119f6d1519654252b4000000070e0ea9b34d781bdcab391b04d1acea7f1027b9c14e8e346920d0e180aa3ad4630666cc5edc269b76fe39b185f6fd1795c0ded9261409e5be0afae8614c16e1260412a81de82d1d2eb97e828eda612dee68411f92575282fe4a9851a57da382600a025792b85b23a72c5f1d0fd8c45b4e8da65c8bae1c4614dfa24f389bf2640d093f4bd73fa605b0200b0c83524db40ff4347aaa347a6f20f11402ab451d783609bd5c6503dcdf40ab177bc451048338b5c106ad8bf2b735bfa3b3ffbe899b6b0a2436a67fa969729d5bcf7ac6c66be3aa7a70f10f67e2085e752abb394e68aa0119908ef63702d3ea3dccb2473d6a04e5939e56a9c17f249dfa0fcd8d9f31750b3337450b7ec6c9abc173b8fcc3b8e90066cde9ae81f48e56c48405d60bb28116bb0792a1779cb92aed0cc68b7288bf32826027870f32b4d38713a26f098c6f11a3d4cdbf23ce57dfc694fd32327d62095a44456ab60722cb38dd09fb4185d1000000010108ab00bfe6fd906a180da81f15222934f088a7521582d7039aab4588bb02e5a92a80b70fb737ec329615fe7c39a644017290eb7650a8c76d7d9070a63121990b601dc1f2abe37c08c9fc3e598f1d9591a32b8c9ab3ad56ed56fbdcf8cfafe8","debug":{"publicInput":"0x6fa348408b4391d263da817fc22f0701399065217bf43da95b628366c4125e4"}} diff --git a/testdata/coordinator/prover/v3/compression/responses/23-25-268a263e550eb02c8196d4b9e3cc06a55d87018f2e20ed7304da5f2f3f6bbe5b-getZkBlobCompressionProof.json b/testdata/coordinator/prover/v3/compression/responses/23-25-268a263e550eb02c8196d4b9e3cc06a55d87018f2e20ed7304da5f2f3f6bbe5b-getZkBlobCompressionProof.json new file mode 100644 index 000000000..dfd928b64 --- /dev/null +++ b/testdata/coordinator/prover/v3/compression/responses/23-25-268a263e550eb02c8196d4b9e3cc06a55d87018f2e20ed7304da5f2f3f6bbe5b-getZkBlobCompressionProof.json @@ -0,0 +1 @@ +{"eip4844Enabled":true,"dataHash":"0x011c205cb61ad36b464d88916e02f3979b79b042c8cab3658900d36046c4aaf1","compressedData":"P//DLcOwI2FMHAnG660DHNnI+LSRoulBjHV4RF2osVYj9wAAEAAS8AAQAAAWeFYGk53DA0IP2BMW8JguFxg7txOqSSQ6ky3nzdRTrUI3Y+3dicwYJCrqzpuFADpNFvGDB4qL71cC6YIFOQ+EWWgvAP4DABA6CUgiU/hMAnZIDA84EAZG0nx/VIFB9YtO4i9tt1sgnSJI9Lrt5lnKNh+X/DWq3ETr+GAGQQ/iQBk/gQDJcZgfhHuKLGLlc/pKC3rwOBXFph8L+u94GGVFPGHX+gY4P4YAyRH+JAMn/AAAAAA=","commitment":"0xb6fb447383919520b78bd861de68883f2c558095826f558c4ce79f2dacb1343c555fcd321006f8eec48f1f0e2d510ca5","kzgProofContract":"0x833ba3ad1abb1c209fd6d3bf63d9ffd66ad7f553ff294d7ee07e2c4dbf66de64d10b9bf656c7fda9c23b773ea26cf6c1","kzgProofSidecar":"0x92c4ad82a464eb8b9906eab5d383e2ba0046b76fc3cbdf08f31ec8e02dd75be05e8b91bd6dc800666f7a92e2442dda17","expectedX":"0x40e01c7c366155743e3ef4a8a6fdc5ccf2351454bdb4bfe0000756668000ead3","expectedY":"0x24e5b95a0de3c17d9be5edf15de13c6f82bccd66fe9afae8e8d5718fe9b60a19","snarkHash":"0x0f44502fa3ab1c9427775b45e393a1a917ae9fb9766dff242d425a98800f31aa","conflationOrder":{"startingBlockNumber":23,"upperBoundaries":[25]},"parentStateRootHash":"0x0bab6a28cfabc29cf1e284145b39f5b37ad04ca0d85cf878943fd066b3c8fb10","finalStateRootHash":"0x0fbfde9208962103fca09983aa7a7692edf9a9db2376cfcb92f6b4ad19bda51f","parentDataHash":"0x0146d216177763b2ddaf338614ac3c621b193019f04145d45ea58dc381c910b1","expectedShnarf":"0x268a263e550eb02c8196d4b9e3cc06a55d87018f2e20ed7304da5f2f3f6bbe5b","prevShnarf":"0xaea706d4657966f8e30e918e1097ffa0da19513b0be56a243cabd7d3a32358c7","proverVersion":"3.0.0","verifyingKeyShaSum":"0xc4a868954d361bf8c18d4b3699c4fa973a6b2e4543ddea0ce7970d6941f55758","decompressionProof":"0x0120da112ec8a6266d08a3d19aa96e4b992b029e90e0c3cad822b46179d46ddbc8a2178480225c28fa6ca932b81b82be01917169b397689ccaa815f701faa7f9eed1518e7c1fbaa96db29822d58c714ebc3909c9bd7939861177fd90ff08dcf70011e36ec718b88628d59de6533917eb001ce356597e064c3f2388e5f2388d914b4f3f394514ff9dce56c53eb3d2c08f00f1d8bfd95010bbf2b771d36115bc25cc288e3030bb35b6c877992c43cc4e09a6f01aebe2ff54e164db2a5b3c9e7a650156627bdb62878fe4e402393ab679878ba06224ad39e4aa0802076ffa1b2d202190fa1423fc73a6c162c61b0eae97fb01a9b05d6ba6f1cfc29fff923cbf16a6360147e3bc2fdb6549a00bde8fd01e4286e138cfe18a77091cef7c280c5f2c420109c6f82c4bfe8763b32ba7c2bec2181f031ed4275a58712e1bf1ee34362e70d7171733b9afeb0eaa083b3ad7bac86100e9eec1531e5686bde08cec05dbaf2610bec2560bae34a20d171364fd60a909cb19db4bbf44a71a84dca50ece0638c9014b63629f7102a2427531659ae60e30ac8cc004b32ee3af25b09e526d416b1bb05c618de28884ffe8f1f465a9e4817a0094cf063c3f383dd12fe80ed06ec66dd867eb8b5c06629a54588002b9ea7be63a9b3b9caaa8c5669ac3078f0bbf75c5017525d9534c0e4326365f8da010e374b71e80eae78580b41b54dc0f918a11c7802c80a8bac06b2171026bee26078b4400b5789196af649f71c8b854173107c27b8318a35d87a310facb6006db6bdda9ef0ed6fbc9aa8546f9c03902784621f700f13f0e696b76d8a22a4ebd7958f3865a0ab0d22ddab067406cf7d8cf10a265495e5962bc02477b78d52b0ec8d40299014d21bd3620f9f238ec8aca2771617bb905691cb82bfaa99d9f8a43fcc41374912e3e5e721e850e26acd7ea1e878df700441d49c198730dc540b2582ee7bdb564b0c8ec285f6d85a55b87155a748b686e02e303d88cf73ac3f0611bd16cf7ee00b3d7cd7e32f5d42ce8479a329d575d62e67364505d169c5b6a33e02a59be576b51f99472a764d3a01733a85ce35d1400000007106ab930fbf3bbfa810e225d3623f1c2859477b14c063d54c3b6bdaf1182193208f35a7d6a1c5cc87d365319190371ec63ac50c50d0e48b3a724e85794def7ae127221ce90d5ef0f5a9d0616f16a315c0b75dcd1b128ee816a1cbb8a73c0b65401e16cf8dfea588fa87ee27587cd44a0238f2136adf6316b29d1d6ae93075ca700e06ea1bd0edddb17c78d0fa8a3406ae6275bc215d598b6f9b4a08716f6d2d70e6fcc2fcd2ab2ef0cb142e4a6690663acd4ce29dbfbf72a641080d4d0b43c690cb7fc6a58176d554b21dd1488591af66e08211418c7444d391019a4e51e00e7001c6715a089c69a73064fe881bc8f0df6e75d8156624697c08001d2b7a05c457bf3c0328e60f680ad94ef8679ed447c006f426113abb004e5aee4a59c90b89a1bfe503266c755a66e65933d836359a498864c0b29ee01f01c248d2a66345a2505e5c12442f7dc501ad94f8f9697b39d6946e797817daae4d496757bfe4e633a000000010061ef85d1eb9632118d9d827414bcb3d034b039327c249de8b8fb7e257851f5b73c4b717238829952f23ebcd821d548018cfbc3e72a349bde1f2df799214fe8444ef0e93db4fcd631e001644ce020a49ab5219abac8cd59a075258dbd1572aa","debug":{"publicInput":"0xfebbbeb857844875c7b336629ef346454944f69cb0a53202199cfe40c740c04"}} diff --git a/testdata/coordinator/prover/v3/compression/responses/26-28-06851ec1f1ba875ffd3a08fa5b2f0d88ac9426c9ccd852973abe73bd9afc921d-getZkBlobCompressionProof.json b/testdata/coordinator/prover/v3/compression/responses/26-28-06851ec1f1ba875ffd3a08fa5b2f0d88ac9426c9ccd852973abe73bd9afc921d-getZkBlobCompressionProof.json new file mode 100644 index 000000000..a6f68f643 --- /dev/null +++ b/testdata/coordinator/prover/v3/compression/responses/26-28-06851ec1f1ba875ffd3a08fa5b2f0d88ac9426c9ccd852973abe73bd9afc921d-getZkBlobCompressionProof.json @@ -0,0 +1 @@ +{"eip4844Enabled":true,"dataHash":"0x01a4531284372a882e18672608435a88af99893b303a0238bbe3f8c95d44e18e","compressedData":"P//DLcOwI2FMHAnG660DHNnI+LSRoulBjHV4RF2osVYj9wAAEAAS8AAQAAAWeFYHXq7IllXUFenvWrrcCtJK0weny7aW7wyHuH8IEZJVhDTdicwYJCrqzpuFADpNFvGDB4qL71cC6YIFORKEWWgvAP4DABA6CUgiU/hMAnZIDA84EAZHmtl58hiEmxdeXn0tVHn+wWtkfyIxNpHz2mYQWw0Lg0En+GAGQT/iQBk/gQDJggOtZUOOupUjx1C8nuDCCs/lShmiah8K3NKjC9CCSe4v/4YAyRT+JAMn/AAAAAA=","commitment":"0x86d4029239ae776242220d12b43b2ddbfcedd802f2eae6bcb10a68f9a8283ff34a25175aa3e0a4e31c61ace1b8acb301","kzgProofContract":"0x97c1fe4d11f5764e3c90bb43a6cccd5c6cb1447bef047ab71678095a577c2a4182166bf843a6e87c5cedfcea662a5c5e","kzgProofSidecar":"0x85c62cc468a6cb73897e460d9c75ecea021312d77f4b5d28c061f290e32060c699af911c5e90812319214faba6fcb8cf","expectedX":"0x5126fc4b426097858bc10552dce1ebed0a959c3989591717d549daef3994f32d","expectedY":"0x6637992bdb7764635e49912b661f265afa18626144fcec1a53790fe940d23ad0","snarkHash":"0x0d06062f6c7644b100baa955d1ec4dcd1cf1bb2102b81daa4ba682eec77d5e9f","conflationOrder":{"startingBlockNumber":26,"upperBoundaries":[28]},"parentStateRootHash":"0x0fbfde9208962103fca09983aa7a7692edf9a9db2376cfcb92f6b4ad19bda51f","finalStateRootHash":"0x04e223e961d59de5d0cd6ecf9d78359cc9d72b4261d851557b1e974d90b71a7e","parentDataHash":"0x011c205cb61ad36b464d88916e02f3979b79b042c8cab3658900d36046c4aaf1","expectedShnarf":"0x06851ec1f1ba875ffd3a08fa5b2f0d88ac9426c9ccd852973abe73bd9afc921d","prevShnarf":"0x268a263e550eb02c8196d4b9e3cc06a55d87018f2e20ed7304da5f2f3f6bbe5b","proverVersion":"3.0.0","verifyingKeyShaSum":"0xc4a868954d361bf8c18d4b3699c4fa973a6b2e4543ddea0ce7970d6941f55758","decompressionProof":"0x016db164c007ea7fb4e94a0a9bb9f949041fc93f8c894f754b80d3037ce051e2666ca19dacf44a532cd0b0d0eb7b87ba00c0aac8561ca1b2d0f6f15ee0f718703018c53871b9b217e5d5264268ed57bca114a2bc9799970e7879c9efb249885401397d67b798ab7b63dcb95e454d6cacc74cbcc3c2776d45ded2891e052cb01dc56599a592b095a5044460876d08aa72000153f8ed5358b4751a75b0a2419b444add09c1cdde82320f14da26bce3253baf2f742c72104d72e3f3800d34d3851100a2825c73d103f40a0f0115ff403ab9ae892ae7495ff3a3797822183d8c7c561795ec8c4193db59e3ac2396347968e0008949ff4c1fd96ac7ebe09998e35c20ad7f3a3d64171de621da93c8a6c50a570f50bac1cde442dfa2b668a780c1cf0400f05ab327013c0f42d0396c301b5462eea53dd1c2298f06857997b28b9c07d53799b592ec995466aafd60dc2ce51c2d00b1adfe23fa2b24aa2481c94a660ac1dc909c02ef6ea0d3809f66370737135b8a642dbd6ec3062ef706ee13f82a9e61017bb868f95bd6b6548b56dc252363feb8cec2eb15026c6018caf32872bf659ee90a463fa24d3edbd346feb0430e8c970124ebed8ef37188688b3aad62c776feea3b2c20b3d55d3ffc4973fc2cfd5968625fef9341a999d0626b0aa0f04dae4d0072a807f504c5483616fa16a6da2a4d91eebe4759e7d3c69878d825f506455dbca917f4b1392908df6a47c36715314e0088050c8b3cb886259914a25bbd1b03704c49f4b875d301d3db2a5b19f48b585bdc187dabd6bb63812f09ce58e3420a00e02507b82661f6ac159ede6a2e64f060aa446cbeb1e26eb1738beaef59dad36929b133f1baf969de5b08a36617b29e019c4757b288768d99faf027abff9abb69586b99a5c7a1db2faa92ef329bda7e4aed602c2e40158f011bc94d954ce4a701a99e8033845e3303c7209c0eb559af5747f927122acb54de7f06af8e3a1ada6617efb8513adf0d7e3c65b687b68405002f73cdb62356bee7e660cf9a7a14afacb5162f0e41d743de693fe1b628ef3a9eb7db1bd5fe2abb3fa38f860e3f6de5000000070b6aa41803ad47070066cddf1b5fd4e21c42c3d23195287ba29f84eed77a2cb612546faf91bc6c8177455779304a9aa9d1cc0d97915da7930c2914e0ed5d6f650fdc4ee07298a0e3b44dfb0f5b629ae2a1fbca6235bfe853459307f9639d679e0dab840c3aa4af25d7a35c0e41390a5275ad117a20ad71b9fc844124b5c699f10eae7c14d2ba3bc95ffd2c2cd8c5af5bc26f2562488953f440f450544086a1e906736d859571f14e9888ccb03b34328dd3b6b897b8283430bb0ebf566b0b426a125ecca84a330febaa10682d2b7046611816268427d1fd53c55f5bba95bd1234012a710574d9cc3881ae3fb121770342b55ffc0dd8bdf1b0b57b5a102a7d08c1adbd5da0b24624a30c6612f7efe1599d00b61d66f04529d275ac6fc120c06e3b1511a7e2c2ebeff391e196f291bcec9a59a05f82350ef80925e9ecf594c0dec801d0fbb96647a5cf36fad20b22e2e3e14a3cec3e869ab9c7819a1e36ceb6add9000000010000f64003b48b522beee0b1be86c409016ae0c2654e30a7ee42cb31a259265e49c106918bb603b03d8de57956a27b5601516a0c5f4103626e7ed95e895fbae69c8ec9bd7ba8104620f6b59ab23be18d1f062a26fd167f1e4859d97ecb79ad2f","debug":{"publicInput":"0xbfe32a41355f4792b20f75f039d3fe2ea12b105243ca597e95772e882059dd"}} diff --git a/testdata/coordinator/prover/v3/compression/responses/29-31-0602578e3a61f2be5afdd3ee34c6ac99e1e36a50450c75ef9dd78e50dddd3f8c-getZkBlobCompressionProof.json b/testdata/coordinator/prover/v3/compression/responses/29-31-0602578e3a61f2be5afdd3ee34c6ac99e1e36a50450c75ef9dd78e50dddd3f8c-getZkBlobCompressionProof.json new file mode 100644 index 000000000..dffaf7c20 --- /dev/null +++ b/testdata/coordinator/prover/v3/compression/responses/29-31-0602578e3a61f2be5afdd3ee34c6ac99e1e36a50450c75ef9dd78e50dddd3f8c-getZkBlobCompressionProof.json @@ -0,0 +1 @@ +{"eip4844Enabled":true,"dataHash":"0x01354941e62722510ef8c530586b3f4edff05009634df244e6df56f131ff1c13","compressedData":"P//DLcOwI2FMHAnG660DHNnI+LSRoulBjHV4RF2osVYj9wAAEAAS8AAQAAAWeFYIYe0EUro5tDF7AfGgIC4vjC4BdXTCzUllOE8MDp0gGPiJicwYJCrqzpuFADpNFvGDB4qL71cC6YIFORWEWWgvAP4DABA6CUgiU/hMAnZIDA84EAZIpcHZkDcwscSpG36RQ5Mirjj3qlafZFJb2KOeYgQJTmS7+GAGQW/iQBk/gQDJjllbPL/c0JfpqUKjaqkjAM764fVC/aeMCh/ix6sQDnA+/4YAyRf+JAMn/AAAAAA=","commitment":"0x914043c038399dcd9ff7040a0ce2b2ef7631eb0544911c4d77e6eda38ab53d9f500f8d7aa888254eac7ac1c7ffb81ebc","kzgProofContract":"0x9190aeceb0f6ba47f4ab823d61a0ac0cee4edbe7cd165798e962cc4674b0b28e11a4a049e6e34f20a63535d660eb4a99","kzgProofSidecar":"0x89481c3c03f6c58fd2b02be46a5954dc372c37efbf30637163a3052c8ad645b6ab5e3d0c612e433d3d92020136c71a06","expectedX":"0xc1007a373089b98c0e41071959d6ec1377c376d6a8d8a3498bcbbcd0a1db55f6","expectedY":"0x03d446b5f37abbad71c95a3e916b2ad98107dc5252323e2e56b51c48cbb3e715","snarkHash":"0x000ee937c9ffa497302444231608180adf4c843060f55f94043c0b3dece2a7ed","conflationOrder":{"startingBlockNumber":29,"upperBoundaries":[31]},"parentStateRootHash":"0x04e223e961d59de5d0cd6ecf9d78359cc9d72b4261d851557b1e974d90b71a7e","finalStateRootHash":"0x072c29b2166fcbd110ef1648d38131ac98044e8f53516b2853289f6d615e74df","parentDataHash":"0x01a4531284372a882e18672608435a88af99893b303a0238bbe3f8c95d44e18e","expectedShnarf":"0x0602578e3a61f2be5afdd3ee34c6ac99e1e36a50450c75ef9dd78e50dddd3f8c","prevShnarf":"0x06851ec1f1ba875ffd3a08fa5b2f0d88ac9426c9ccd852973abe73bd9afc921d","proverVersion":"3.0.0","verifyingKeyShaSum":"0xc4a868954d361bf8c18d4b3699c4fa973a6b2e4543ddea0ce7970d6941f55758","decompressionProof":"0x010b4cea0a68e2286a03a79a73de424bbf00077656b8c992bbe902909d44b0f6960df53e2954f4604b2eb72df507e754015b384f5cd4f084fc4a9dc2aa7832b3b305ef898e178e00d653a4545041e6890b0b517eacc5bf8bab4fa917e8b25499017c1a051d509797c83313d67c4cf03499ee6b97a50466109e81f553268628acd6ba1b82fe508bc856005b2b9eea2d4c009104852f5824df91a84e1bc9fbb397b07614ded662b95ec41a3640e525cb11df2da2e01262bed868b13e9f05b9833b00003da6d3ab7deaf956e170882fd4dd7f426b08b29f669aaf747d13151f809ea50259c01da6ea83590f986294dfc287011763177193030c0d36dc172f25ccc9fc53e4f00a20566bc616f1ff46f368ece3673b801932c8914a367e2f8a96253801340273222ac65ea4ee48c2719e4d20024be8fa8e0581ce6df1463d4becacf9e2b5d91953615138623dc41d99a3be1900a2f2555de869d63e8fffda3f666c7def0466f5997b57566be9f2d019c996ff485f54b82c0c18829146c01ed0dad3020187c2535113d03c3e548316492571a34647be6721958cb63cbcd959b9bcba9ff2204a98007ac41b56d98e1739ad888900d956b455817e003751021efff54f4e187fda16631b7ddade78b941988426a5380597c056c3d4e7a196f95ccb39e5b2014b268dd287333f4c47b43919cb97258992d63c0c34351fd06467a78de890f5aeeed6577b8c27a6232fd9467897b6a5010a1577d95b695d20a385454c719a94c5df7aeef2164d1e6d02faa9259bc237bc8717f9cef7fe68ae24c2cf847fc84500425d4b82425cbc24ae71700b8d4e24a015e752002bf6cd3c96dd289159375eb8f2f9809f19d24ea890408ddbb6d67c01a881d2979393de30b816943bd9416cc3906120d5745366be19d6fcc86a4cef630c6a449b2f612bdf040c49e559f85e014c55d7c8b9be65ea9e41b084c43a376b682608170b683c9e82ec427d80ba9523ffe375356359db25092b2d30a3189e004b67391fc1efcf0e1dc50294ba8f70205566280b651aaa5854b157a6ec58b2e7bc5a6d0a711edf275692b30926008200000007085fb982cd0fdb5aa2c6875dcb1fed8e289014765dad6ed17f55fcdefd60a8250c37f36d8490adc75ec5025dd7ac87892446f03306a2df5bf2c42f30c97e97d2112e564f48f529e7946f826c782226bb79977bfb5f2aa5f659f3e5dd8bd9c0320718d97b3e181bfeeb6af34187a6878f2bbac2160a03f2594b957fa3c49c54460edf0b2ac7ec386ac1498ecf55e4643fa448c6ea8f7a4e316381ca0f5c6a94b90eb92b6ce1e859b5ef11175e107f48ce10498f026748adcf73a3ce7c089c184401257dff39592068dcf6b8de859e8f101884123ac50ec080012b7343c66a483a01aa12edda893e432b7cac19b0bef165212647a194dad9393a75e27204b24d4194b9ced4721e2172262c99412efa6a1701abdf72dfc4b241cd029385969d4cf31f6cce4d6c9b48712900429745d72e617cfb3fc75f3d484ab810fd73c3729e1309f73a7971885e922fe9aee0d0a2b10d980c9e7a685fbc0181944188043b38000000000101404f9039ef17674e751ebec0e0e530d08c9068b4aba6460e40cd5028b4fe9bb6506a8431bcb0af0181499a37e6966f0003a8bbdd9239b74da9091ffbed895cbe5ad110dc8b8cb536c679719c4d34ae04a847c6e7fb2827b299e1a5e428489e","debug":{"publicInput":"0x218a808006e2776930739a24ab53d9900061f84d747ae84b69ff69d5b7578f0"}} diff --git a/testdata/coordinator/prover/v3/compression/responses/32-34-a646621c48d374488e214c7e02a64d431ae0712f3bc817a3d5943914f2246831-getZkBlobCompressionProof.json b/testdata/coordinator/prover/v3/compression/responses/32-34-a646621c48d374488e214c7e02a64d431ae0712f3bc817a3d5943914f2246831-getZkBlobCompressionProof.json new file mode 100644 index 000000000..6c6736342 --- /dev/null +++ b/testdata/coordinator/prover/v3/compression/responses/32-34-a646621c48d374488e214c7e02a64d431ae0712f3bc817a3d5943914f2246831-getZkBlobCompressionProof.json @@ -0,0 +1 @@ +{"eip4844Enabled":true,"dataHash":"0x011531090261c2af287fb3f766eb58a8a11ec7fb958560efce58f8ec03e24e5d","compressedData":"P//DLcOwI2FMHAnG660DHNnI+LSRoulBjHV4RF2osVYj9wAAEAAS8AAQAAAWeFYJIVJQVsMsNV5WmAm74j7vZS4c5DbNz1X53q1rfxObWACxicwYJCrqzpuFADpNFvGDB4qL71cC6YIFORiEWWgvAP4DABA6CUgiU/hMAnZIDA84EAZJZBmKWdIy+AyPdc/Y7y1+UVs2nPxYHX2wwsDtSCvq7W2X+GAGQZ/iQBk/gQDJmgVlvqJFMd08GUnpGiMAOtGf1HejZRp3WTDJnhAzVIHi/4YAyRr+JAMn/AAAAAA=","commitment":"0x93a63f3345bc67d21bad315894e368ed90e964731f7d80c63624a458d389fd74c5d1cbbecce97a977987895378f4fba1","kzgProofContract":"0x877186b16ab2050ab1882349f51eb72d806b68ff9bc133740dcebfce9101e58d3beca3f2f5a54f24a7fc86b5a2b0208c","kzgProofSidecar":"0xa715c44f2abfe59239ca6a0912d7e14e9b79e0e9de6847660ea84e37d364198c6a0d7d2bcbbdd7f81cfe0c335fe9e825","expectedX":"0x48dc636138af6a3a73783a4887c5fe24a9748338dd36996ddb21246049deff4a","expectedY":"0x433159b04ac95a514993d0c1cbb583330d744e8cbb424f3942cf9f1499a221c1","snarkHash":"0x07e86953fa53fc032cd223e331227ebe23cc887d6154a9efa6109580376d2b72","conflationOrder":{"startingBlockNumber":32,"upperBoundaries":[34]},"parentStateRootHash":"0x072c29b2166fcbd110ef1648d38131ac98044e8f53516b2853289f6d615e74df","finalStateRootHash":"0x10556468275a46e1261bd2af01c421e81af255ab49f932de2b6352de9648727c","parentDataHash":"0x01354941e62722510ef8c530586b3f4edff05009634df244e6df56f131ff1c13","expectedShnarf":"0xa646621c48d374488e214c7e02a64d431ae0712f3bc817a3d5943914f2246831","prevShnarf":"0x0602578e3a61f2be5afdd3ee34c6ac99e1e36a50450c75ef9dd78e50dddd3f8c","proverVersion":"3.0.0","verifyingKeyShaSum":"0xc4a868954d361bf8c18d4b3699c4fa973a6b2e4543ddea0ce7970d6941f55758","decompressionProof":"0x00093ca416fd5edca805bf59c232a873fb42c4141da527c0678cd72d7a262b541ee0c62502dcd1066cfc27745169f852004e16b0be212e2247ff9b7514a755b29384d61b48505abd50581c7d6d904356d873d7cc5c15669731884bc5fc14903d01abb3e0cba1bae94f6b12d101c11e6e8d47be3233a494618f636eeb676535c2d0b7b1b4e70ade42dcceac4f789c4def01431a01e90b2a20b70c2a52aab7839b328922077f08efd55ad0aa81123d9f7206fabcbc6b002fb22549467b8fa8c78c00832451bb84dc3989fe8bdef2d5f3b2292a96808777625e8ae8c4b9b077f0e24fa04ebc898c5c46fa469ab648853ec8018c399463c5abbe3889fc37b56fecd5549f3a8592f0b0f5921075c59263c93e5ab1c23bb14e69206864c5fd1a4be817004aaa2c90c134eeabda1e87867b1a365b9d0dafb6e34a7702c119da7c98b894195276cc80e5d86f2a2ce6717ac31ff1012b2b39b66c806aba82e80cf05b140af00ef3f271b4d4371405277712e36a56941919c624fe9555018053b0afd66c0701273c7c4b4df7e84e132109a2e5faec30a378c3ba2009b3c02397e7a81d3a7be4451e0ac19464417a7291d93028ce9f01a94681c6c4366569dd9cd01e845fd41ccb8a1e445ded75bc8119eb3538de819847bd87cf164f2b4c6813a29cc2812a01203068cd8b25d59d6af6449529ca860801dfa99885c8dbcdce282ca6ad63a389a350ba988cde43089a291d4831a5b8019460774d4c62f6ad2251131fc0f3505fd021870cc73c9f4788c28574a059e3a661226b08cb10d1ce3434fa3992000c002d7e52b3fd13195910bc35ace9d07728207a50602a11578f89b5d9e8da45ae689e0a3f3499b76e05ebf62c6d6c66c8006643cde9efff32e8339ac7a76229c32f4bee6b9a479522ed4153b38d9293a3c13d13743527fbbcca6182e075c9139e005210d5c5fec706015e98eb37277a8e7537b1a99c1433e231f8a9a260f1ff477952a6540138ff2113f2501fa47656f1010c796eb113c58bed5ec2bc345c626ec5dc541e5ef6578691763a6aecf6ce80bd745efe4f5ba5bca99825a0c390e8c9000000070da7ba3d68e13338e0ee23afece9d5329842f07cac052cc5c1d8b76ad947a1610787417dd021a4b758de2974dff8383b8cae702215158443b7bd82313329e78e1204f099508b0495e17934ddf1025a114d778de9c983f5049e333f96e31318120ddbc8fddd8ec0c0cb31d806e292768f3969b8e6c07a7dac68e1e1b5bf616eef0424a2ade2a5e153b2d1fe897fbd44077b76907dc22c8d359781e835d74b9e7b10f2556c99a1c0caaee54325551630aff5cc0807cce97f1551fb3b8e63a91de804e01a567b8ad5e77a556c4d22322a623b69e570db962fc6c57641d3802e2967003f94d56c05840f11be273176beeca8f2df1e55998e3ec66878820d52259adc3b50f0ccbb0357d3291c2e45133ea22c0094862249385ca752c4c028495d663e07c118b5c53059205621b740e7cbabf1ca75fb9e0f729f8f124f6590dad87341080f2f25bf6e40ffd199992bf662687cca92cd28b0ae9cf5dc959fd718a6fba90000000100d551f827c8f4a0bc293490af80f0fed50fc949f52b8a1c155110d7789866021add355e1137b0b5284b4aad346888bb00bdde89038a311b7c09040080273a3241b7fce9645748e44a5015e2535ade474b3699acee2d28fbe176421dd5376674","debug":{"publicInput":"0x85026d7a9847ca73aa12735ab2c2540ae1bb1d6666f3e221577b977a33b1dd8"}} diff --git a/testdata/coordinator/prover/v3/compression/responses/35-37-86dc4abc4be5dfa0ddf8f4b8b98783973bbcd82b5ceff8d39361fe151d4e2ee8-getZkBlobCompressionProof.json b/testdata/coordinator/prover/v3/compression/responses/35-37-86dc4abc4be5dfa0ddf8f4b8b98783973bbcd82b5ceff8d39361fe151d4e2ee8-getZkBlobCompressionProof.json new file mode 100644 index 000000000..ee19fd76f --- /dev/null +++ b/testdata/coordinator/prover/v3/compression/responses/35-37-86dc4abc4be5dfa0ddf8f4b8b98783973bbcd82b5ceff8d39361fe151d4e2ee8-getZkBlobCompressionProof.json @@ -0,0 +1 @@ +{"eip4844Enabled":true,"dataHash":"0x010f6596abf90a103c9558772f56e652de5ea08805763035539bf14bf3c23674","compressedData":"P//DLcOwI2FMHAnG660DHNnI+LSRoulBjHV4RF2osVYj9wAAEAAS8AAQAAAWeFYJ9YcwrXpuBRcO46XbW0BGeT47eVsrQpdd3IbCO7QpG5rticwYJCrqzpuFADpNFvGDB4qL71cC6YIFORuEWWgvAP4DABA6CUgiU/hMAnZIDA84EAZKMNBYVb11MacXM6zur3qeliHCPh+oXS9Gm4uikS9XxcFb+GAGQc/iQBk/gQDJp+rn/wACRI2ghVnaZKmWL3sWQnlVsXV9q89wDRdvNtKZ4AZCT/wwBkjv8SAZI/w=","commitment":"0xa8ae865bfed6134818b5351ae988daa2c9d9d36aa80d061e31a5a405f5e91b36dd1c1c9b4c61061693d645ce72c6dab3","kzgProofContract":"0x8fc4570d6b7747e31e7b380f4cc2e602d64332373fc3b48524d9984544e88186fddbc93364cfba5224c8db4e05b610b1","kzgProofSidecar":"0xb341368ce576f037ec6cb2acf46f229810522e7d7fe3dc5573668d8c324ffbf91c73733545c5b61d125188ee373d568a","expectedX":"0x5159e662a9139ac484a7c4ee2fbaa095cd6f3271624999afa2abccf735e2d815","expectedY":"0x42ab116f821254ca906e0e4a6fd09f178dd8eddda3eba132e91b75d7e16dfe57","snarkHash":"0x10004e1bbcd2739670e91b1f566622cebc1ef7fd1333327a8e89502974a8b7fa","conflationOrder":{"startingBlockNumber":35,"upperBoundaries":[37]},"parentStateRootHash":"0x10556468275a46e1261bd2af01c421e81af255ab49f932de2b6352de9648727c","finalStateRootHash":"0x038f427f164b4cbd3733505c5853d245d3ae4c25dc69716762f2f7f7df68be1f","parentDataHash":"0x011531090261c2af287fb3f766eb58a8a11ec7fb958560efce58f8ec03e24e5d","expectedShnarf":"0x86dc4abc4be5dfa0ddf8f4b8b98783973bbcd82b5ceff8d39361fe151d4e2ee8","prevShnarf":"0xa646621c48d374488e214c7e02a64d431ae0712f3bc817a3d5943914f2246831","proverVersion":"3.0.0","verifyingKeyShaSum":"0xc4a868954d361bf8c18d4b3699c4fa973a6b2e4543ddea0ce7970d6941f55758","decompressionProof":"0x0138904335e4d85f4041c7b1c823fb827634bf04a223423300692e094ba1252937d2e1bc198e5045bfe2cd7316d6f06500127f80e9a42fccbda3fe3fc7257631e8ec2c94b03b2ad9b22ca66f7bbaff6b832d38857cfe4a53a517d6ff514287cf00b065f87eb3dcf1fd062f54457bd3747396dc74ebf693075fda4856bddaf0da238af834745f589c5465e9bebef48102011a665c6e00a1fef0b2a9b9d2bfff5c1ab4c403f657eac167736d834a3efe469d8ad7f07b8d58367815263589671a1a005172cb5be452871913406430a73a1a0e8ca6461975a614d3c1396592cb6451f982c25b00a894461d34bfaca887d6e100cb8e70822949e4eb24fb9b08c0ff0860daf5a479ae73f63760d39920e96244fe6362c6b46955cfa43fc483562740c700f8b0d9e36a8fd4aa589dfb72c90709c01c3c77100e663840634a9eb3d125504e562f75b2cc3e61d932df6151045701001f6a7f9717f8382a16503336eeb63a7ae7a6613d8ea80ccf4cb582ef3bd2e2c1c79f9152278542471a1ff4f190dab300ac5357af49142b13d71852f33384411e149d612f92d15e35295ec8e9bedb3ae85f1b980a70116d1b1d877409b9afd1015f54760c28368b76004fc3a2d5b3ce412a3684b392deb19a9a0b8e19b214b9c123a917c152823c8b6a6b32fc4c3cfa0033111d437cff950caced99105ce6ca82b3aef3f5ac442bd49155c4d100f13e70a57126d8eac29cbd62af4049ef3d32018df891cb1b1f6eb822b1ebc78fdb9ecde9f6cf8889aac946ead38a44383a3d46131f377d72fcc9153ef6caf6c87912009743a500bae16bf920d98d44cfb01689d764e32e7fbdd00dea33900fcc54901e7b1a020aa56e98c3b7360670ce645600fb7e9cd4940198e46289aa86f14c5c31039448afbe9d09cf7e1a8670b5d88367ce96d8b16115e1781d7cd9928ca9dc014a0f409f788107001328a82e77cd2ebc06e5b6c7c97f62d8d2df847c07b83f62c29c2bd571ea292ca9be92cc440b6900a069e97646b4500efda274c783e130eeec9a042a9097b283a401c0a1f218981ed5366891f9ff68316b165bbf2bf33c00000007086aa3037db3f53cb8555f5901c94004614946322af6d0a909921185a4859c88035c3516a6a458fa4b413fa1001db604134ad194ad3d4f3317a6ecf8b8e067320dd734a31f41edf400847b0923ec79efe15c2cf1c1c85077445a3eaf9c57eeb60e191516df1aa1eec89036179bda995decf5879196a75ede9e6217fdc9ced15c0a925f7088de2f1df04bfb828fce1ccc7dd057655d5c5816f47f591b5d7be9e60a1f0f1753a7db7cee8cc08209b016643860a17af74613a5f685b8ee773df018106d5f41bc4d495c85eb349f769e77fb312d8a40c2a665d1b64bdf00bb5b53e701a8d5a26ffd7c3cc2c018064f6083173ba5c5f1d555425fc58a9be27f4a71a7fa6cde1f178389cb8767e9b5a7beb76c004f92779d074fa7095bcbe718ad55dea75dc79d42e6595c5002890a5baabf4c69984825c4257ba8e4746f9996768ce40d3b16c8b33d40069e9ef799131b27ffa3c8751ef7e5bb3d7791edce001d1bc1000000010069b39f014cc21a0f219437bbf5fcb6a6a3654ad5d87e6b0f9d99a3d601ebdc4cec5aa57fbe08b5ba695e0db03640dd001968c26640616c9b4a1b9e2cc16978eefd22d21e0af6c564effb3204254a7743fad7972bedb9032cd223f39d629ad4","debug":{"publicInput":"0xa77a93797117f3499b782c7c31ed336484a1b73ec40ae20243dca9be28f21cf"}} diff --git a/testdata/coordinator/prover/v3/compression/responses/38-40-dec8e24af04a4aa184d63b3f68066b7633c2099aa042bcb37a234c5ce4210446-getZkBlobCompressionProof.json b/testdata/coordinator/prover/v3/compression/responses/38-40-dec8e24af04a4aa184d63b3f68066b7633c2099aa042bcb37a234c5ce4210446-getZkBlobCompressionProof.json new file mode 100644 index 000000000..c58913620 --- /dev/null +++ b/testdata/coordinator/prover/v3/compression/responses/38-40-dec8e24af04a4aa184d63b3f68066b7633c2099aa042bcb37a234c5ce4210446-getZkBlobCompressionProof.json @@ -0,0 +1 @@ +{"eip4844Enabled":true,"dataHash":"0x01e5edb2951948f86cc72f924c12e14428625fdd76461f50ffb63b71b0b673f6","compressedData":"P//DLcOwI2FMHAnG660DHNnI+LSRoulBjHV4RF2osVYj9wAAEAAS8AAQAAAWeFYKtOw1iNkzoyNKNUobYE5w0DtEgrVZLHBIBoAdPulQWNdpicwYJCrqzpuFADpNFvGDB4qL71cC6YIFOR6EWWgvAP4DABA6CUgiU/hMAnZIDA84EAZK8lc7T2W7v7dA24cRNIWSTb6ZHg2MSzVsX2qOkz4kFie7+GAGQf/iQBk/gQDJsxM339uKtJnGYsm9la8YJS0tKqyg6nElrlirIF1Z5b3Cv4YAySD+JAMn/AAAAAA=","commitment":"0x88ea002a6837e3e8d028cf685b099c4cf390fd030173e9c629b61cea91d34f5a728409c9398a57b83257fb4250ea3203","kzgProofContract":"0xa5ac0c37cd220bfe76c7d64ef0fb7a4a014c86d5040f865ec75e3b93c14cd8631484659858241986d745f160c0cee3a6","kzgProofSidecar":"0xa264c904fc01294c2a26ca11ce9b9d11377909d74751d6f2ab44a85a490226b07bc70f5d0e32467e07ef74a33e9b7756","expectedX":"0x91f0eb80c6e34b3ffc3485830b2570d08c4f0a00b898744ac535d216ff67f19e","expectedY":"0x043de442b97386f9a5e9b28a4186a83c499e0628c82b56da5d04b04d243187ff","snarkHash":"0x076f8610e23df1806e0268803e65ebb888bc81093c34922cee5be808250673a4","conflationOrder":{"startingBlockNumber":38,"upperBoundaries":[40]},"parentStateRootHash":"0x038f427f164b4cbd3733505c5853d245d3ae4c25dc69716762f2f7f7df68be1f","finalStateRootHash":"0x086b0a16469f68533a059d3dac85f21d2efaaff0da66110093f85b08623b2cbe","parentDataHash":"0x010f6596abf90a103c9558772f56e652de5ea08805763035539bf14bf3c23674","expectedShnarf":"0xdec8e24af04a4aa184d63b3f68066b7633c2099aa042bcb37a234c5ce4210446","prevShnarf":"0x86dc4abc4be5dfa0ddf8f4b8b98783973bbcd82b5ceff8d39361fe151d4e2ee8","proverVersion":"3.0.0","verifyingKeyShaSum":"0xc4a868954d361bf8c18d4b3699c4fa973a6b2e4543ddea0ce7970d6941f55758","decompressionProof":"0x0181db222ec5f8f5e7e9e7388bc6514f1388677373817b78cc016fa57cdb2ed3c675704a13941945bc4c950a33a7ee8600d24c77d2fa9a01b6fa5fc9157144c749c7d2231781cde12674764e3da34bab52e5abd8ba20d101a484e9d3d6580efd0161494305fb5c522058ed992feb120c61d96e08a8181d423f2d5a24a446f28eb31c69c31461b822b2df68868523957a0138af78e58503cedf79217188fe5f36a491173079b059f6731459ed1e20c1dc14e73e328130c8c73fc9b38cfddf6f54000cd7a0eb93e0f2f1082c5ef8f9c43e4c98f1d3ec62a5fc32e3a2242e6895a8304a4a8782ff1b31f0dc17d68fadbb4b00c50744cc6f625c87ea2becf5863a1859d4e059099fc54c2eb6a42c844049de5e45c3f5ab3c761cdc3d39356bb83d4d0083531d8003af2afa80f811ed28daeceae989ed9eb4b35610577dce42ac9b7110f72cb35e2e356538640263bbf3b8cf008a8f39034e2e67f37513fdfe026878afcda6740aad3abdfcbc5bd9c0fcefeeece6149efc6c1d573c6eaff81e1aaa7600fd68082de2feaa76e365fca89c153da77e2116fae1a2dff647e87bc52893ced6bc758a37eb62ca1c55c25ebbe790de013deead8457faa6eb0c5a31bc70cca9e10e2eaef066dc10225503afe1fe84eb7523ba8309685a761ddf8f832e0b350f018086b73d400b6ab3c3c384bf4ce8a226e5a9e52b704e449b80e127256eb2f740fedaa9ec686d9f6977d2c0f05fb4fb00dc2106dcbb572fb1dc553682e5040cd48c58b4279726f5d7116428553a89997e2ca9e65eb8801e7578daf68710465400064128c1022c2921011a5002bb20d0a39a9121bcb99dfb22a637e72807c68ba63ec6c1018209ed82c43e6f236e2bef017809953b5acfa132ec1b0066c1edade9c9babe5db1453c993c67e3b66b6dea54d2656b8bf82d7ede01eb295bbcc0c401090ba5a886c2ffe27a67d1ee3f11dc5798a608704b704db8b02a30c16d8f5dcb08086630a134feb9fca4369f04998300679775bf94e1fb98ae3784b9dd067f9218b3f56b1c59a21300055b1c99dde880ddb3403dac1601e23b2de3287cefdf0000000701e67668c26ed179e2b94cbec1248564b3027f559d45617dc1b9d019b8b4666b0b989711d2e989b5cfee9b501f6b325e3256bdd11ff35643545ff46a6ae3e4c302d9ddab6b9c64a82bedbe9d8b574908975dbd719dbcc4eb75d81f6fe1cf768f0e46f5b614e3252311e5de6625c3928787b070a57d107c3e660ed4d36704b6c0013e7618e553ea90615ace78509648f2ef4c40abd759ae9899837b9b00ea73130d8bf532b6ea5c1adfc2d7bfcbaa59134181b59ca6c9440c640bbf31d9546d1011f293d2e06bb92de93e8578d3fa2ae857e0e1d7756f6d87f9e6a390143562200011cbba0e78b005b24929d5949d8afdfa46f891b09549297df929e07fa27caa45b83876a2bd8f17c1f1695d4bbbaea0003080723a873fc1ce3b4d857420919d29e3fbe2aa2c87a06673b29f0f55f78d03415ac91410e70db83f5d04a0ad6a49015634f3d5e9c7c88abd35115232bbd54aa63a2768f1e596d4319443cda5a23500000001016b965e01794ef681425fbb2c30008b73caa989228b0a9c7c0cb3a32c7a120e2900feb021543ce2878a30771a4533eb00a70767e519a9f0c2edfe5d362f412da10a98603e3370dc13ab090dca07c91429875669ed25950c471b9fc1918e3956","debug":{"publicInput":"0x8caf0411e624104c7f00762eb90895515cb61f1d5da57dc76ae739c0414a66a"}} diff --git a/testdata/coordinator/prover/v3/compression/responses/4-6-513ed85de5604294e15b683fb22532c07a25531d93f402f17bb4a4c83a91b025-getZkBlobCompressionProof.json b/testdata/coordinator/prover/v3/compression/responses/4-6-513ed85de5604294e15b683fb22532c07a25531d93f402f17bb4a4c83a91b025-getZkBlobCompressionProof.json new file mode 100644 index 000000000..0ce91e43d --- /dev/null +++ b/testdata/coordinator/prover/v3/compression/responses/4-6-513ed85de5604294e15b683fb22532c07a25531d93f402f17bb4a4c83a91b025-getZkBlobCompressionProof.json @@ -0,0 +1 @@ +{"eip4844Enabled":true,"dataHash":"0x01201000a6593e1362c41814298d3cefae56c41fb2726051d0d7638e355b5b15","compressedData":"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","commitment":"0xa4b33ffa5de01cadb07ec72b235ab19a3e45efb7b978ac53e084cd2ee8b29b8e347b1cc828134c4a76a4e0450cb1211b","kzgProofContract":"0x90dd7c402a931f882b203058f1241bea34a3d0c444c344a90653a9b0c266c6c4b4521b6049e210298c1fcf038c346e49","kzgProofSidecar":"0x8f5ef32ca181ed02c546034656dcee85d888f805e6b103d59122012a1376abe03ecfdd96c361d23e933b9dabed892ae3","expectedX":"0x35f257650f08ca1a59a84061cf5497818d4b7882fe4bf0841dc3a8e0cebdfdee","expectedY":"0x01b0746ec8e682a59b780b234cd18ce19d5f50766b4f134e37196ee834ddae00","snarkHash":"0x0be139d44d334d830b01c0a90afe5773c1b19a011e17d38b981326244a44b20e","conflationOrder":{"startingBlockNumber":4,"upperBoundaries":[6]},"parentStateRootHash":"0x12992d60a0ff80d1c2089da74125c185a3bedafb1ff68e26e0cbfcbd9055b1f6","finalStateRootHash":"0x0f603fc5fdb46043a8a04bab525d7f4d966ee254608468da2fef80dc27f54ba2","parentDataHash":"0x01f48456f10caa5029fed9b89cc5d2b3853af3a1b76f0deae6ebb5a2dd1e9ea2","expectedShnarf":"0x513ed85de5604294e15b683fb22532c07a25531d93f402f17bb4a4c83a91b025","prevShnarf":"0xc185fbadf462de3a6c8517cbac3ba7402a14e939e1d77e3a515ca1c8a3f7d977","proverVersion":"3.0.0","verifyingKeyShaSum":"0xc4a868954d361bf8c18d4b3699c4fa973a6b2e4543ddea0ce7970d6941f55758","decompressionProof":"0x013fc5fd42f8b151c71ad5bbea917793119c8e2e09fc33a289e2b3f0d6909f2aa0988bc1c1fec0420175ae283aa518db00fb9367f93505cc7493ec7c48aa3a727422905c0f82d56e675498464a5f62bacc6a01095f21b12a0f76516e6ebf6d80005ae49fe2dc50a51b9124389a1470de00f64fd5646566791d54d5729b364a8e1a61e37077d6a552f75afe5f2680f86400f3bebe0cd08de00173f3575c97c3498451df5c67e13a09176c8a99fc94601addaca6317e12e4e19be5f643e7c97cef001c14d2f7b4ada58028d966ad68763234c7d098ff0b05831fbe0dd190d0ddc06cebc1014282a51793a93a3e8e0cf514007cc6537c68027bcd328835781e9056ce40c2b8018ec793a2d959f63c9b5a4b6b8e74ae354ccfbe04fad16f3e9a57f100e9729e2b6829dbc72107ef9058349012b719e3d93a5c3b4cb95f9764135ccd4efa365d31ac96497b06e6d26c3cf0b70106f3229d1926dd38f08d65a2f1cd440712cc58acda91ad8afe56288b55ccdcf1897832b2e124ccac0d7c992314796701460d816f854aef5b50019257161f715ad75b81c10accc730ee13e32e950efe38304136af93d264f8d065c4835516f60180d964c73736c5ca237153e1471a6df2edca0d72788e12c2a425727657acb0e4219d400facc9db001ae7b0d4ffa82000a931073091b32430ef1ca7557b3556475bbfaee3b660699a52014d84e1935d9f24205fb8ec494228c73faf7bd56fda0032cd2bb85e323a4f8a326cb02799e9d5a035fa4fbb0bd99dc09afcbf2fc04a6d1f1b20fb141bf2ee21837fcc91e14e0115fe9302cb97b5880048f687b369dbc6e2d513f1f2bc5a4efc9912b7fb2cdfe90e34993f3e1a612f80e8a0f8bc7cf801a8af57aa6a1323036432c785e3280e52726cef8691ac51ed7474b82bd142fd50fada15bc8dfa1d37e3630f70ac07c7001816f9f705c979fedac704638792542f3a534888586147db0fc14cc207ccf0484265a4e75891ff9f3020c93cd94e6e00a0a73417ab3fa13a6482e19b29634762afe22f9ad73da4692c70e3978d289dda73be13b6c7d12049434fce6933d2c1000000070baf3bc46ecb7f93b6af21a8dda226f893a571ca21137e2853a46f9d367f20ff08b6db98ada60e39e2790aa3e722265f76a9fe0c1feed9354b9ec701f6068e8c0b472aa936d3c1ac74315aa3ab6a84280cf0e1deab2fd54a58d730de4d7c99c0067bd7610d07406291282488b0d84f0730a3cab54f56dd6676615e66505688f6055ea5310b27a9d85a67c1b9949fb3af4df00a29505876a5f0c92ac93ef3db2709f9c707065bf99cfdd57107643f22cefd4e7a1ffd98ab690afffffc6ec0434f005a237c1730b19437bacaa353b49aa7b604c8edf4ba4ffce91b20eb5cd8a51500d298bd1c0efab923971eff2069e8007a4fd8e2572c9ffe1f998dfdc3cab48d4e30da0aa890987bf3262e391ded95a3001a006666c60b8b79db7fe36716f948a0ad6efbf6b2a872730f93788607862f805a0ea2d93b66c4dd4eeaf26d3de1e60b05f46ce37e240bcd8c9bd09a9ab9ee78858095b33d0cc9b95dddfc7776b68a000000010143f378c1e471de884daaeca16d35903364ffed01dc0e1a75e1ec6bb1d65213198cc9b1402317de30fbbb5e8aea4c0e019a4530fd01a28ae6b1a2b3be1070010748eedbf0f55c2fa5e547e9a59792c2bf7df47c65091c24ff9f064999786fa6","debug":{"publicInput":"0xafd672e17d75b7f2cd85363fd0f8aae48980939381b157b44af0e9a13919715"}} diff --git a/testdata/coordinator/prover/v3/compression/responses/41-43-67b48d2e3c30f21caaffe8677e9c8a84f43ae1e7ee936f0f8c03c4941cf04695-getZkBlobCompressionProof.json b/testdata/coordinator/prover/v3/compression/responses/41-43-67b48d2e3c30f21caaffe8677e9c8a84f43ae1e7ee936f0f8c03c4941cf04695-getZkBlobCompressionProof.json new file mode 100644 index 000000000..b021cb64e --- /dev/null +++ b/testdata/coordinator/prover/v3/compression/responses/41-43-67b48d2e3c30f21caaffe8677e9c8a84f43ae1e7ee936f0f8c03c4941cf04695-getZkBlobCompressionProof.json @@ -0,0 +1 @@ +{"eip4844Enabled":true,"dataHash":"0x01ab0956525f99b22c1ecaf9757afba9cc8e88b55e1e56385cb4f8bfeb986e78","compressedData":"P//DLcOwI2FMHAnG660DHNnI+LSRoulBjHV4RF2osVYj9wAAEAAS8AAQAAAWeFYLey33DP+OOhd34nrN+K7h0BZt2AonPh72J6uEMd3WgS79icwYJCrqzpuFADpNFvGDB4qL71cC6YIFOSGEWWgvAP4DABA6CUgiU/hMAnZIDA84EAZLsE89kAMenwBQ68jZTgh83WOfBgSVs14SweetowUfm4qD+GAGQi/iQBk/gQDJvy2px+cpNqeFX/xEeKjAKWbTH6vI6zwtSEmXImGiB257f4YAySP+JAMn/AAAAAA=","commitment":"0xb9d059ed007983176e704d6b9d339fcec406509b1b791d7986d7f19d323cf7ad38bcd060cd34fafef44678f022182012","kzgProofContract":"0x813564c93ac8a268eed8b2a36d01e6ba3b73f2b9804c388cdee231105b58d9c48f474b6803b7a9dcc2ce970c51b9cff4","kzgProofSidecar":"0xb2b6f7e1eb2cbfde8496d49c3e523a7fdb14d33108d7c24685a71c9ab8013f97a7784b5a61372336c01fe698289cabcb","expectedX":"0x5924ee5b7142b5737ed187b3cc52abbf26741c8cb7ae966e1f7cad22752247ec","expectedY":"0x666a9e9b0c0d562e1cc636c44dc091e0d0b9486167c74a9050148cb5098ab4ac","snarkHash":"0x037ae0babab25f9cb90125fa74a38ffa96757031a776254dcd6a8c6a73c21d9e","conflationOrder":{"startingBlockNumber":41,"upperBoundaries":[43]},"parentStateRootHash":"0x086b0a16469f68533a059d3dac85f21d2efaaff0da66110093f85b08623b2cbe","finalStateRootHash":"0x021f2681f4ce68e3b9f77c934ec0599899cfc96c873e6a9a7450e95c5de230b0","parentDataHash":"0x01e5edb2951948f86cc72f924c12e14428625fdd76461f50ffb63b71b0b673f6","expectedShnarf":"0x67b48d2e3c30f21caaffe8677e9c8a84f43ae1e7ee936f0f8c03c4941cf04695","prevShnarf":"0xdec8e24af04a4aa184d63b3f68066b7633c2099aa042bcb37a234c5ce4210446","proverVersion":"3.0.0","verifyingKeyShaSum":"0xc4a868954d361bf8c18d4b3699c4fa973a6b2e4543ddea0ce7970d6941f55758","decompressionProof":"0x005f768c4e5446a5fa499956f3d6df68f9c8e108af232761301f233773c1eba2ea16335f278f5b534b130386a4ef5d20009ea82ca0a560a201b0d662cf316c31ace887ff81f2ca13d3f7a124b17ef81536222a6fba005176133bc9e5eb99bdbc01330a4b6208200285e3730f4465a9290411bb3260cf9388300d393c063084caa49a9c52f7bf897652bfaa69a42c2ebb011318abf31d7ffe05f423adb7e582ccac05b8223636715dde3ef67527cad923b96fb0b2c0e14e520e561b8e46b45ec40059ea108b9a6ee6c9985f4185be06645146c759b900327b99deb1e341feddeaec6c8f21b1045b016cf80ecc0ea421eb0119d7048a2260021ea71e2f04223764ddd20b0c3c385381022d3d44eb39ccfec079d85a3cf5692cc34653a92b033a7300247bcc911fbbfe57c67db3eba36c44b55f9a0ad332b55b541c320847b3c702e54bf15d24feac51b64f28421c42f89f00aa37ebadf3665d2f911760ca1bb4eb17c8f735ea03310485ab954e8647562eef4f4bca236e6268f91acf06ca4975b9008ddbcea12c5e294a5998de6aa1b3c7647506b53cbab1b5e8c10ca27aeb669be539ca8764082b2ea51267e5c3bc5f0401a196de16417157fb9a61edb2c3038ee3369c4e5de93455f61520ae21e8ab625ae6c54dccbce637a1cfd50a2306a84300c6b9294f9f3b087dcb615584e9e8d30fc6369e7ef97525b88c91879ab6cf41e97b6fbfd074081c0a6fd24b5624683100ccfb0c04214f4b980999fb6ada1aa94c2d6dc4d492265b7e932f75d4e13981f1dad4b986810278cbc71654044adbce007432d67bf8f2936489f922372cde647708f52279004752844d7f0dcb1c4f9e814b4f24fc8b90967ea44514b39a038f00e3a75d6d5188f4b41c4b554dc1426256a2a07591ffb5059692624c1e3e7ea07279ac40e114b344833982bfb530f5a500cde4fc3776b612c878e0ca7f75a6df04013081517d8b90aa9726c5f6d77ef98ed3d567259c60f6afe8b21d8f586e24002279e55c12795a103272547220043461a0f462c6eca937b2c46bd2416bc2c1f12c49891d2e5fc37cf89da5e7166a380000000707a3c1e65298abf000067abe4d14fa517dd8bef2d7a82b0528592123bd22620c0440785cd42ab55db957306cb5119186758cb6621c73094681210278ae9f197009970bc83b6a7ffee4ca94d76a91b6e410e80cce2ece91f903bbbbbca3c814f60c5e40b97886f45225e8bc659e6624eaad13bbb645b27fc971268089af53226e0a7692a95887f9de00336ce7b9366f0fd79aead5faefac43c0edd900bbe861a90439acf5d97ee256fd211e724fd60dfc7978cad8ce99e1d9feb13a1c7e7a486e06db9bc75d12fdbcb83f07748131ff57c14e5c88464cefe1e392d9e3d39a766301184393c1013fed558c22d785099ec3c206d313726afb2f3f51e7c7effa976b4c8e3c2b0e2dc6c2d298d43f466990810139b69fe8fa7d855c843e24a66894e1332d0c016725973a3e0f10b7929b2baabcd85068112d2a8e997db495d75d97490347e83aa5a763dcc300c2f8cf3b95e0b5500e24c9b1018219ee70d971b1b23e0000000101307aea552db3c5fd9b3cf833df839be6e4fb5fb1374ee0fd9cd20d1d66275f37364f64fefd956811404e38533327a900fe5e332b514fff81c5085c0fc55dc48e08ca847e81b45f5248c7d8e5837d753a6c5294667450ed7acfea55d54f89af","debug":{"publicInput":"0x127a19dcefd592a60d16a48e3a502bf3da5555d8383cd100ca90358814f0c98e"}} diff --git a/testdata/coordinator/prover/v3/compression/responses/44-46-e3c210adb4a5b495db0a285094885c32b74bd6cc85bbe0e0b5a6cdf7e88387da-getZkBlobCompressionProof.json b/testdata/coordinator/prover/v3/compression/responses/44-46-e3c210adb4a5b495db0a285094885c32b74bd6cc85bbe0e0b5a6cdf7e88387da-getZkBlobCompressionProof.json new file mode 100644 index 000000000..7a0255b9e --- /dev/null +++ b/testdata/coordinator/prover/v3/compression/responses/44-46-e3c210adb4a5b495db0a285094885c32b74bd6cc85bbe0e0b5a6cdf7e88387da-getZkBlobCompressionProof.json @@ -0,0 +1 @@ +{"eip4844Enabled":true,"dataHash":"0x0104998034ee589f662c8b801b219074675af50a522d9281f23e4ff8aea8df53","compressedData":"P//DLcOwI2FMHAnG660DHNnI+LSRoulBjHV4RF2osVYj9wAAEAAS8AAQAAAWeFYMNg7PIsb17foJWFBEnw7QiBiN6UTGpbzMv/VG4Fje61apicwYJCrqzpuFADpNFvGDB4qL71cC6YIFOSSEWWgvAP4DABA6CUgiU/hMAnZIDA84EAZMd6fgOt0OZr/RfgK+JOFkDe7kJ0hnyVWwGSnSLDee4oHb+GAGQl/iQBk/gQDJzMqao+HgIBP6QVdTzXxZE0pAT7hENJw3YEWYVAWmtdCSv4YAySb+JAMn/AAAAAA=","commitment":"0xb65e93b0e8b4f4ab4a2433eb01f95908d1f4d34805758625fd49d13bb72a8bd96a728cb869a92dfc5af02269693b7527","kzgProofContract":"0x8e66724ec9eaa9e9775aa8877068d181437cc90bd33424b455de29f6ddb6c12574dec1a78315b497851b3c4395cc3a23","kzgProofSidecar":"0xb82ed057521fbb01dafee79644b15d77e30f46d60df713e42fa15fd203fa0e689d19aed9db0ef8e9fad063a9111d8d4f","expectedX":"0x2b5c95e024a5c8d6e9d767adfbd6e5e8afbb1ea1ab073d6dabf339a8eef4af18","expectedY":"0x267e4ae71dac6b64f616d12c0b12a5409f5ec513123778453bf6afca8305e15e","snarkHash":"0x01f556a5d2fee7beb32752174fcc462526b9b878bef030f26fa34233c78984f0","conflationOrder":{"startingBlockNumber":44,"upperBoundaries":[46]},"parentStateRootHash":"0x021f2681f4ce68e3b9f77c934ec0599899cfc96c873e6a9a7450e95c5de230b0","finalStateRootHash":"0x07a612f27fc38d0c22d8704b9bccdee3de51e2b3ec3c5ac3ce61f5e1926f21cb","parentDataHash":"0x01ab0956525f99b22c1ecaf9757afba9cc8e88b55e1e56385cb4f8bfeb986e78","expectedShnarf":"0xe3c210adb4a5b495db0a285094885c32b74bd6cc85bbe0e0b5a6cdf7e88387da","prevShnarf":"0x67b48d2e3c30f21caaffe8677e9c8a84f43ae1e7ee936f0f8c03c4941cf04695","proverVersion":"3.0.0","verifyingKeyShaSum":"0xc4a868954d361bf8c18d4b3699c4fa973a6b2e4543ddea0ce7970d6941f55758","decompressionProof":"0x004070a15373a30cc508ce0453eff79deacf22c4883965b1b1738f6eac8fcd777b9e289896e37cf37541512ef1f3f23e00376a8179dddc64ba87cf5dcf05d0e06e70f76821312019554d49e9b2c0f3ac83fd8dbd9ff96d4c0e795312963023210066dc50be0ed7d9030e56ef630beda6b248deb04f1ededc0506f5777448fe784f2b78595ff652df49f03c07a088958f00f6bb273ac263efe144d7dd654609dd869ec01908afce5e5a62ba055005f3f0efe4d94478fb3f396e70f0a61c54612501785128c9a91eb5f4a6058be2a9369256c81c5914f815469c6c8a4015476c01034e8784c86da5ee9b939712e187b34500ab4420f5077a775d5e64826b2494e1fbc6b52cc312c0f90f780df4312bdf89a76e81170da65b24ad9ce9f4be1577cd01548040e80430b04edd6f9b5547eb529d05c2b905f8b6f7780cced8d807518eeca023096e7d22943b01268a941d3c8100cdcab8b5219b638e4e00c18ed408808cd3913c5cc86d49a32066724d33322093194f3beceabe01eeff29d771b86cf9009fa38a68f655de9e431c03d4edc09eb226b3d88ff435cc838cf229c0e6189220017d64c8b345a5e150e4e7878d75ab012ebabc892400c7bd01b78f868ea91cdcca4ebdd7ebdc88bf9d0ea71571b9079da6b600f15454f59e37810cbf689905004f4843155717cc623e0398a66651ab28ec41b42053605faf04a6d7bcf913c6e6efa223cc5af4c9bfcd9162c7d4a86701aa659af2b1c9dde6782e1c7fabca0a806843bcad4533a586a016f0bff8a231a55d9843f79cf882bf9ac53766fef45e0118fb4c9781fdf8085c37a8c5972ba2b8cf6330a4beebc0eeb0881faed096a552b1a52d36304d39d790c420c7819633009deb733591ac2d64d81a6996d5de3ce04274fae364f91b9021dd12785ccf8d2058fcdf2dd774cbb59742ac300cd49c003b218544132c803dfedc4f7a37e799f6bb149f294e4d81cdf477e38820b1c6d97ea3ce7bb1073b7e477f2c0476249e00c35ebc7917b47721e4f48cce1f6cdc4b10c5581da51ea89ce7a6e4e7dc6f48afea20d286ef8ecf6e55db79955e4172000000070d073de51afd794d9939e2eaa11792d702e50ba6613c2bf1e515ab4cf9549229116e735bccd2c39829cfa158b8881828bd5024ad4fb5e4d6644b9ee513ea53890f0e666a57c36929abacfb48ecd1891788a9d7e0015142c4618b1e321fd5a65005a728f4798da3122bb579ccc1ca91c364631ae90eb7e03bdcc77471f86334c10ea700b889b244c144d1e35a2133def3120f6dc03f8880fa4ebd920b9ed6e2ad115324a7ba7f0724b8290f027ce5fb5b09e36cb952a065aab24cd332c2d51e8008e9fe1e39028a19050a8d8f1956c3d9b921f5cd36b76a789ef90e560c5775120005161fb71a768e5e0665ddac9be04de4079090304d4ff3790c90184634f0385dea9d0e8c090ba24f9e3a695117a530012b7f960a7cd564dbd0c0a6fe9342ef65d1f0909249f957d90981ef29ecb87953efc0e8a3a40835d4abb036d54117b90a10ba23b1b5ca8a34ddde7ec7b2fbc3281a41db1b4b7691fb1839d03014ff88000000010043159fec81650afd6dfed546f69522ea21f247e214112cfe19d903f74b204b4670dc0138d23f32c9cb296100500f4200c9ddaff32f2cec559a6ae0db13a4bddc5226e2620e054c24f647dfe3fc19023dd96556c77b8246b62d14e292982bc8","debug":{"publicInput":"0x12760b62e87dcd4b18807a7c213d92a2d76c0c2007c76863a3c9f96dc72d608e"}} diff --git a/testdata/coordinator/prover/v3/compression/responses/47-47-dc73dc616fccf89ba4b33ba446a9b73b5a1836142e0b1be933b7283f6f2b8061-getZkBlobCompressionProof.json b/testdata/coordinator/prover/v3/compression/responses/47-47-dc73dc616fccf89ba4b33ba446a9b73b5a1836142e0b1be933b7283f6f2b8061-getZkBlobCompressionProof.json new file mode 100644 index 000000000..b8da579e2 --- /dev/null +++ b/testdata/coordinator/prover/v3/compression/responses/47-47-dc73dc616fccf89ba4b33ba446a9b73b5a1836142e0b1be933b7283f6f2b8061-getZkBlobCompressionProof.json @@ -0,0 +1 @@ +{"eip4844Enabled":true,"dataHash":"0x01e4891ba581b2c658fd0ccd0b7084942b7e2ac4252e9d93b15bd71d41a44338","compressedData":"P//DLcOwI2FMHAnG660DHNnI+LSRoulBjHV4RF2osVYj9wAAEAAGUAAQAAAWeFYNBBpv8BBSJfccXONjKQMTUDl9mEm+8Tb0jqzjQe0GrCcc3yTMTmDBIVdWdNwoAdJoLeMGPFRfergXTBApyTwiy0F4B/AYAIHQSkESn8JgE7IQGAA/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==","commitment":"0x9980568f70dc0b51ec9c64e3d9c115496e341fb8d782dc4a8c59611c7a1d005accce2d142ed4a2903af13837bb11035c","kzgProofContract":"0xb81586d096c043bdbca5da761dc0e686db316bdb45a5b134831019fe4bb6b6a00584542bd715622aabf8fa023a5a6adf","kzgProofSidecar":"0xb42478edac770629a9c3addc5cd9b9305cfc81f796789e6ac52398d219d4357ad937c6964942db8849dc5b8fefbdb0ec","expectedX":"0x51b4c44dbb7ff243628227c8597cbc6cca382a7f5c260e8d092c804d1aa7e2a3","expectedY":"0x25191ec6ae8b68aa682c11a97fb1b76473b4c686a81e6ac2b4386566cf3a847e","snarkHash":"0x06b336651388464927964c592958a9b5bb7c2ea2d1ae852b7c7c2c85379e7e48","conflationOrder":{"startingBlockNumber":47,"upperBoundaries":[47]},"parentStateRootHash":"0x07a612f27fc38d0c22d8704b9bccdee3de51e2b3ec3c5ac3ce61f5e1926f21cb","finalStateRootHash":"0x08a16016990b33c1fc814a077bf831ddb13bd07f440f3e7d8eeb7fde135a58df","parentDataHash":"0x0104998034ee589f662c8b801b219074675af50a522d9281f23e4ff8aea8df53","expectedShnarf":"0xdc73dc616fccf89ba4b33ba446a9b73b5a1836142e0b1be933b7283f6f2b8061","prevShnarf":"0xe3c210adb4a5b495db0a285094885c32b74bd6cc85bbe0e0b5a6cdf7e88387da","proverVersion":"3.0.0","verifyingKeyShaSum":"0xc4a868954d361bf8c18d4b3699c4fa973a6b2e4543ddea0ce7970d6941f55758","decompressionProof":"0x019271c206505c6736addab5cae19a152fc34708732c5e89d1db620a321ecc6e6534f23f193b9b19d0ecc2d34d7eeb970108a057bc021e84614f83be33f7b8a58f511526c70497d9b8a4709e486ad43b6847b73f60f1fb16acf6c1372a8a08a60009c8b21bcdcdfa7523f1fcc141c70993cd70eeeddab98d2d90899fe616a1ff5f0ff1ef6809027e45668a0164744116012276985fd89250507ea0612182c3f4d77932e019bced52dfd32b9dfdb792fae70e185461f2bb500b0e2c947be24623014d9f6c662546b9c3249e0b5c63768912b666781ac16f3e28ed8267f053b89868daae0e352ec068c4b7765247aa1fbb00721764422d9207c38077b149c8599be0e722e87c6d8d82c5d6b108d3945e7ad150bc861979cfbd5fe0cb72aebdb42e00261a8e08a6f801b68e94132468b40096b02ba0e29a52a2d95f4a1d05242e53d860af4dffa155f9f0d92476f5c86f2300fa3679c130783d08edce01b3a67c06a1f98e9076dedd2ee82c2e6096e22e58779f332b5214d8641e1a0e632622069b014e113d3ec0ca5bf5fc2acb022e1cc866ae1ba98ff1385932aedb597fd020cd89ac773a8c04a1c2f240cbce4be673da000b3c54b093a9804ea5f2eff3d62e604521f2f0ac34eaecfa12f81c637f1086b5cacc906809e97435519b479b54d95400f83bd803c728fb600a74ab5a1803843d70794083de3ff9d9993b541f378dd25a47c1f7cb84a5b6b0217727f2ce359f01338db9dfb27dd0b55e2093280f6e6d4adff3152201d0057ee47bef901c9b6d7260550062b1da8c7f7ecded90543fd9004d28839691ba27ab15ede4dd74dc600d788c54bd160bac035ed81ba89ad94812e96655af6df949ff1cc86ed824edc4017bc337568d138f77f6acc31c84ec83a99d985524e1a30a6624a76b82af6734f0d06186afaa5496615449c7bd6613e10020e71d85766c4ff66859f8a436157580b58c34c07e2fb507f8f9975582ba0a4055423e246027855289c59f60de6e7b011b240762096b190822ce227834c93da49739bca3448c29f9e0925cba9229a604cf1b65cdb70a30b002f95624ddb6bc0000000700ea431eb8748dbc6cac00beee748959b30eda33143daa26ddadd8c1f360b98b0fa6ac0189785e5d337d5c0783527da9d65fdd879ce51b9a2cc2e8c5ef61b26e0c58f3a9a34cf8d731f595af4cd738aff5f04e1ac93911989c2cf7078e9a1c3100eeb2f2bc7c93d43dfd2bc7f2a54466f21d52dd763952d8d23cf3649737ca4d04e84cb456972c3c0aa021ff26a97bfb4305c24dbc4c904be8a056b1d011a96c07bb930fb96b6ede94e10a34fe116d950388ed5f631e6b7e4cae21c21b68607c01f7b5ec821096a01d87c76709e83110d6e33454fdd9e32cd7c00564794c5c8b013e376bc9a91a2af0f8b8eda62e290b0aec029ab5e1d4673749ce341abe8938157d4baf2a5f0819c8b3a4dbdf94afdf017a0e57b3f1339d3c27b22871b308142ed9c7889f7b68c8b94e14d12d6b2e53f5a037df2160797e5be6107c847fae3b10aec6f9d63eb6a35517491cbd7416e9c810b46f13fef54622b07b5d6ac909010000000100c22f919dcbcebeadce04ebc4416a3617969e6571b1178c50ebc31e5cfb3116e9384715e5972665af71a25f1d461c1e008e00d4bfa11422bb6f85e5363027e8dd15fb2dc5b97bcd6ff45f9795a3f31a4c72e44a5c093e1fb9358942a88d846f","debug":{"publicInput":"0x77c1834d54f520974f8b332dc0d192f646ec9c3d1a7c0fa858317f072a79322"}} diff --git a/testdata/coordinator/prover/v3/compression/responses/7-7-7db9a7cbfd21211ecd77d8791894eca4478be04c38002a415dce9eea9a7d39cb-getZkBlobCompressionProof.json b/testdata/coordinator/prover/v3/compression/responses/7-7-7db9a7cbfd21211ecd77d8791894eca4478be04c38002a415dce9eea9a7d39cb-getZkBlobCompressionProof.json new file mode 100644 index 000000000..320bd8809 --- /dev/null +++ b/testdata/coordinator/prover/v3/compression/responses/7-7-7db9a7cbfd21211ecd77d8791894eca4478be04c38002a415dce9eea9a7d39cb-getZkBlobCompressionProof.json @@ -0,0 +1 @@ +{"eip4844Enabled":true,"dataHash":"0x0122ac92a79da67dca1dce1ee4bdc30c4e945e02664463d0924ae3b1b9c96594","compressedData":"P//DLcOwI2FMHAnG660DHNnI+LSRoulBjHV4RF2osVYj9wAAEAAGIAAQAAAWeFX8sdfcGnMLP8G+CncyCj00SBllVLy2gCEAeYv2Xy+Sh2Ikbmr7sMhXYreijNgfyzw9D2Dl8NAC5oIFOQeADoNMS0CUmX/Drx8ZPL3AEwYAdsYehPiGJgOgIRpBpbwwP8AAAAAAAAAAAAAAAAAAAAAAAA==","commitment":"0x8839912b7ff8691e96d04e9422ec97fb935bf8928aeaf8f92a834b87345fa964ebdd5b2224e4045bf545b0bcd5aabb3c","kzgProofContract":"0x910b5a131d90b020ceb79174a0f4f130a5ef6cb31f6d7da6abff60169e5085abcf3a320f49bda75781ed7155c4297cb4","kzgProofSidecar":"0x83f1e95ca35e30ca9294af91dc459f84311103a55040f501550df8e0fd5f85f5271db168043fec9356d3cc79232af91b","expectedX":"0x4b00e9e2b96c643454cf1acc28cf685f948ddbc1fb8b1809b125cc04b6e5c946","expectedY":"0x26909f5154b9a6d019d91cae6af1bc690bb9005ea5833dc72e5b8e0a9a20ab93","snarkHash":"0x050b4aced7f075dad433db123c32b42603e77ce67b5f93b02531c6b423212531","conflationOrder":{"startingBlockNumber":7,"upperBoundaries":[7]},"parentStateRootHash":"0x0f603fc5fdb46043a8a04bab525d7f4d966ee254608468da2fef80dc27f54ba2","finalStateRootHash":"0x00e974de2acac404377d2d3856a35cc1dee03cb25af603f111442cf8d8b0c700","parentDataHash":"0x01201000a6593e1362c41814298d3cefae56c41fb2726051d0d7638e355b5b15","expectedShnarf":"0x7db9a7cbfd21211ecd77d8791894eca4478be04c38002a415dce9eea9a7d39cb","prevShnarf":"0x513ed85de5604294e15b683fb22532c07a25531d93f402f17bb4a4c83a91b025","proverVersion":"3.0.0","verifyingKeyShaSum":"0xc4a868954d361bf8c18d4b3699c4fa973a6b2e4543ddea0ce7970d6941f55758","decompressionProof":"0x00a23af47d0a9709c1f529935d545e3e79c37859682dc1689bb55bcff024d74e493b7dcc103b5c53b0f986e658bab35000ae8a0dd3dccff134d203b1d260be50ab7d5b1f8882d6fa872d696ba3f7364e729366715fa0ce410449d82e2a1ba85f002d036b0abac7f916187a71ae8301debf66c704965fd5afd7e25718653a18ecd980abba9e9044640d6872878fc431e500f97e101480a2a21e3c2904f4ae1d48d0cdb6cbca9b9c59982fa6a169101a6de41435e4c9a3105ed7402aa3a4356db4007f16f162a2b70f80d20abeb844da1b5f0dec3a6003badfd8a710dc931b55b316e442778b6f1526720a3090b174e2ed011a7544f4a5fa98b146da07071d4c7be31440d309349c63a68d5da8cb9893ec690af6e90f511e60e5ea3afc91c48bb800ffa14f061887c3f6dfa3ab3a8a00831c5bcb3b32b096b0ad6c9a7047b138ef77c2bab962a5cf23f31339a3a9037ef300883ce9d630d884eebde44eb1aac1a5ea58e1d8054c854f79ff3ca719fddfc50aa1ae839081a3dc66be897add6c01200176358fa7bd897295a6adc274e6e659e024fd525cade3dea945eabc9462d31b899c55c58d8fbd93e33690e5b065a2bd0199368b0724a50f55ac1584e5fd30f3ca13b129f8e79b44fc322e97c277e678bdccad2a303df395785fa76618a1dc5d01662a653dcfb47e9765a3a30ff1ce73baefedb4125673898b134e0e485b004b1ccae038c831a47a6dbd3d9d24d8807200385cf8ee32d9fa9bcd9bf07b59d374a9fec1788f642ad7df331895f40b97a8652bb130a0d4abaec2765cbd62a88b6c005b17fc166a510469e1e626334db915088d0895c28c6fb529b3db12ca645165c5fe715bcaf6134a5e8685535bba6930002ea0cc9aed42d888f62a31d9c22c9a63cf38855530c53e7b72a11f1970ec350fe52e3be1a8ab6355caba5c6483524d0152ee7de90bce155a17a6b1043d306c7b9198fefa78ec63c8e938a86c8d1289cf5df20821f1693545bd5f232dadfb3d003128306a625119cbc05982fffec6182ee5b4e1eb9f0476b61375712d19e9b097dd95db9d8e61b9a4a0a85d37ea564100000007040731c20cf9e0adaccbf9b82a097c9e3e8b5d151027075e1c8b67c2fe6cf1f004631a4d68073b4a50ccd81062e105740556a238fbb77bbecee9a8b23c116c620eafccc932e22e8448a5232609b026005a377560ed61dc93ad9273e7a64254e710bd8ea5ee900a485d072beda1205e73bc21ea23b34464d9af39f1615d25ddf0097b9dc1e8675909a914ae7e2c3dd93ecf35f3492b2151f1d8196df801c97fc9037568ce2aea0c73d220245894e9385cd9f7d87fc2604562b7501b5e81b1737502842bcf1c35cdd466ebaefc969feb64de14bc0531fa22693c9f4c643093b8c80082fca0db6c0a2d263b55539df3892123ea5a6a0ed725dafdb782111efdb82beda479f78534bb647fb64c74ef688fc9007326547f3e97b86617513ab066f6f42bff1baee921157fd347948df22b33af7c0ab568102170177b5f24240b00cc36061ce55676e217ea42e737962ca8820b04e54cab18f8866474af9881c02f46b400000001005fa32579e83903a5116e13cd0d8003d3c76d03d186088021a7ab64156f29ca6bf63fe29e642f56905d10cd6d6d68d800dba923c8c2b7015064ffd8e4fdf7215c725528f6ebfb7bfa3ca8cdc6179439b6c0f028ba88dec135badccda86a0a53","debug":{"publicInput":"0x3fd011d04a20b79f8182be8fc90ca217520f3789da609c7c11064fd3c89d821"}} diff --git a/testdata/coordinator/prover/v3/compression/responses/8-10-e6a7703511076e3789cc25059b468940b2e91df262f11b95b9005f758482aed7-getZkBlobCompressionProof.json b/testdata/coordinator/prover/v3/compression/responses/8-10-e6a7703511076e3789cc25059b468940b2e91df262f11b95b9005f758482aed7-getZkBlobCompressionProof.json new file mode 100644 index 000000000..85a906051 --- /dev/null +++ b/testdata/coordinator/prover/v3/compression/responses/8-10-e6a7703511076e3789cc25059b468940b2e91df262f11b95b9005f758482aed7-getZkBlobCompressionProof.json @@ -0,0 +1 @@ +{"eip4844Enabled":true,"dataHash":"0x01c993ae52495203ab88827c3111fcf3b09c16655c392dbdaac614dc00473c32","compressedData":"P//DLcOwI2FMHAnG660DHNnI+LSRoulBjHV4RF2osVYj9wAAEAAS8AAQAAAWeFYCtie7H4OIl6mfOCG7s67wIhYeVg8ALDFACMJvvVCvxtDpicwYJCrqzpuFADpNFvGDB4qL71cC6YIFOYCEWWgvAP4DABA6CUgiU/hMAnZIDA84EAZC7IA1dYQGGjAS3wyc0PObzHDrPMsn9iU557/wAAkIY37D1bguP8MAMgD/EgDJ/AgGSZ1jf/AACah9TBhPD+q8uXzGs1eSSgdJ/m8N/vPaC9JV01Xqv/DADIBfxIAZIP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==","commitment":"0xa5aa451141fe41b879aa058a20be3a9eadb902e7be4ee8eb7c5d26112e47728d3825f7cba01d64bb26a9f55dc2e0a0c3","kzgProofContract":"0xa385455eb5b14fb2fe4d7ba3d19d937a31dc31a99053496c9c93a3d97656a0fdd90eac58472a349003328bf998507b69","kzgProofSidecar":"0x90c042e73776f784b7a0e0f2469bd500eece6557f290ba30659826c85de769b7131dd85e01af310672e44e2a3d5cd759","expectedX":"0xaa7351229e2b16408a95f939adb983640536ee666204da38047aa64cb22971b0","expectedY":"0x5db2935089470a8bff08f797b4ee53249e3fb44dc7e42f991cf59b60567da524","snarkHash":"0x0cb4e1fb16c2eb266b8096b81207af2e856d76959014e7b468818eda7f51114a","conflationOrder":{"startingBlockNumber":8,"upperBoundaries":[10]},"parentStateRootHash":"0x00e974de2acac404377d2d3856a35cc1dee03cb25af603f111442cf8d8b0c700","finalStateRootHash":"0x06dfd5bf00ac76bece68984bced5f376d4a62abc03b56472959bf804c547d574","parentDataHash":"0x0122ac92a79da67dca1dce1ee4bdc30c4e945e02664463d0924ae3b1b9c96594","expectedShnarf":"0xe6a7703511076e3789cc25059b468940b2e91df262f11b95b9005f758482aed7","prevShnarf":"0x7db9a7cbfd21211ecd77d8791894eca4478be04c38002a415dce9eea9a7d39cb","proverVersion":"3.0.0","verifyingKeyShaSum":"0xc4a868954d361bf8c18d4b3699c4fa973a6b2e4543ddea0ce7970d6941f55758","decompressionProof":"0x0065f8b21dcdcbd60c44261b3bac28c7def612baa05fb88dde626ea512732e02d4168915ec34f318573cbd3a5704da320106a391a0619e36cd44fd3de0928a16f7634af98f0ef497c7a3731e853874846440ac82d7a8ee4574d3a514abc4778e016541f63a1e049c6fc858aef13088c7ecf3301229e68e28452aae82a7a611d716d4ee523bacbab5a3d0e786a75b0fb1015f6247b68a1e90e5c875b6bc8167eb7672e742deb8b8d8b920afab1ced31dff37d567f39537ba7d96aad85621e7ba60028a528ceaddd23b59ef3b1b5b52313be5d8086c8c99d1695ec84838969d7e411cfb5cf21e96ed56df3044350e3d4e701024e8898be317d12b9e5cb2ad1a3392427c95d9f01a79b14f91103eaa93924612de3cec48113d82efb41296cbbf6ed01952adff0a83b21add6fe5cac1e70e261a5e121151ed32a4e40fea7344ef7a48010a1398d7e167804067908e0a4463c00227a80a31d4a874a67abf84e10b12e2ae2ab1fc5a6bd6bf0c2da61a55af0364370fe7e4c717253894299ad8268d8ff00981208da63b489358c12ac728713a123c12c6c5df30d6991f583619a8f5a36c4887d848beaa68d6894efeef4a2a96c00ae3f3ba87100b0e8c0ce1cf46c7b0456b924f50a1e23b216a2b4223a5f36070b50996cdfa7df5a67172e6ac84a1fb900d7c809508a1522a583fc5d49e7529eb06d50c615ed017061cf02213298547c46617ba30a0a08927f6dbe567b8c48c000e0e5d48b47e17006615ab50518f1e12bb32abedc59a1ccf0122cbd4c3eafad36d384711f84b465813f0419d01c98e8017f3f954f7ab87cc748e54c641fca03137b10e50fc030d92e242404459bc4b80e32a6dd1a04e4186d699c8d021205cb005c818f78915877b39022722bfef4a1b56523d9f6a94ebb8b4a3cc5a4dd7443caf9060451e50701193945f96938b851000eb8f37b0d4b56b07c9b9416d3c5f4cc9a2c56f389d565f0d934411f75b27dcea279bd8606b868036729c515d080f900c15b357118ec7c61192962c8238aa01b635eed7b5422964c25da2c6c9a61c0ae8a802360eaf6324f94aefb4fe3c183000000070d394d5cf43825c4ae22df3bbfdfdef3b926c369a02cf4e2a0c47f23d9c93f3d0722e3870ef81055872672fce9974d7233676dda0f6b57dd78361fa848ae1ecc0e169233865012f39ca78c82e02a08dee010950dbbd99478fdc801cb32bc4eaa020f78b922746741a12cdf09d033c7ba79c011beb797dcd6799dd4d771451b6510777bd644338726a9bb25aa5f5358f93fe2fcc72cb017cd52bc222d15452b0502b74620aba1a1d52ebe407db0187b81a44791863f3e0469f56fdaa3c792b3e40af6d9e611a17c62fc6ab2ecdf6cf08e3ee77f3b6af13b12cb8995d4ad35d494015b7098609d907a2dc753d3aca3cd9233b860bed3533071a03eb80169a89988a99bae5fa03ee5f742d85065dbe3900e007d999667aa9b5d352fadef352305a8625017c76c8c34c33155ae4af96e4ce57c8d81e76975146b4f0726a9993fb9bb05cbdf763971cbd6bb0f52ea82480b0d0a6b7970f8753de83b5b34585b2a090d000000010056d1dd30270e14358caa017c55de8eff6b5c745675c7e233934d2849a3dc6aa168c3c6f1e563a5ab8809fb9743ed9a013fe90b1661ad71364a900b014f4fb57c62dadaba345043f28098342849c78b86078fdac79759a246e9361e87c1963d","debug":{"publicInput":"0x3342cb51853c46a97fe61fde0e66d7056d3dca38f81257fe90cc4ab0483349d"}} From 26ba22ead0fc2851ca120443c9f5117b709eb30b Mon Sep 17 00:00:00 2001 From: kyzooghost <73516204+kyzooghost@users.noreply.github.com> Date: Thu, 16 Jan 2025 23:01:45 +1100 Subject: [PATCH 8/9] [Fix] Make codecov action optional in workflows (#559) * make codecov action optional in workflows * test env vs secret * added CODECOV_TOKEN to optional * fix typo --- .github/workflows/coordinator-testing.yml | 2 ++ .github/workflows/run-smc-tests.yml | 3 +++ 2 files changed, 5 insertions(+) diff --git a/.github/workflows/coordinator-testing.yml b/.github/workflows/coordinator-testing.yml index edaf2e582..50471a45f 100644 --- a/.github/workflows/coordinator-testing.yml +++ b/.github/workflows/coordinator-testing.yml @@ -26,6 +26,7 @@ jobs: GITHUB_TOKEN: ${{ secrets._GITHUB_TOKEN_RELEASE_ACCESS }} DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }} DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }} + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} runs-on: gha-runner-scale-set-ubuntu-22.04-amd64-large name: Coordinator tests steps: @@ -76,6 +77,7 @@ jobs: path: | ${{ github.workspace }}/build/reports/jacoco/jacocoRootReport/jacocoRootReport.xml - name: Upload coverage to Codecov + if: ${{ env.CODECOV_TOKEN != '' }} uses: codecov/codecov-action@v5 with: fail_ci_if_error: true diff --git a/.github/workflows/run-smc-tests.yml b/.github/workflows/run-smc-tests.yml index af94f3311..7f29d5386 100644 --- a/.github/workflows/run-smc-tests.yml +++ b/.github/workflows/run-smc-tests.yml @@ -31,6 +31,8 @@ jobs: run-contract-tests: runs-on: [self-hosted, ubuntu-20.04, X64, small] name: Run smart contracts tests + env: + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} steps: - name: Checkout uses: actions/checkout@v4 @@ -69,6 +71,7 @@ jobs: run: pnpm -F contracts run coverage - name: Upload coverage to Codecov + if: ${{ env.CODECOV_TOKEN != '' }} uses: codecov/codecov-action@v5 with: fail_ci_if_error: true From 05d3ee287563efaee6538b4cf1a7e1560cd4d8a5 Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Thu, 16 Jan 2025 13:24:04 +0100 Subject: [PATCH 9/9] fix(ecpair): ensure last non-trivial input pair goes to ML+finalexp circuit (#524) * fix: set inputresult only once * fix: copy only actual inputs going to pairing (no trivial pairs) * fix: non-exclusive G2 membership or pairing check * fix: enable index consistency check when interleaved G2 membership We may interleave in the same rows the G2 membership and pairing check inputs. Currently when we have interleaved then we disable the index consisitency check. * fix: do not project pair IDs and total pairings * fix: add constraint to check totalpairs correctness * test: add IS_RESULT column to test cases and uniform reformat * feat: allow outputting CSV in hex * feat: add utility method to write the module * test: check also IS_RESULT in test cases * test: add test case modules * test: add regression test case * feat: add testdata generator for ecpair * feat: add tests for manual generation of EC edge cases * fix: accumulator consistency assignment in case of one valid point * docs: describe assignment * fix: indexing when non-sequential valid points * test: run tests on generated data * feat: generate all cases for 1-5 input pairs * test: skip long tests * fix: test imports * enable ecpair * perf: parallelize testcase testing --------- Co-authored-by: gusiri --- prover/utils/csvtraces/csvtraces.go | 13 +- prover/zkevm/prover/ecpair/ecpair.go | 5 +- .../zkevm/prover/ecpair/ecpair_assignment.go | 109 ++- .../zkevm/prover/ecpair/ecpair_constraints.go | 40 +- prover/zkevm/prover/ecpair/ecpair_test.go | 70 +- .../prover/ecpair/ecpair_with_circuit_test.go | 31 + .../testdata/ecpair_double_pair_module.csv | 258 +++--- .../ecpair/testdata/ecpair_empty_module.csv | 1 + .../ecpair_failing_double_pair_module.csv | 258 +++--- .../testdata/ecpair_regression_1_input.csv | 51 ++ .../testdata/ecpair_regression_1_module.csv | 129 +++ .../ecpair/testdata/ecpair_trace_module.csv | 257 ++++++ .../testdata/ecpair_triple_pair_module.csv | 514 ++++++------ .../testdata/ecpair_two_pairings_module.csv | 514 ++++++------ .../testdata_generator_manual_test.go | 765 ++++++++++++++++++ .../testdata/testdata_generator_test.go | 583 +++++++++++++ prover/zkevm/zkevm.go | 17 +- 17 files changed, 2805 insertions(+), 810 deletions(-) create mode 100644 prover/zkevm/prover/ecpair/testdata/ecpair_empty_module.csv create mode 100644 prover/zkevm/prover/ecpair/testdata/ecpair_regression_1_input.csv create mode 100644 prover/zkevm/prover/ecpair/testdata/ecpair_regression_1_module.csv create mode 100644 prover/zkevm/prover/ecpair/testdata/ecpair_trace_module.csv create mode 100644 prover/zkevm/prover/ecpair/testdata/testdata_generator_manual_test.go create mode 100644 prover/zkevm/prover/ecpair/testdata/testdata_generator_test.go diff --git a/prover/utils/csvtraces/csvtraces.go b/prover/utils/csvtraces/csvtraces.go index a5d2f1ca4..ffa3d6acd 100644 --- a/prover/utils/csvtraces/csvtraces.go +++ b/prover/utils/csvtraces/csvtraces.go @@ -20,6 +20,7 @@ type cfg struct { nbRows int skipPrePaddingZero bool filterOn ifaces.Column + inHex bool } type Option func(*cfg) error @@ -47,6 +48,12 @@ func FilterOn(col ifaces.Column) Option { } } +// InHex sets the CSV printer to print the values in hexadecimal +func InHex(c *cfg) error { + c.inHex = true + return nil +} + type CsvTrace struct { mapped map[string][]field.Element @@ -110,7 +117,11 @@ func FmtCsv(w io.Writer, run *wizard.ProverRuntime, cols []ifaces.Column, option } if assignment[c][r].IsUint64() { - fmtVals = append(fmtVals, assignment[c][r].String()) + if cfg.inHex { + fmtVals = append(fmtVals, "0x"+assignment[c][r].Text(16)) + } else { + fmtVals = append(fmtVals, assignment[c][r].String()) + } continue } diff --git a/prover/zkevm/prover/ecpair/ecpair.go b/prover/zkevm/prover/ecpair/ecpair.go index ab2fdcb20..52f882d0a 100644 --- a/prover/zkevm/prover/ecpair/ecpair.go +++ b/prover/zkevm/prover/ecpair/ecpair.go @@ -108,11 +108,12 @@ func newECPair(comp *wizard.CompiledIOP, limits *Limits, ecSource *ECPairSource) res.csInstanceIDChangeWhenNewInstance(comp) res.csAccumulatorInit(comp) res.csAccumulatorConsistency(comp) + res.csTotalPairs(comp) res.csLastPairToFinalExp(comp) res.csIndexConsistency(comp) res.csAccumulatorMask(comp) // only Unaligned Pairing data or G2 membership data is active at a time - res.csExclusiveUnalignedDatas(comp) + res.csPairingDataOrMembershipActive(comp) // only to Miller loop or to FinalExp res.csExclusivePairingCircuitMasks(comp) @@ -241,6 +242,7 @@ type UnalignedPairingData struct { ToMillerLoopCircuitMask ifaces.Column ToFinalExpCircuitMask ifaces.Column + IsResultOfInstance ifaces.Column IsFirstLineOfInstance ifaces.Column IsFirstLineOfPrevAccumulator ifaces.Column IsFirstLineOfCurrAccumulator ifaces.Column @@ -263,6 +265,7 @@ func newUnalignedPairingData(comp *wizard.CompiledIOP, limits *Limits) *Unaligne IsFirstLineOfInstance: createCol("IS_FIRST_LINE_OF_INSTANCE"), IsFirstLineOfPrevAccumulator: createCol("IS_FIRST_LINE_OF_PREV_ACC"), IsFirstLineOfCurrAccumulator: createCol("IS_FIRST_LINE_OF_CURR_ACC"), + IsResultOfInstance: createCol("IS_RESULT"), IsAccumulatorPrev: createCol("IS_ACCUMULATOR_PREV"), IsAccumulatorCurr: createCol("IS_ACCUMULATOR_CURR"), IsAccumulatorInit: createCol("IS_ACCUMULATOR_INIT"), diff --git a/prover/zkevm/prover/ecpair/ecpair_assignment.go b/prover/zkevm/prover/ecpair/ecpair_assignment.go index ba1e28b6a..2cc78dcfa 100644 --- a/prover/zkevm/prover/ecpair/ecpair_assignment.go +++ b/prover/zkevm/prover/ecpair/ecpair_assignment.go @@ -88,10 +88,18 @@ func (ec *ECPair) assignPairingData(run *wizard.ProverRuntime) { dstIndex = common.NewVectorBuilder(ec.UnalignedPairingData.Index) dstIsFirstPrev = common.NewVectorBuilder(ec.UnalignedPairingData.IsFirstLineOfPrevAccumulator) dstIsFirstCurr = common.NewVectorBuilder(ec.UnalignedPairingData.IsFirstLineOfCurrAccumulator) + dstIsResult = common.NewVectorBuilder(ec.UnalignedPairingData.IsResultOfInstance) ) for currPos := 0; currPos < len(srcLimbs); { - // we need to check if the current position is a pairing or not. If not, then skip it. + // we need to check if the current position is a pairing or not. If not, + // then skip it. + // + // this also skips inputs to the current pairing instance which do not + // require passing to the pairing circuit (full-trivial or half-trivial + // inputs). But this is fine as it doesn't change the result as trivial + // result ML is 1. Only non-trivial input pairs affect the pairing check + // result. if srcIsPairing[currPos].IsZero() { currPos++ continue @@ -100,28 +108,42 @@ func (ec *ECPair) assignPairingData(run *wizard.ProverRuntime) { // input data. We iterate over the data to get the number of pairing // inputs. nbInputs := 1 // we start with 1 because we always have at least one pairing input + // we may have trivial input pairs in-between the non-trivial ones. We + // mark which inputs we are interested in. + actualInputs := []int{0} // we started when isPairing is 1, this means that we have non-trivial input. for { if srcIsRes[currPos+nbInputs*(nbG1Limbs+nbG2Limbs)].IsOne() { break } + if srcIsPairing[currPos+nbInputs*(nbG1Limbs+nbG2Limbs)].IsOne() { + actualInputs = append(actualInputs, nbInputs) + } nbInputs++ } + nbActualTotalPairs := len(actualInputs) // now, we have continous chunk of data that is for the pairing. Prepare it for processing. - pairingInG1 = make([][nbG1Limbs]field.Element, nbInputs) - pairingInG2 = make([][nbG2Limbs]field.Element, nbInputs) - for i := 0; i < nbInputs; i++ { + pairingInG1 = make([][nbG1Limbs]field.Element, nbActualTotalPairs) + pairingInG2 = make([][nbG2Limbs]field.Element, nbActualTotalPairs) + for ii, i := range actualInputs { for j := 0; j < nbG1Limbs; j++ { - pairingInG1[i][j] = srcLimbs[currPos+i*(nbG1Limbs+nbG2Limbs)+j] + pairingInG1[ii][j] = srcLimbs[currPos+i*(nbG1Limbs+nbG2Limbs)+j] } for j := 0; j < nbG2Limbs; j++ { - pairingInG2[i][j] = srcLimbs[currPos+i*(nbG1Limbs+nbG2Limbs)+nbG1Limbs+j] + pairingInG2[ii][j] = srcLimbs[currPos+i*(nbG1Limbs+nbG2Limbs)+nbG1Limbs+j] } - inputResult[0] = srcLimbs[currPos+(i+1)*(nbG1Limbs+nbG2Limbs)] - inputResult[1] = srcLimbs[currPos+(i+1)*(nbG1Limbs+nbG2Limbs)+1] } + inputResult[0] = srcLimbs[currPos+nbInputs*(nbG1Limbs+nbG2Limbs)] + inputResult[1] = srcLimbs[currPos+nbInputs*(nbG1Limbs+nbG2Limbs)+1] limbs := processPairingData(pairingInG1, pairingInG2, inputResult) instanceId := srcID[currPos] // processed data has the input limbs, but we have entered the intermediate Gt accumulator values + + // generic assignment. We push the static values for the current instance: + // - the limbs (interleaved with accumulator values) + // - indicator for the first row of the whole pairingcheck instance + // - the instance id + // - the index of the current limb + // - activeness of the submodule for i := 0; i < len(limbs); i++ { dstLimb.PushField(limbs[i]) if i == 0 { @@ -133,15 +155,24 @@ func (ec *ECPair) assignPairingData(run *wizard.ProverRuntime) { dstIndex.PushInt(i) dstIsActive.PushOne() } - for i := 0; i < nbInputs-1; i++ { + // now we push the dynamic values per Miller loop. We send all valid + // pairs except the last to Miller loop (not Miller loop + finalexp!) + // circuit. Keep in mind if there is only a single valid pair then this + // loop is skipped. + for ii := range actualInputs[:len(actualInputs)-1] { + // first we indicate for the accumulator if it is the first one, previous or current for j := 0; j < nbGtLimbs; j++ { dstIsComputed.PushOne() dstIsPulling.PushZero() - if i == 0 { + if ii == 0 { + // we handle first accumulator separately to be able to + // constrain that the initial accumulator value is correct. dstIsAccInit.PushOne() dstIsAccPrev.PushZero() dstIsFirstPrev.PushZero() } else { + // we're not in the first pair of points, so we indicate + // that the accumulator consistency needs to be checked. dstIsAccInit.PushZero() if j == 0 { dstIsFirstPrev.PushOne() @@ -153,6 +184,8 @@ func (ec *ECPair) assignPairingData(run *wizard.ProverRuntime) { dstIsAccCurr.PushZero() dstIsFirstCurr.PushZero() } + // now we push the dynamic values for the actual inputs to the pairing check circuit (coming from the arithmetization). + // essentially we only mark that this limb came directly from arithmetization. for j := nbGtLimbs; j < nbGtLimbs+nbG1Limbs+nbG2Limbs; j++ { dstIsPulling.PushOne() dstIsComputed.PushZero() @@ -162,6 +195,7 @@ func (ec *ECPair) assignPairingData(run *wizard.ProverRuntime) { dstIsFirstPrev.PushZero() dstIsFirstCurr.PushZero() } + // finally, we need to indicate that the next limbs are for the current accumulator for j := nbGtLimbs + nbG1Limbs + nbG2Limbs; j < 2*nbGtLimbs+nbG1Limbs+nbG2Limbs; j++ { dstIsComputed.PushOne() dstIsPulling.PushZero() @@ -175,54 +209,92 @@ func (ec *ECPair) assignPairingData(run *wizard.ProverRuntime) { } dstIsAccCurr.PushOne() } + // we also set the static values for all limbs in this pairs of points. These are: + // - true mark for miller loop circuit + // - false mark for the ML+finalexp circuit + // - the pair ID + // - the total number of pairs + // - false mark that current limb is for the result for j := 0; j < nbG1Limbs+nbG2Limbs+2*nbGtLimbs; j++ { dstToMillerLoop.PushOne() dstToFinalExp.PushZero() - dstPairId.PushInt(i + 1) - dstTotalPairs.PushInt(nbInputs) + dstPairId.PushInt(ii + 1) + dstTotalPairs.PushInt(nbActualTotalPairs) + dstIsResult.PushZero() } } + // we need to handle the final pair of points separately. The + // ML+finalexp circuit does not take the current accumulator as an + // input, but rather the expected pairing check result. + // + // first we set the masks for the accumulator limbs. for j := 0; j < nbGtLimbs; j++ { dstIsComputed.PushOne() dstIsPulling.PushZero() - dstPairId.PushInt(nbInputs) - dstIsAccInit.PushZero() - dstIsAccPrev.PushOne() + dstPairId.PushInt(nbActualTotalPairs) + // handle separately the case when there is only one valid input + // pair. In this case, the first valid pair also includes the + // accumulator initialization. + if nbActualTotalPairs == 1 { + dstIsAccInit.PushOne() + dstIsAccPrev.PushZero() + } else { + dstIsAccInit.PushZero() + dstIsAccPrev.PushOne() + } dstIsAccCurr.PushZero() if j == 0 { - dstIsFirstPrev.PushOne() + // handle separately the case when there is only one valid + // input. In this case we don't have the previous accumulator. + if nbActualTotalPairs == 1 { + dstIsFirstPrev.PushZero() + } else { + dstIsFirstPrev.PushOne() + } } else { dstIsFirstPrev.PushZero() } dstIsFirstCurr.PushZero() + dstIsResult.PushZero() } + // similarly for the final pair of points, we need to indicate that the + // G1/G2 points come directly from the arithmetization. for j := nbGtLimbs; j < nbGtLimbs+nbG1Limbs+nbG2Limbs; j++ { dstIsPulling.PushOne() dstIsComputed.PushZero() - dstPairId.PushInt(nbInputs) + dstPairId.PushInt(nbActualTotalPairs) dstIsAccInit.PushZero() dstIsAccPrev.PushZero() dstIsAccCurr.PushZero() dstIsFirstPrev.PushZero() dstIsFirstCurr.PushZero() + dstIsResult.PushZero() } + // finally, we need to indicate that the result of the pairing check + // comes directly from the arithmetization. this is a bit explicit loop, + // but it's easier to understand. for j := nbGtLimbs + nbG1Limbs + nbG2Limbs; j < nbGtLimbs+nbG1Limbs+nbG2Limbs+2; j++ { dstIsPulling.PushOne() dstIsComputed.PushZero() + // NB! for the result the Pair ID is 0. This is important to keep in + // mind as we set some constraints based on this. dstPairId.PushZero() dstIsAccInit.PushZero() dstIsAccPrev.PushZero() dstIsAccCurr.PushZero() dstIsFirstPrev.PushZero() dstIsFirstCurr.PushZero() + dstIsResult.PushOne() } + // finally we set the static masks for the final pair of points. for j := 0; j < nbG1Limbs+nbG2Limbs+nbGtLimbs+2; j++ { dstToFinalExp.PushOne() dstToMillerLoop.PushZero() - dstTotalPairs.PushInt(nbInputs) + dstTotalPairs.PushInt(nbActualTotalPairs) } currPos += nbInputs*(nbG1Limbs+nbG2Limbs) + 2 } + // Finally, we pad and assign the assigned data. dstIsActive.PadAndAssign(run, field.Zero()) dstLimb.PadAndAssign(run, field.Zero()) dstPairId.PadAndAssign(run, field.Zero()) @@ -239,6 +311,7 @@ func (ec *ECPair) assignPairingData(run *wizard.ProverRuntime) { dstIndex.PadAndAssign(run, field.Zero()) dstIsFirstPrev.PadAndAssign(run, field.Zero()) dstIsFirstCurr.PadAndAssign(run, field.Zero()) + dstIsResult.PadAndAssign(run, field.Zero()) } func processPairingData(pairingInG1 [][nbG1Limbs]field.Element, pairingInG2 [][nbG2Limbs]field.Element, inputResult [2]field.Element) []field.Element { diff --git a/prover/zkevm/prover/ecpair/ecpair_constraints.go b/prover/zkevm/prover/ecpair/ecpair_constraints.go index 932cca482..cae32bf68 100644 --- a/prover/zkevm/prover/ecpair/ecpair_constraints.go +++ b/prover/zkevm/prover/ecpair/ecpair_constraints.go @@ -55,8 +55,8 @@ func (ec *ECPair) csProjections(comp *wizard.CompiledIOP) { // we project data from the arithmetization correctly to the unaligned part of the circuit projection.InsertProjection( comp, ifaces.QueryIDf("%v_PROJECTION_PAIRING", nameECPair), - []ifaces.Column{ec.ECPairSource.Limb, ec.ECPairSource.AccPairings, ec.ECPairSource.TotalPairings, ec.ECPairSource.ID}, - []ifaces.Column{ec.UnalignedPairingData.Limb, ec.UnalignedPairingData.PairID, ec.UnalignedPairingData.TotalPairs, ec.UnalignedPairingData.InstanceID}, + []ifaces.Column{ec.ECPairSource.Limb, ec.ECPairSource.ID, ec.ECPairSource.IsEcPairingResult}, + []ifaces.Column{ec.UnalignedPairingData.Limb, ec.UnalignedPairingData.InstanceID, ec.UnalignedPairingData.IsResultOfInstance}, ec.ECPairSource.CsEcpairing, ec.UnalignedPairingData.IsPulling, ) @@ -159,6 +159,23 @@ func (ec *ECPair) csAccumulatorConsistency(comp *wizard.CompiledIOP) { ) } +func (ec *ECPair) csTotalPairs(comp *wizard.CompiledIOP) { + // total pairs corresponds to the number of pairs in the instance. for this + // we check that when the limb corresponds to the result, then the PairID of + // the shifted by two corresponds to the total pairs. the limb corresponds + // to the result when its PairID is 0 (for input pairs the indexing starts + // from 1). + comp.InsertGlobal( + roundNr, + ifaces.QueryIDf("%v_TOTAL_PAIRS", nameECPair), + sym.Mul( + ec.UnalignedPairingData.IsActive, + ec.UnalignedPairingData.IsResultOfInstance, + sym.Sub(ec.UnalignedPairingData.TotalPairs, column.Shift(ec.UnalignedPairingData.PairID, -2)), // we have two limbs for the result, shift by two gets to the input + ), + ) +} + func (ec *ECPair) csLastPairToFinalExp(comp *wizard.CompiledIOP) { // if the last pair then the final exp circuit should be active @@ -191,7 +208,6 @@ func (ec *ECPair) csIndexConsistency(comp *wizard.CompiledIOP) { ifaces.QueryIDf("%v_INDEX_INCREMENT", nameECPair), sym.Mul( ec.UnalignedPairingData.IsActive, - sym.Sub(1, ec.UnalignedG2MembershipData.IsPulling, ec.UnalignedG2MembershipData.IsComputed), // we dont use index in the G2 membership check sym.Sub(1, ec.UnalignedPairingData.IsFirstLineOfInstance), sym.Sub(ec.UnalignedPairingData.Index, column.Shift(ec.UnalignedPairingData.Index, -1), 1), ), @@ -276,11 +292,19 @@ func (ec *ECPair) csAccumulatorMask(comp *wizard.CompiledIOP) { ) } -func (ec *ECPair) csExclusiveUnalignedDatas(comp *wizard.CompiledIOP) { - common.MustBeMutuallyExclusiveBinaryFlags(comp, ec.IsActive, []ifaces.Column{ - ec.UnalignedG2MembershipData.ToG2MembershipCircuitMask, - ec.UnalignedPairingData.IsActive, - }) +func (ec *ECPair) csPairingDataOrMembershipActive(comp *wizard.CompiledIOP) { + // when module is active, then either pairing data or membership data is + // active. Can also be both. + comp.InsertGlobal( + roundNr, + ifaces.QueryIDf("%v_PAIRING_OR_MEMBERSHIP_ACTIVE", nameECPair), + sym.Add( + ec.IsActive, + sym.Neg(ec.UnalignedPairingData.IsActive), + sym.Neg(ec.UnalignedG2MembershipData.ToG2MembershipCircuitMask), + sym.Mul(ec.UnalignedPairingData.IsActive, ec.UnalignedG2MembershipData.ToG2MembershipCircuitMask), + ), + ) } func (ec *ECPair) csExclusivePairingCircuitMasks(comp *wizard.CompiledIOP) { diff --git a/prover/zkevm/prover/ecpair/ecpair_test.go b/prover/zkevm/prover/ecpair/ecpair_test.go index 50fa06f29..21e1f4822 100644 --- a/prover/zkevm/prover/ecpair/ecpair_test.go +++ b/prover/zkevm/prover/ecpair/ecpair_test.go @@ -1,10 +1,12 @@ package ecpair import ( + "os" "testing" "github.com/consensys/linea-monorepo/prover/protocol/compiler/dummy" "github.com/consensys/linea-monorepo/prover/protocol/dedicated/plonk" + "github.com/consensys/linea-monorepo/prover/protocol/ifaces" "github.com/consensys/linea-monorepo/prover/protocol/wizard" "github.com/consensys/linea-monorepo/prover/utils/csvtraces" ) @@ -49,17 +51,25 @@ var pairingDataTestCases = []pairingDataTestCase{ { // empty input to test edge case and input fillers InputFName: "testdata/ecpair_empty.csv", - ModuleFName: "", + ModuleFName: "testdata/ecpair_empty_module.csv", NbMillerLoops: 2, NbFinalExps: 2, }, { // trace test InputFName: "testdata/ecpair_trace_input.csv", - ModuleFName: "", + ModuleFName: "testdata/ecpair_trace_module.csv", NbMillerLoops: 2, NbFinalExps: 1, }, + { + // regression test in Linea Sepolia transaction 0x7afcf5eddbe09d85c8d0b1e3608b755b9baed1a59d8589ebcaf50e7603074139 + InputFName: "testdata/ecpair_regression_1_input.csv", + ModuleFName: "testdata/ecpair_regression_1_module.csv", + NbMillerLoops: 2, + NbFinalExps: 1, + NbSubgroupChecks: 1, + }, } func testModule(t *testing.T, tc pairingDataTestCase, withPairingCircuit, withG2MembershipCircuit bool, checkPairingModule, checkSubgroupModule bool) { @@ -149,6 +159,7 @@ func testModule(t *testing.T, tc pairingDataTestCase, withPairingCircuit, withG2 "ECPAIR_UNALIGNED_PAIRING_DATA_IS_ACCUMULATOR_PREV", "ECPAIR_UNALIGNED_PAIRING_DATA_IS_FIRST_LINE_OF_CURR_ACC", "ECPAIR_UNALIGNED_PAIRING_DATA_IS_ACCUMULATOR_CURR", + "ECPAIR_UNALIGNED_PAIRING_DATA_IS_RESULT", "ECPAIR_UNALIGNED_PAIRING_DATA_LIMB", "ECPAIR_UNALIGNED_PAIRING_DATA_TO_MILLER_LOOP_CIRCUIT", "ECPAIR_UNALIGNED_PAIRING_DATA_TO_FINAL_EXP_CIRCUIT", @@ -205,3 +216,58 @@ func TestMembership(t *testing.T) { testModule(t, tc, false, false, false, true) } } + +func writeModule(t *testing.T, run *wizard.ProverRuntime, outFile string, mod *ECPair) { + // this is utility function for being able to write the module output to a + // file. it is useful for testcase generation. NB! when generating testcase + // then manually check the correctness of the file before committing it. + w, err := os.Create(outFile) + if err != nil { + t.Fatal(err) + } + defer w.Close() + csvtraces.FmtCsv(w, run, []ifaces.Column{ + // // module activation + // mod.IsActive, + + // // source + // mod.ECPairSource.ID, + // mod.ECPairSource.Index, + // mod.ECPairSource.Limb, + // mod.ECPairSource.SuccessBit, + // mod.ECPairSource.AccPairings, + // mod.ECPairSource.TotalPairings, + // mod.ECPairSource.IsEcPairingData, + // mod.ECPairSource.IsEcPairingResult, + // mod.ECPairSource.CsEcpairing, + // mod.ECPairSource.CsG2Membership, + + // // for pairing module test + // mod.UnalignedPairingData.IsActive, + // mod.UnalignedPairingData.Index, + // mod.UnalignedPairingData.InstanceID, + // mod.UnalignedPairingData.IsFirstLineOfInstance, + // mod.UnalignedPairingData.IsAccumulatorInit, + // mod.UnalignedPairingData.IsFirstLineOfPrevAccumulator, + // mod.UnalignedPairingData.IsAccumulatorPrev, + // mod.UnalignedPairingData.IsFirstLineOfCurrAccumulator, + // mod.UnalignedPairingData.IsAccumulatorCurr, + // mod.UnalignedPairingData.IsResultOfInstance, + // mod.UnalignedPairingData.IsComputed, + // mod.UnalignedPairingData.IsPulling, + // mod.UnalignedPairingData.PairID, + // mod.UnalignedPairingData.TotalPairs, + // mod.UnalignedPairingData.Limb, + // mod.UnalignedPairingData.ToMillerLoopCircuitMask, + // mod.UnalignedPairingData.ToFinalExpCircuitMask, + + // // for subgroup module module test + // mod.UnalignedG2MembershipData.IsComputed, + // mod.UnalignedG2MembershipData.IsPulling, + // mod.UnalignedG2MembershipData.Limb, + // mod.UnalignedG2MembershipData.SuccessBit, + // mod.UnalignedG2MembershipData.ToG2MembershipCircuitMask, + }, + []csvtraces.Option{csvtraces.InHex}, + ) +} diff --git a/prover/zkevm/prover/ecpair/ecpair_with_circuit_test.go b/prover/zkevm/prover/ecpair/ecpair_with_circuit_test.go index f7df56d7f..4af8dacd6 100644 --- a/prover/zkevm/prover/ecpair/ecpair_with_circuit_test.go +++ b/prover/zkevm/prover/ecpair/ecpair_with_circuit_test.go @@ -3,7 +3,12 @@ package ecpair import ( + "os" + "path/filepath" + "strings" "testing" + + "github.com/consensys/linea-monorepo/prover/utils/parallel" ) func TestPairingDataCircuit(t *testing.T) { @@ -17,3 +22,29 @@ func TestMembershipCircuit(t *testing.T) { testModule(t, tc, false, true, false, true) } } + +func TestGeneratedData(t *testing.T) { + // in order to run the test, you need to have generated the different test + // cases. Run the test [TestGenerateECPairTestCases] at + // prover/zkevm/prover/ecpair/testdata/testdata_generator_test.go to + // generate all inputs. + t.Skip("long test, run manually when needed") + var generatedData []pairingDataTestCase + filepath.Walk("testdata/generated", func(path string, info os.FileInfo, err error) error { + if strings.HasSuffix(path, "input.csv") { + tc := pairingDataTestCase{ + InputFName: path, + NbMillerLoops: 5, + NbFinalExps: 1, + NbSubgroupChecks: 5, + } + generatedData = append(generatedData, tc) + } + return nil + }) + parallel.Execute(len(generatedData), func(start, end int) { + for i := start; i < end; i++ { + testModule(t, generatedData[i], true, true, true, true) + } + }) +} diff --git a/prover/zkevm/prover/ecpair/testdata/ecpair_double_pair_module.csv b/prover/zkevm/prover/ecpair/testdata/ecpair_double_pair_module.csv index bcef32bda..033e3a876 100644 --- a/prover/zkevm/prover/ecpair/testdata/ecpair_double_pair_module.csv +++ b/prover/zkevm/prover/ecpair/testdata/ecpair_double_pair_module.csv @@ -1,129 +1,129 @@ -ECPAIR_IS_ACTIVE,ECPAIR_UNALIGNED_PAIRING_DATA_IS_ACTIVE,ECPAIR_UNALIGNED_PAIRING_DATA_INDEX,ECPAIR_UNALIGNED_PAIRING_DATA_INSTANCE_ID,ECPAIR_UNALIGNED_PAIRING_DATA_IS_FIRST_LINE_OF_INSTANCE,ECPAIR_UNALIGNED_PAIRING_DATA_IS_ACCUMULATOR_INIT,ECPAIR_UNALIGNED_PAIRING_DATA_IS_FIRST_LINE_OF_PREV_ACC,ECPAIR_UNALIGNED_PAIRING_DATA_IS_ACCUMULATOR_PREV,ECPAIR_UNALIGNED_PAIRING_DATA_IS_FIRST_LINE_OF_CURR_ACC,ECPAIR_UNALIGNED_PAIRING_DATA_IS_ACCUMULATOR_CURR,ECPAIR_UNALIGNED_PAIRING_DATA_IS_COMPUTED,ECPAIR_UNALIGNED_PAIRING_DATA_IS_PULLING,ECPAIR_UNALIGNED_PAIRING_DATA_PAIR_ID,ECPAIR_UNALIGNED_PAIRING_DATA_TOTAL_PAIRS,ECPAIR_UNALIGNED_PAIRING_DATA_LIMB,ECPAIR_UNALIGNED_PAIRING_DATA_TO_MILLER_LOOP_CIRCUIT,ECPAIR_UNALIGNED_PAIRING_DATA_TO_FINAL_EXP_CIRCUIT -0x1,0x1,0x0,0x0,0x1,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x1,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x1,0x1,0x0 -0x1,0x1,0x2,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x3,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x4,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x5,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x6,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x7,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x8,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x9,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0xa,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0xb,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0xc,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0xd,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0xe,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0xf,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x10,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x11,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x12,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x13,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x14,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x15,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x16,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x17,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x18,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x13364879816394e38a2d72bde23bda93,0x1,0x0 -0x1,0x1,0x19,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0xcd39885c6bfdedbc45e6bafcfc8fa685,0x1,0x0 -0x1,0x1,0x1a,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0xe0e4c9d03746d287b341d52461946a1,0x1,0x0 -0x1,0x1,0x1b,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0xc865002c35ba9bd6b789fc26a526d121,0x1,0x0 -0x1,0x1,0x1c,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x0e82be8514331e947408a3a27a54d580,0x1,0x0 -0x1,0x1,0x1d,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x9866db37d74db5abc7de8f0d3d0f7ee3,0x1,0x0 -0x1,0x1,0x1e,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x0f89c9a7bb2eb9418d2d89310306196d,0x1,0x0 -0x1,0x1,0x1f,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0xf1ae8d9de0173f3e1151487bb5157cd7,0x1,0x0 -0x1,0x1,0x20,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x10b30b9925aace81dcec2ccce77c3eea,0x1,0x0 -0x1,0x1,0x21,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0xa949c366d7cd71a6a6748bcdd996b762,0x1,0x0 -0x1,0x1,0x22,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x11497987c563ade267b3bdfcc9c04022,0x1,0x0 -0x1,0x1,0x23,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x3e25664c3bcdd28858b1daa7ac249034,0x1,0x0 -0x1,0x1,0x24,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x1,0x0,0x1,0x2,0x1fc57e97fc7f579bbc2ba220d9b10d46,0x1,0x0 -0x1,0x1,0x25,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x4c95627608bdbb0235762c7048400f93,0x1,0x0 -0x1,0x1,0x26,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x2b4305dcdfcf51d41a169cbe7b4e89d4,0x1,0x0 -0x1,0x1,0x27,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x59f4578a51cdbe050925fc0b9312aa86,0x1,0x0 -0x1,0x1,0x28,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x1133d6c9d0cacf4e7cd03b8ae8654f3b,0x1,0x0 -0x1,0x1,0x29,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0xfbfc80323c91c70825d4aa8accfd77b8,0x1,0x0 -0x1,0x1,0x2a,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x2b45ce688738a571621b63dba9880856,0x1,0x0 -0x1,0x1,0x2b,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x9dd4ff917cefc257d7cfe3ea571e206a,0x1,0x0 -0x1,0x1,0x2c,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x653b8af047158278411df902874a82a,0x1,0x0 -0x1,0x1,0x2d,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x401206aafb12aa7c2d704f51f115d8c2,0x1,0x0 -0x1,0x1,0x2e,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x1373a842ceca78f2ae076804f168559c,0x1,0x0 -0x1,0x1,0x2f,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x1781cbb3451085c1166bdadbc7c92688,0x1,0x0 -0x1,0x1,0x30,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x2c8c1f272129cf6b0866ad1d8f3ac818,0x1,0x0 -0x1,0x1,0x31,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x2f12833bfd8a1711d7947461776699df,0x1,0x0 -0x1,0x1,0x32,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x16e10599cfcd3537d808d197ce64c2c5,0x1,0x0 -0x1,0x1,0x33,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0xdaf005b2c0be94b08c52e30acfb098e,0x1,0x0 -0x1,0x1,0x34,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0xd5d04cfad426760d9019d3d15b98aee,0x1,0x0 -0x1,0x1,0x35,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x8c37f28a10bb3cfa2f3971505c77db23,0x1,0x0 -0x1,0x1,0x36,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x22af99c52785193aa8920826c0d96380,0x1,0x0 -0x1,0x1,0x37,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0xe8213976bbbab27922a2cd8c8fe4adeb,0x1,0x0 -0x1,0x1,0x38,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0xa6356a8a0caaec7d1a28661b990a20b,0x1,0x0 -0x1,0x1,0x39,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x217f227c48e2682613693d3afb8231e,0x1,0x0 -0x1,0x1,0x3a,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x5641ef4d251e87484afef7cae876258,0x1,0x0 -0x1,0x1,0x3b,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0xc199d8553a68a9408d2603bd9ff29c36,0x1,0x0 -0x1,0x1,0x3c,0x0,0x0,0x0,0x1,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x1fc57e97fc7f579bbc2ba220d9b10d46,0x0,0x1 -0x1,0x1,0x3d,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x4c95627608bdbb0235762c7048400f93,0x0,0x1 -0x1,0x1,0x3e,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x2b4305dcdfcf51d41a169cbe7b4e89d4,0x0,0x1 -0x1,0x1,0x3f,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x59f4578a51cdbe050925fc0b9312aa86,0x0,0x1 -0x1,0x1,0x40,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x1133d6c9d0cacf4e7cd03b8ae8654f3b,0x0,0x1 -0x1,0x1,0x41,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0xfbfc80323c91c70825d4aa8accfd77b8,0x0,0x1 -0x1,0x1,0x42,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x2b45ce688738a571621b63dba9880856,0x0,0x1 -0x1,0x1,0x43,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x9dd4ff917cefc257d7cfe3ea571e206a,0x0,0x1 -0x1,0x1,0x44,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x653b8af047158278411df902874a82a,0x0,0x1 -0x1,0x1,0x45,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x401206aafb12aa7c2d704f51f115d8c2,0x0,0x1 -0x1,0x1,0x46,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x1373a842ceca78f2ae076804f168559c,0x0,0x1 -0x1,0x1,0x47,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x1781cbb3451085c1166bdadbc7c92688,0x0,0x1 -0x1,0x1,0x48,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x2c8c1f272129cf6b0866ad1d8f3ac818,0x0,0x1 -0x1,0x1,0x49,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x2f12833bfd8a1711d7947461776699df,0x0,0x1 -0x1,0x1,0x4a,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x16e10599cfcd3537d808d197ce64c2c5,0x0,0x1 -0x1,0x1,0x4b,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0xdaf005b2c0be94b08c52e30acfb098e,0x0,0x1 -0x1,0x1,0x4c,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0xd5d04cfad426760d9019d3d15b98aee,0x0,0x1 -0x1,0x1,0x4d,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x8c37f28a10bb3cfa2f3971505c77db23,0x0,0x1 -0x1,0x1,0x4e,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x22af99c52785193aa8920826c0d96380,0x0,0x1 -0x1,0x1,0x4f,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0xe8213976bbbab27922a2cd8c8fe4adeb,0x0,0x1 -0x1,0x1,0x50,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0xa6356a8a0caaec7d1a28661b990a20b,0x0,0x1 -0x1,0x1,0x51,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x217f227c48e2682613693d3afb8231e,0x0,0x1 -0x1,0x1,0x52,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x5641ef4d251e87484afef7cae876258,0x0,0x1 -0x1,0x1,0x53,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0xc199d8553a68a9408d2603bd9ff29c36,0x0,0x1 -0x1,0x1,0x54,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0xb9624a62e115247146d4643e8d4daf0,0x0,0x1 -0x1,0x1,0x55,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x7ff180000fcf9f02c84cc5692b2c0526,0x0,0x1 -0x1,0x1,0x56,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x1cb9908c06bf3099f1538277102b31e3,0x0,0x1 -0x1,0x1,0x57,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x1d022dc64770bc130df14daef72830e4,0x0,0x1 -0x1,0x1,0x58,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x2977858b214a3cb43fa4024976dd1675,0x0,0x1 -0x1,0x1,0x59,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x9b1bf5367e6318da3545e697b9931671,0x0,0x1 -0x1,0x1,0x5a,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x06fcfd4b9ca03fb145ff273e480efda3,0x0,0x1 -0x1,0x1,0x5b,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0xc8a7aef64882efcbd8920b4458e1ef3d,0x0,0x1 -0x1,0x1,0x5c,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x281508326108309778f9cdf9c39a4c4d,0x0,0x1 -0x1,0x1,0x5d,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0xc90a405c0cfbfd5d20fec4e47acce66f,0x0,0x1 -0x1,0x1,0x5e,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x10d24b6f0b87c1e3f78b80b967bac765,0x0,0x1 -0x1,0x1,0x5f,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x763f38c53a4377e9a97e2761758a92f1,0x0,0x1 -0x1,0x1,0x60,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x2,0x0,0x0,0x1 -0x1,0x1,0x61,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x2,0x1,0x0,0x1 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +ECPAIR_IS_ACTIVE,ECPAIR_UNALIGNED_PAIRING_DATA_IS_ACTIVE,ECPAIR_UNALIGNED_PAIRING_DATA_INDEX,ECPAIR_UNALIGNED_PAIRING_DATA_INSTANCE_ID,ECPAIR_UNALIGNED_PAIRING_DATA_IS_FIRST_LINE_OF_INSTANCE,ECPAIR_UNALIGNED_PAIRING_DATA_IS_ACCUMULATOR_INIT,ECPAIR_UNALIGNED_PAIRING_DATA_IS_FIRST_LINE_OF_PREV_ACC,ECPAIR_UNALIGNED_PAIRING_DATA_IS_ACCUMULATOR_PREV,ECPAIR_UNALIGNED_PAIRING_DATA_IS_FIRST_LINE_OF_CURR_ACC,ECPAIR_UNALIGNED_PAIRING_DATA_IS_ACCUMULATOR_CURR,ECPAIR_UNALIGNED_PAIRING_DATA_IS_RESULT,ECPAIR_UNALIGNED_PAIRING_DATA_IS_COMPUTED,ECPAIR_UNALIGNED_PAIRING_DATA_IS_PULLING,ECPAIR_UNALIGNED_PAIRING_DATA_PAIR_ID,ECPAIR_UNALIGNED_PAIRING_DATA_TOTAL_PAIRS,ECPAIR_UNALIGNED_PAIRING_DATA_LIMB,ECPAIR_UNALIGNED_PAIRING_DATA_TO_MILLER_LOOP_CIRCUIT,ECPAIR_UNALIGNED_PAIRING_DATA_TO_FINAL_EXP_CIRCUIT +0x1,0x1,0x0,0x0,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x1,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x1,0x1,0x0 +0x1,0x1,0x2,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x3,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x4,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x5,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x6,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x7,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x8,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x9,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0xa,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0xb,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0xc,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0xd,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0xe,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0xf,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x10,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x11,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x12,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x13,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x14,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x15,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x16,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x17,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x18,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x13364879816394e38a2d72bde23bda93,0x1,0x0 +0x1,0x1,0x19,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0xcd39885c6bfdedbc45e6bafcfc8fa685,0x1,0x0 +0x1,0x1,0x1a,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0xe0e4c9d03746d287b341d52461946a1,0x1,0x0 +0x1,0x1,0x1b,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0xc865002c35ba9bd6b789fc26a526d121,0x1,0x0 +0x1,0x1,0x1c,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0xe82be8514331e947408a3a27a54d580,0x1,0x0 +0x1,0x1,0x1d,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x9866db37d74db5abc7de8f0d3d0f7ee3,0x1,0x0 +0x1,0x1,0x1e,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0xf89c9a7bb2eb9418d2d89310306196d,0x1,0x0 +0x1,0x1,0x1f,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0xf1ae8d9de0173f3e1151487bb5157cd7,0x1,0x0 +0x1,0x1,0x20,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x10b30b9925aace81dcec2ccce77c3eea,0x1,0x0 +0x1,0x1,0x21,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0xa949c366d7cd71a6a6748bcdd996b762,0x1,0x0 +0x1,0x1,0x22,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x11497987c563ade267b3bdfcc9c04022,0x1,0x0 +0x1,0x1,0x23,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x3e25664c3bcdd28858b1daa7ac249034,0x1,0x0 +0x1,0x1,0x24,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x0,0x1,0x2,0x1fc57e97fc7f579bbc2ba220d9b10d46,0x1,0x0 +0x1,0x1,0x25,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x4c95627608bdbb0235762c7048400f93,0x1,0x0 +0x1,0x1,0x26,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x2b4305dcdfcf51d41a169cbe7b4e89d4,0x1,0x0 +0x1,0x1,0x27,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x59f4578a51cdbe050925fc0b9312aa86,0x1,0x0 +0x1,0x1,0x28,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x1133d6c9d0cacf4e7cd03b8ae8654f3b,0x1,0x0 +0x1,0x1,0x29,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0xfbfc80323c91c70825d4aa8accfd77b8,0x1,0x0 +0x1,0x1,0x2a,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x2b45ce688738a571621b63dba9880856,0x1,0x0 +0x1,0x1,0x2b,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x9dd4ff917cefc257d7cfe3ea571e206a,0x1,0x0 +0x1,0x1,0x2c,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x653b8af047158278411df902874a82a,0x1,0x0 +0x1,0x1,0x2d,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x401206aafb12aa7c2d704f51f115d8c2,0x1,0x0 +0x1,0x1,0x2e,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x1373a842ceca78f2ae076804f168559c,0x1,0x0 +0x1,0x1,0x2f,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x1781cbb3451085c1166bdadbc7c92688,0x1,0x0 +0x1,0x1,0x30,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x2c8c1f272129cf6b0866ad1d8f3ac818,0x1,0x0 +0x1,0x1,0x31,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x2f12833bfd8a1711d7947461776699df,0x1,0x0 +0x1,0x1,0x32,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x16e10599cfcd3537d808d197ce64c2c5,0x1,0x0 +0x1,0x1,0x33,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0xdaf005b2c0be94b08c52e30acfb098e,0x1,0x0 +0x1,0x1,0x34,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0xd5d04cfad426760d9019d3d15b98aee,0x1,0x0 +0x1,0x1,0x35,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x8c37f28a10bb3cfa2f3971505c77db23,0x1,0x0 +0x1,0x1,0x36,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x22af99c52785193aa8920826c0d96380,0x1,0x0 +0x1,0x1,0x37,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0xe8213976bbbab27922a2cd8c8fe4adeb,0x1,0x0 +0x1,0x1,0x38,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0xa6356a8a0caaec7d1a28661b990a20b,0x1,0x0 +0x1,0x1,0x39,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x217f227c48e2682613693d3afb8231e,0x1,0x0 +0x1,0x1,0x3a,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x5641ef4d251e87484afef7cae876258,0x1,0x0 +0x1,0x1,0x3b,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0xc199d8553a68a9408d2603bd9ff29c36,0x1,0x0 +0x1,0x1,0x3c,0x0,0x0,0x0,0x1,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x1fc57e97fc7f579bbc2ba220d9b10d46,0x0,0x1 +0x1,0x1,0x3d,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x4c95627608bdbb0235762c7048400f93,0x0,0x1 +0x1,0x1,0x3e,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x2b4305dcdfcf51d41a169cbe7b4e89d4,0x0,0x1 +0x1,0x1,0x3f,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x59f4578a51cdbe050925fc0b9312aa86,0x0,0x1 +0x1,0x1,0x40,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x1133d6c9d0cacf4e7cd03b8ae8654f3b,0x0,0x1 +0x1,0x1,0x41,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0xfbfc80323c91c70825d4aa8accfd77b8,0x0,0x1 +0x1,0x1,0x42,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x2b45ce688738a571621b63dba9880856,0x0,0x1 +0x1,0x1,0x43,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x9dd4ff917cefc257d7cfe3ea571e206a,0x0,0x1 +0x1,0x1,0x44,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x653b8af047158278411df902874a82a,0x0,0x1 +0x1,0x1,0x45,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x401206aafb12aa7c2d704f51f115d8c2,0x0,0x1 +0x1,0x1,0x46,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x1373a842ceca78f2ae076804f168559c,0x0,0x1 +0x1,0x1,0x47,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x1781cbb3451085c1166bdadbc7c92688,0x0,0x1 +0x1,0x1,0x48,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x2c8c1f272129cf6b0866ad1d8f3ac818,0x0,0x1 +0x1,0x1,0x49,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x2f12833bfd8a1711d7947461776699df,0x0,0x1 +0x1,0x1,0x4a,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x16e10599cfcd3537d808d197ce64c2c5,0x0,0x1 +0x1,0x1,0x4b,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0xdaf005b2c0be94b08c52e30acfb098e,0x0,0x1 +0x1,0x1,0x4c,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0xd5d04cfad426760d9019d3d15b98aee,0x0,0x1 +0x1,0x1,0x4d,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x8c37f28a10bb3cfa2f3971505c77db23,0x0,0x1 +0x1,0x1,0x4e,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x22af99c52785193aa8920826c0d96380,0x0,0x1 +0x1,0x1,0x4f,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0xe8213976bbbab27922a2cd8c8fe4adeb,0x0,0x1 +0x1,0x1,0x50,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0xa6356a8a0caaec7d1a28661b990a20b,0x0,0x1 +0x1,0x1,0x51,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x217f227c48e2682613693d3afb8231e,0x0,0x1 +0x1,0x1,0x52,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x5641ef4d251e87484afef7cae876258,0x0,0x1 +0x1,0x1,0x53,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0xc199d8553a68a9408d2603bd9ff29c36,0x0,0x1 +0x1,0x1,0x54,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0xb9624a62e115247146d4643e8d4daf0,0x0,0x1 +0x1,0x1,0x55,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x7ff180000fcf9f02c84cc5692b2c0526,0x0,0x1 +0x1,0x1,0x56,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x1cb9908c06bf3099f1538277102b31e3,0x0,0x1 +0x1,0x1,0x57,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x1d022dc64770bc130df14daef72830e4,0x0,0x1 +0x1,0x1,0x58,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x2977858b214a3cb43fa4024976dd1675,0x0,0x1 +0x1,0x1,0x59,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x9b1bf5367e6318da3545e697b9931671,0x0,0x1 +0x1,0x1,0x5a,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x6fcfd4b9ca03fb145ff273e480efda3,0x0,0x1 +0x1,0x1,0x5b,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0xc8a7aef64882efcbd8920b4458e1ef3d,0x0,0x1 +0x1,0x1,0x5c,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x281508326108309778f9cdf9c39a4c4d,0x0,0x1 +0x1,0x1,0x5d,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0xc90a405c0cfbfd5d20fec4e47acce66f,0x0,0x1 +0x1,0x1,0x5e,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x10d24b6f0b87c1e3f78b80b967bac765,0x0,0x1 +0x1,0x1,0x5f,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x763f38c53a4377e9a97e2761758a92f1,0x0,0x1 +0x1,0x1,0x60,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x2,0x0,0x0,0x1 +0x1,0x1,0x61,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x2,0x1,0x0,0x1 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 diff --git a/prover/zkevm/prover/ecpair/testdata/ecpair_empty_module.csv b/prover/zkevm/prover/ecpair/testdata/ecpair_empty_module.csv new file mode 100644 index 000000000..0b22726c4 --- /dev/null +++ b/prover/zkevm/prover/ecpair/testdata/ecpair_empty_module.csv @@ -0,0 +1 @@ +ECPAIR_IS_ACTIVE,ECPAIR_UNALIGNED_PAIRING_DATA_IS_ACTIVE,ECPAIR_UNALIGNED_PAIRING_DATA_INDEX,ECPAIR_UNALIGNED_PAIRING_DATA_INSTANCE_ID,ECPAIR_UNALIGNED_PAIRING_DATA_IS_FIRST_LINE_OF_INSTANCE,ECPAIR_UNALIGNED_PAIRING_DATA_IS_ACCUMULATOR_INIT,ECPAIR_UNALIGNED_PAIRING_DATA_IS_FIRST_LINE_OF_PREV_ACC,ECPAIR_UNALIGNED_PAIRING_DATA_IS_ACCUMULATOR_PREV,ECPAIR_UNALIGNED_PAIRING_DATA_IS_FIRST_LINE_OF_CURR_ACC,ECPAIR_UNALIGNED_PAIRING_DATA_IS_ACCUMULATOR_CURR,ECPAIR_UNALIGNED_PAIRING_DATA_IS_RESULT,ECPAIR_UNALIGNED_PAIRING_DATA_IS_COMPUTED,ECPAIR_UNALIGNED_PAIRING_DATA_IS_PULLING,ECPAIR_UNALIGNED_PAIRING_DATA_PAIR_ID,ECPAIR_UNALIGNED_PAIRING_DATA_TOTAL_PAIRS,ECPAIR_UNALIGNED_PAIRING_DATA_LIMB,ECPAIR_UNALIGNED_PAIRING_DATA_TO_MILLER_LOOP_CIRCUIT,ECPAIR_UNALIGNED_PAIRING_DATA_TO_FINAL_EXP_CIRCUIT diff --git a/prover/zkevm/prover/ecpair/testdata/ecpair_failing_double_pair_module.csv b/prover/zkevm/prover/ecpair/testdata/ecpair_failing_double_pair_module.csv index 0d7099470..602be4f74 100644 --- a/prover/zkevm/prover/ecpair/testdata/ecpair_failing_double_pair_module.csv +++ b/prover/zkevm/prover/ecpair/testdata/ecpair_failing_double_pair_module.csv @@ -1,129 +1,129 @@ -ECPAIR_IS_ACTIVE,ECPAIR_UNALIGNED_PAIRING_DATA_IS_ACTIVE,ECPAIR_UNALIGNED_PAIRING_DATA_INDEX,ECPAIR_UNALIGNED_PAIRING_DATA_INSTANCE_ID,ECPAIR_UNALIGNED_PAIRING_DATA_IS_FIRST_LINE_OF_INSTANCE,ECPAIR_UNALIGNED_PAIRING_DATA_IS_ACCUMULATOR_INIT,ECPAIR_UNALIGNED_PAIRING_DATA_IS_FIRST_LINE_OF_PREV_ACC,ECPAIR_UNALIGNED_PAIRING_DATA_IS_ACCUMULATOR_PREV,ECPAIR_UNALIGNED_PAIRING_DATA_IS_FIRST_LINE_OF_CURR_ACC,ECPAIR_UNALIGNED_PAIRING_DATA_IS_ACCUMULATOR_CURR,ECPAIR_UNALIGNED_PAIRING_DATA_IS_COMPUTED,ECPAIR_UNALIGNED_PAIRING_DATA_IS_PULLING,ECPAIR_UNALIGNED_PAIRING_DATA_PAIR_ID,ECPAIR_UNALIGNED_PAIRING_DATA_TOTAL_PAIRS,ECPAIR_UNALIGNED_PAIRING_DATA_LIMB,ECPAIR_UNALIGNED_PAIRING_DATA_TO_MILLER_LOOP_CIRCUIT,ECPAIR_UNALIGNED_PAIRING_DATA_TO_FINAL_EXP_CIRCUIT -0x1,0x1,0x0,0x0,0x1,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x1,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x1,0x1,0x0 -0x1,0x1,0x2,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x3,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x4,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x5,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x6,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x7,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x8,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x9,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0xa,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0xb,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0xc,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0xd,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0xe,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0xf,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x10,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x11,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x12,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x13,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x14,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x15,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x16,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x17,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x18,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x219db76fd15c77e92376ec7ccdf3795a,0x1,0x0 -0x1,0x1,0x19,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x96b20b521116027d63df9d7a4d76bcef,0x1,0x0 -0x1,0x1,0x1a,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x0692f74fd48f12f945546eb1daaa688b,0x1,0x0 -0x1,0x1,0x1b,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0xe31ef7b9f6338c8c452d69a386f0a098,0x1,0x0 -0x1,0x1,0x1c,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x0f679eca6f21e702c5613627661a31b7,0x1,0x0 -0x1,0x1,0x1d,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0xa5b99a766175a8ceebadf12135d8c0a0,0x1,0x0 -0x1,0x1,0x1e,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x0a23a4431ea9ca09eb5787a8a0a7bb52,0x1,0x0 -0x1,0x1,0x1f,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x30a7cf5dc4fbf71edbda6ae0faca4000,0x1,0x0 -0x1,0x1,0x20,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x0715261e3e5eb7991d5dbe83f4cd963c,0x1,0x0 -0x1,0x1,0x21,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0xd8eb1975c583801573dc432c2c677165,0x1,0x0 -0x1,0x1,0x22,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x142ed84e025468f2aa7a6fe50839c23a,0x1,0x0 -0x1,0x1,0x23,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0xa3e99559088d53289092e02ffd59e84d,0x1,0x0 -0x1,0x1,0x24,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x1,0x0,0x1,0x2,0x2519fb9fc917e5401ef8ae1dc4e0fcf6,0x1,0x0 -0x1,0x1,0x25,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0xe73ec610c73dedfaecdc78b4cfed5fae,0x1,0x0 -0x1,0x1,0x26,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x532dd87a224b3c74c0972336084d8cf,0x1,0x0 -0x1,0x1,0x27,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0xd63ea1761e1b3eb06330f9a70a334bb3,0x1,0x0 -0x1,0x1,0x28,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x1be66119d8e9cb15799f97c5765a4f8f,0x1,0x0 -0x1,0x1,0x29,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x7945a28f14dda8ff8d91e8e7472250dc,0x1,0x0 -0x1,0x1,0x2a,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x1445016cdd9b1f1521bc8554163ed0d8,0x1,0x0 -0x1,0x1,0x2b,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x1d69bb89e43261ea0cd55460902d1502,0x1,0x0 -0x1,0x1,0x2c,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x27c2852669c9bb985bb057af1b521490,0x1,0x0 -0x1,0x1,0x2d,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x9e44217a7c12ccc32c1a38dfddb3e4f9,0x1,0x0 -0x1,0x1,0x2e,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x213cd09f21a19a3ba7bf07cfb2af15db,0x1,0x0 -0x1,0x1,0x2f,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x484f312ecb72e9937bb9d118dc40bb98,0x1,0x0 -0x1,0x1,0x30,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x278d3989a6a313a5ae46832637fb035d,0x1,0x0 -0x1,0x1,0x31,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x27160f6e52a0177a893c3b8cfc3a16dd,0x1,0x0 -0x1,0x1,0x32,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0xf2867d79c66c1b03b24b76190f1cddb,0x1,0x0 -0x1,0x1,0x33,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x507f66b1e126b7d5f6b8fb575b98f4e3,0x1,0x0 -0x1,0x1,0x34,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x190f41a349878e7007fa72a919920ebe,0x1,0x0 -0x1,0x1,0x35,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x4afaca4694c9b0a0848e46598d1f80fd,0x1,0x0 -0x1,0x1,0x36,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x274ebf234ca143dd8a07c1ffff2ed891,0x1,0x0 -0x1,0x1,0x37,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0xb7638a696e66fe108cb6a122e36c2c9d,0x1,0x0 -0x1,0x1,0x38,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x26f9711c5e431d68483d1c20ad498818,0x1,0x0 -0x1,0x1,0x39,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x2f3ae73e50cb72160c69a85e3b6cf774,0x1,0x0 -0x1,0x1,0x3a,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x967d0cd5a60dd7aedeb12ef807e2ce8,0x1,0x0 -0x1,0x1,0x3b,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x43aad3aff198259e8706389ab5add7c1,0x1,0x0 -0x1,0x1,0x3c,0x0,0x0,0x0,0x1,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x2519fb9fc917e5401ef8ae1dc4e0fcf6,0x0,0x1 -0x1,0x1,0x3d,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0xe73ec610c73dedfaecdc78b4cfed5fae,0x0,0x1 -0x1,0x1,0x3e,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x532dd87a224b3c74c0972336084d8cf,0x0,0x1 -0x1,0x1,0x3f,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0xd63ea1761e1b3eb06330f9a70a334bb3,0x0,0x1 -0x1,0x1,0x40,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x1be66119d8e9cb15799f97c5765a4f8f,0x0,0x1 -0x1,0x1,0x41,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x7945a28f14dda8ff8d91e8e7472250dc,0x0,0x1 -0x1,0x1,0x42,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x1445016cdd9b1f1521bc8554163ed0d8,0x0,0x1 -0x1,0x1,0x43,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x1d69bb89e43261ea0cd55460902d1502,0x0,0x1 -0x1,0x1,0x44,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x27c2852669c9bb985bb057af1b521490,0x0,0x1 -0x1,0x1,0x45,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x9e44217a7c12ccc32c1a38dfddb3e4f9,0x0,0x1 -0x1,0x1,0x46,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x213cd09f21a19a3ba7bf07cfb2af15db,0x0,0x1 -0x1,0x1,0x47,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x484f312ecb72e9937bb9d118dc40bb98,0x0,0x1 -0x1,0x1,0x48,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x278d3989a6a313a5ae46832637fb035d,0x0,0x1 -0x1,0x1,0x49,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x27160f6e52a0177a893c3b8cfc3a16dd,0x0,0x1 -0x1,0x1,0x4a,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0xf2867d79c66c1b03b24b76190f1cddb,0x0,0x1 -0x1,0x1,0x4b,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x507f66b1e126b7d5f6b8fb575b98f4e3,0x0,0x1 -0x1,0x1,0x4c,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x190f41a349878e7007fa72a919920ebe,0x0,0x1 -0x1,0x1,0x4d,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x4afaca4694c9b0a0848e46598d1f80fd,0x0,0x1 -0x1,0x1,0x4e,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x274ebf234ca143dd8a07c1ffff2ed891,0x0,0x1 -0x1,0x1,0x4f,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0xb7638a696e66fe108cb6a122e36c2c9d,0x0,0x1 -0x1,0x1,0x50,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x26f9711c5e431d68483d1c20ad498818,0x0,0x1 -0x1,0x1,0x51,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x2f3ae73e50cb72160c69a85e3b6cf774,0x0,0x1 -0x1,0x1,0x52,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x967d0cd5a60dd7aedeb12ef807e2ce8,0x0,0x1 -0x1,0x1,0x53,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x43aad3aff198259e8706389ab5add7c1,0x0,0x1 -0x1,0x1,0x54,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x1ae800da67a6c22f94d05578d1361f25,0x0,0x1 -0x1,0x1,0x55,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x422a9f478669101d5b117f57fcb741e1,0x0,0x1 -0x1,0x1,0x56,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x15ded9e40e5489c82b473115f1d4b409,0x0,0x1 -0x1,0x1,0x57,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x9e93aa996ad2346e8b46a2aa0db7832c,0x0,0x1 -0x1,0x1,0x58,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x2e1b4d36165dbb3f03664c4e77181c95,0x0,0x1 -0x1,0x1,0x59,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x285a1f1bb08fac1599d9c06095085cf0,0x0,0x1 -0x1,0x1,0x5a,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x286dcf3fe302f14b9df2d19119a97c81,0x0,0x1 -0x1,0x1,0x5b,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x70a68443dafe5001dcc450abf66cb1b9,0x0,0x1 -0x1,0x1,0x5c,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x23e5cf5e441d3d12e4b63d4d16eea2dd,0x0,0x1 -0x1,0x1,0x5d,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0xdc6005a79a59c812fbd4050870691a91,0x0,0x1 -0x1,0x1,0x5e,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x11cfc60ff4ceb85b8af413347b760f13,0x0,0x1 -0x1,0x1,0x5f,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x4325aead086b2761e0a16039ab1f12aa,0x0,0x1 -0x1,0x1,0x60,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x2,0x0,0x0,0x1 -0x1,0x1,0x61,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x2,0x0,0x0,0x1 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +ECPAIR_IS_ACTIVE,ECPAIR_UNALIGNED_PAIRING_DATA_IS_ACTIVE,ECPAIR_UNALIGNED_PAIRING_DATA_INDEX,ECPAIR_UNALIGNED_PAIRING_DATA_INSTANCE_ID,ECPAIR_UNALIGNED_PAIRING_DATA_IS_FIRST_LINE_OF_INSTANCE,ECPAIR_UNALIGNED_PAIRING_DATA_IS_ACCUMULATOR_INIT,ECPAIR_UNALIGNED_PAIRING_DATA_IS_FIRST_LINE_OF_PREV_ACC,ECPAIR_UNALIGNED_PAIRING_DATA_IS_ACCUMULATOR_PREV,ECPAIR_UNALIGNED_PAIRING_DATA_IS_FIRST_LINE_OF_CURR_ACC,ECPAIR_UNALIGNED_PAIRING_DATA_IS_ACCUMULATOR_CURR,ECPAIR_UNALIGNED_PAIRING_DATA_IS_RESULT,ECPAIR_UNALIGNED_PAIRING_DATA_IS_COMPUTED,ECPAIR_UNALIGNED_PAIRING_DATA_IS_PULLING,ECPAIR_UNALIGNED_PAIRING_DATA_PAIR_ID,ECPAIR_UNALIGNED_PAIRING_DATA_TOTAL_PAIRS,ECPAIR_UNALIGNED_PAIRING_DATA_LIMB,ECPAIR_UNALIGNED_PAIRING_DATA_TO_MILLER_LOOP_CIRCUIT,ECPAIR_UNALIGNED_PAIRING_DATA_TO_FINAL_EXP_CIRCUIT +0x1,0x1,0x0,0x0,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x1,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x1,0x1,0x0 +0x1,0x1,0x2,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x3,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x4,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x5,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x6,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x7,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x8,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x9,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0xa,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0xb,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0xc,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0xd,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0xe,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0xf,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x10,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x11,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x12,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x13,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x14,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x15,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x16,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x17,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x18,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x219db76fd15c77e92376ec7ccdf3795a,0x1,0x0 +0x1,0x1,0x19,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x96b20b521116027d63df9d7a4d76bcef,0x1,0x0 +0x1,0x1,0x1a,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x692f74fd48f12f945546eb1daaa688b,0x1,0x0 +0x1,0x1,0x1b,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0xe31ef7b9f6338c8c452d69a386f0a098,0x1,0x0 +0x1,0x1,0x1c,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0xf679eca6f21e702c5613627661a31b7,0x1,0x0 +0x1,0x1,0x1d,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0xa5b99a766175a8ceebadf12135d8c0a0,0x1,0x0 +0x1,0x1,0x1e,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0xa23a4431ea9ca09eb5787a8a0a7bb52,0x1,0x0 +0x1,0x1,0x1f,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x30a7cf5dc4fbf71edbda6ae0faca4000,0x1,0x0 +0x1,0x1,0x20,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x715261e3e5eb7991d5dbe83f4cd963c,0x1,0x0 +0x1,0x1,0x21,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0xd8eb1975c583801573dc432c2c677165,0x1,0x0 +0x1,0x1,0x22,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x142ed84e025468f2aa7a6fe50839c23a,0x1,0x0 +0x1,0x1,0x23,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0xa3e99559088d53289092e02ffd59e84d,0x1,0x0 +0x1,0x1,0x24,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x0,0x1,0x2,0x2519fb9fc917e5401ef8ae1dc4e0fcf6,0x1,0x0 +0x1,0x1,0x25,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0xe73ec610c73dedfaecdc78b4cfed5fae,0x1,0x0 +0x1,0x1,0x26,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x532dd87a224b3c74c0972336084d8cf,0x1,0x0 +0x1,0x1,0x27,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0xd63ea1761e1b3eb06330f9a70a334bb3,0x1,0x0 +0x1,0x1,0x28,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x1be66119d8e9cb15799f97c5765a4f8f,0x1,0x0 +0x1,0x1,0x29,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x7945a28f14dda8ff8d91e8e7472250dc,0x1,0x0 +0x1,0x1,0x2a,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x1445016cdd9b1f1521bc8554163ed0d8,0x1,0x0 +0x1,0x1,0x2b,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x1d69bb89e43261ea0cd55460902d1502,0x1,0x0 +0x1,0x1,0x2c,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x27c2852669c9bb985bb057af1b521490,0x1,0x0 +0x1,0x1,0x2d,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x9e44217a7c12ccc32c1a38dfddb3e4f9,0x1,0x0 +0x1,0x1,0x2e,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x213cd09f21a19a3ba7bf07cfb2af15db,0x1,0x0 +0x1,0x1,0x2f,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x484f312ecb72e9937bb9d118dc40bb98,0x1,0x0 +0x1,0x1,0x30,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x278d3989a6a313a5ae46832637fb035d,0x1,0x0 +0x1,0x1,0x31,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x27160f6e52a0177a893c3b8cfc3a16dd,0x1,0x0 +0x1,0x1,0x32,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0xf2867d79c66c1b03b24b76190f1cddb,0x1,0x0 +0x1,0x1,0x33,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x507f66b1e126b7d5f6b8fb575b98f4e3,0x1,0x0 +0x1,0x1,0x34,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x190f41a349878e7007fa72a919920ebe,0x1,0x0 +0x1,0x1,0x35,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x4afaca4694c9b0a0848e46598d1f80fd,0x1,0x0 +0x1,0x1,0x36,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x274ebf234ca143dd8a07c1ffff2ed891,0x1,0x0 +0x1,0x1,0x37,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0xb7638a696e66fe108cb6a122e36c2c9d,0x1,0x0 +0x1,0x1,0x38,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x26f9711c5e431d68483d1c20ad498818,0x1,0x0 +0x1,0x1,0x39,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x2f3ae73e50cb72160c69a85e3b6cf774,0x1,0x0 +0x1,0x1,0x3a,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x967d0cd5a60dd7aedeb12ef807e2ce8,0x1,0x0 +0x1,0x1,0x3b,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x43aad3aff198259e8706389ab5add7c1,0x1,0x0 +0x1,0x1,0x3c,0x0,0x0,0x0,0x1,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x2519fb9fc917e5401ef8ae1dc4e0fcf6,0x0,0x1 +0x1,0x1,0x3d,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0xe73ec610c73dedfaecdc78b4cfed5fae,0x0,0x1 +0x1,0x1,0x3e,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x532dd87a224b3c74c0972336084d8cf,0x0,0x1 +0x1,0x1,0x3f,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0xd63ea1761e1b3eb06330f9a70a334bb3,0x0,0x1 +0x1,0x1,0x40,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x1be66119d8e9cb15799f97c5765a4f8f,0x0,0x1 +0x1,0x1,0x41,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x7945a28f14dda8ff8d91e8e7472250dc,0x0,0x1 +0x1,0x1,0x42,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x1445016cdd9b1f1521bc8554163ed0d8,0x0,0x1 +0x1,0x1,0x43,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x1d69bb89e43261ea0cd55460902d1502,0x0,0x1 +0x1,0x1,0x44,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x27c2852669c9bb985bb057af1b521490,0x0,0x1 +0x1,0x1,0x45,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x9e44217a7c12ccc32c1a38dfddb3e4f9,0x0,0x1 +0x1,0x1,0x46,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x213cd09f21a19a3ba7bf07cfb2af15db,0x0,0x1 +0x1,0x1,0x47,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x484f312ecb72e9937bb9d118dc40bb98,0x0,0x1 +0x1,0x1,0x48,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x278d3989a6a313a5ae46832637fb035d,0x0,0x1 +0x1,0x1,0x49,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x27160f6e52a0177a893c3b8cfc3a16dd,0x0,0x1 +0x1,0x1,0x4a,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0xf2867d79c66c1b03b24b76190f1cddb,0x0,0x1 +0x1,0x1,0x4b,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x507f66b1e126b7d5f6b8fb575b98f4e3,0x0,0x1 +0x1,0x1,0x4c,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x190f41a349878e7007fa72a919920ebe,0x0,0x1 +0x1,0x1,0x4d,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x4afaca4694c9b0a0848e46598d1f80fd,0x0,0x1 +0x1,0x1,0x4e,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x274ebf234ca143dd8a07c1ffff2ed891,0x0,0x1 +0x1,0x1,0x4f,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0xb7638a696e66fe108cb6a122e36c2c9d,0x0,0x1 +0x1,0x1,0x50,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x26f9711c5e431d68483d1c20ad498818,0x0,0x1 +0x1,0x1,0x51,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x2f3ae73e50cb72160c69a85e3b6cf774,0x0,0x1 +0x1,0x1,0x52,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x967d0cd5a60dd7aedeb12ef807e2ce8,0x0,0x1 +0x1,0x1,0x53,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x43aad3aff198259e8706389ab5add7c1,0x0,0x1 +0x1,0x1,0x54,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x1ae800da67a6c22f94d05578d1361f25,0x0,0x1 +0x1,0x1,0x55,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x422a9f478669101d5b117f57fcb741e1,0x0,0x1 +0x1,0x1,0x56,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x15ded9e40e5489c82b473115f1d4b409,0x0,0x1 +0x1,0x1,0x57,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x9e93aa996ad2346e8b46a2aa0db7832c,0x0,0x1 +0x1,0x1,0x58,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x2e1b4d36165dbb3f03664c4e77181c95,0x0,0x1 +0x1,0x1,0x59,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x285a1f1bb08fac1599d9c06095085cf0,0x0,0x1 +0x1,0x1,0x5a,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x286dcf3fe302f14b9df2d19119a97c81,0x0,0x1 +0x1,0x1,0x5b,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x70a68443dafe5001dcc450abf66cb1b9,0x0,0x1 +0x1,0x1,0x5c,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x23e5cf5e441d3d12e4b63d4d16eea2dd,0x0,0x1 +0x1,0x1,0x5d,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0xdc6005a79a59c812fbd4050870691a91,0x0,0x1 +0x1,0x1,0x5e,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x11cfc60ff4ceb85b8af413347b760f13,0x0,0x1 +0x1,0x1,0x5f,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x4325aead086b2761e0a16039ab1f12aa,0x0,0x1 +0x1,0x1,0x60,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x2,0x0,0x0,0x1 +0x1,0x1,0x61,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x2,0x0,0x0,0x1 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 diff --git a/prover/zkevm/prover/ecpair/testdata/ecpair_regression_1_input.csv b/prover/zkevm/prover/ecpair/testdata/ecpair_regression_1_input.csv new file mode 100644 index 000000000..278d9801b --- /dev/null +++ b/prover/zkevm/prover/ecpair/testdata/ecpair_regression_1_input.csv @@ -0,0 +1,51 @@ +ECDATA_CS_PAIRING,ECDATA_ID,ECDATA_LIMB,ECDATA_SUCCESS_BIT,ECDATA_INDEX,ECDATA_IS_DATA,ECDATA_IS_RES,ECDATA_ACC_PAIRINGS,ECDATA_TOTAL_PAIRINGS,ECDATA_CS_G2_MEMBERSHIP +0,29563,0x0,1,0,1,0,1,4,0 +0,29563,0x0,1,1,1,0,1,4,0 +0,29563,0x0,1,2,1,0,1,4,0 +0,29563,0x0,1,3,1,0,1,4,0 +0,29563,0x0,1,4,1,0,1,4,0 +0,29563,0x0,1,5,1,0,1,4,0 +0,29563,0x0,1,6,1,0,1,4,0 +0,29563,0x0,1,7,1,0,1,4,0 +0,29563,0x0,1,8,1,0,1,4,0 +0,29563,0x0,1,9,1,0,1,4,0 +0,29563,0x0,1,10,1,0,1,4,0 +0,29563,0x0,1,11,1,0,1,4,0 +1,29563,0x27c69626be302e46df0af1982d621c7b,1,12,1,0,2,4,0 +1,29563,0x358571d44f0c65c9207af46b2e4b9594,1,13,1,0,2,4,0 +1,29563,0x120b258a7d2bb21e213159d01dd4364f,1,14,1,0,2,4,0 +1,29563,0xa11f02c47337b94e73ce1ad65ee10ada,1,15,1,0,2,4,0 +1,29563,0xb7c8b8c2f08ad05c14efdb53212ef50,1,16,1,0,2,4,0 +1,29563,0x1ac66ce991a90c10c22608a6ef0c6daf,1,17,1,0,2,4,0 +1,29563,0xda86f1aa7f003fc49ba5257f6a1a31b,1,18,1,0,2,4,0 +1,29563,0x762fb2a71e26b2bf972ad9c5ce50aabd,1,19,1,0,2,4,0 +1,29563,0x20b3c0f5090994b976afe7fa30002668,1,20,1,0,2,4,0 +1,29563,0x9547288c6611bf5bb913d706309817fc,1,21,1,0,2,4,0 +1,29563,0x1b55dc31de4c20571c178adea2e97fc6,1,22,1,0,2,4,0 +1,29563,0xb5745f4727165ab056c3150134fa6856,1,23,1,0,2,4,0 +1,29563,0x1996a3bf3f09f5c3d609d0341d07a22a,1,24,1,0,3,4,0 +1,29563,0x30cc16bfe7e74afdd0770ff169502c92,1,25,1,0,3,4,0 +1,29563,0x2c8c2d7e802418dea505c1856cb9f95b,1,26,1,0,3,4,0 +1,29563,0x1ca0a26bec7e4f73d03e9958dff2081a,1,27,1,0,3,4,0 +1,29563,0x198e9393920d483a7260bfb731fb5d25,1,28,1,0,3,4,0 +1,29563,0xf1aa493335a9e71297e485b7aef312c2,1,29,1,0,3,4,0 +1,29563,0x1800deef121f1e76426a00665e5c4479,1,30,1,0,3,4,0 +1,29563,0x674322d4f75edadd46debd5cd992f6ed,1,31,1,0,3,4,0 +1,29563,0x90689d0585ff075ec9e99ad690c3395,1,32,1,0,3,4,0 +1,29563,0xbc4b313370b38ef355acdadcd122975b,1,33,1,0,3,4,0 +1,29563,0x12c85ea5db8c6deb4aab71808dcb408f,1,34,1,0,3,4,0 +1,29563,0xe3d1e7690c43d37b4ce6cc0166fa7daa,1,35,1,0,3,4,0 +0,29563,0x0,1,36,1,0,4,4,0 +0,29563,0x0,1,37,1,0,4,4,0 +0,29563,0x0,1,38,1,0,4,4,0 +0,29563,0x0,1,39,1,0,4,4,0 +0,29563,0xed5b8a199985a625f5a0b6a44275b4c,1,40,1,0,4,4,1 +0,29563,0x48874ea094387e322a9a65548e55baaf,1,41,1,0,4,4,1 +0,29563,0x14c46c51fbb5b9e3d065addbcdd76571,1,42,1,0,4,4,1 +0,29563,0x12f73bbcdfecec743c83cd36cd6a11a0,1,43,1,0,4,4,1 +0,29563,0xa898f0e4144460a4a5a7018ceea8ab5,1,44,1,0,4,4,1 +0,29563,0x6732baf61e32b9873d6cef5cb8457cbe,1,45,1,0,4,4,1 +0,29563,0x3f6ad521b15ce41febd3ec0579fa48f,1,46,1,0,4,4,1 +0,29563,0xd563b64f31711e6e2b133b1fc2dd4588,1,47,1,0,4,4,1 +1,29563,0,1,0,0,1,0,4,0 +1,29563,0,1,1,0,1,0,4,0 \ No newline at end of file diff --git a/prover/zkevm/prover/ecpair/testdata/ecpair_regression_1_module.csv b/prover/zkevm/prover/ecpair/testdata/ecpair_regression_1_module.csv new file mode 100644 index 000000000..1e68c3596 --- /dev/null +++ b/prover/zkevm/prover/ecpair/testdata/ecpair_regression_1_module.csv @@ -0,0 +1,129 @@ +ECPAIR_IS_ACTIVE,ECPAIR_UNALIGNED_PAIRING_DATA_IS_ACTIVE,ECPAIR_UNALIGNED_PAIRING_DATA_INDEX,ECPAIR_UNALIGNED_PAIRING_DATA_INSTANCE_ID,ECPAIR_UNALIGNED_PAIRING_DATA_IS_FIRST_LINE_OF_INSTANCE,ECPAIR_UNALIGNED_PAIRING_DATA_IS_ACCUMULATOR_INIT,ECPAIR_UNALIGNED_PAIRING_DATA_IS_FIRST_LINE_OF_PREV_ACC,ECPAIR_UNALIGNED_PAIRING_DATA_IS_ACCUMULATOR_PREV,ECPAIR_UNALIGNED_PAIRING_DATA_IS_FIRST_LINE_OF_CURR_ACC,ECPAIR_UNALIGNED_PAIRING_DATA_IS_ACCUMULATOR_CURR,ECPAIR_UNALIGNED_PAIRING_DATA_IS_RESULT,ECPAIR_UNALIGNED_PAIRING_DATA_IS_COMPUTED,ECPAIR_UNALIGNED_PAIRING_DATA_IS_PULLING,ECPAIR_UNALIGNED_PAIRING_DATA_PAIR_ID,ECPAIR_UNALIGNED_PAIRING_DATA_TOTAL_PAIRS,ECPAIR_UNALIGNED_PAIRING_DATA_LIMB,ECPAIR_UNALIGNED_PAIRING_DATA_TO_MILLER_LOOP_CIRCUIT,ECPAIR_UNALIGNED_PAIRING_DATA_TO_FINAL_EXP_CIRCUIT +0x1,0x1,0x0,0x737b,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x1,0x737b,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x1,0x1,0x0 +0x1,0x1,0x2,0x737b,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x3,0x737b,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x4,0x737b,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x5,0x737b,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x6,0x737b,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x7,0x737b,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x8,0x737b,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x9,0x737b,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0xa,0x737b,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0xb,0x737b,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0xc,0x737b,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0xd,0x737b,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0xe,0x737b,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0xf,0x737b,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x10,0x737b,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x11,0x737b,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x12,0x737b,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x13,0x737b,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x14,0x737b,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x15,0x737b,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x16,0x737b,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x17,0x737b,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x18,0x737b,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x27c69626be302e46df0af1982d621c7b,0x1,0x0 +0x1,0x1,0x19,0x737b,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x358571d44f0c65c9207af46b2e4b9594,0x1,0x0 +0x1,0x1,0x1a,0x737b,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x120b258a7d2bb21e213159d01dd4364f,0x1,0x0 +0x1,0x1,0x1b,0x737b,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0xa11f02c47337b94e73ce1ad65ee10ada,0x1,0x0 +0x1,0x1,0x1c,0x737b,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0xb7c8b8c2f08ad05c14efdb53212ef50,0x1,0x0 +0x1,0x1,0x1d,0x737b,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x1ac66ce991a90c10c22608a6ef0c6daf,0x1,0x0 +0x1,0x1,0x1e,0x737b,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0xda86f1aa7f003fc49ba5257f6a1a31b,0x1,0x0 +0x1,0x1,0x1f,0x737b,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x762fb2a71e26b2bf972ad9c5ce50aabd,0x1,0x0 +0x1,0x1,0x20,0x737b,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x20b3c0f5090994b976afe7fa30002668,0x1,0x0 +0x1,0x1,0x21,0x737b,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x9547288c6611bf5bb913d706309817fc,0x1,0x0 +0x1,0x1,0x22,0x737b,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x1b55dc31de4c20571c178adea2e97fc6,0x1,0x0 +0x1,0x1,0x23,0x737b,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0xb5745f4727165ab056c3150134fa6856,0x1,0x0 +0x1,0x1,0x24,0x737b,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x0,0x1,0x2,0x1137fc12353dc8b52b4a9fddbbaa3a5b,0x1,0x0 +0x1,0x1,0x25,0x737b,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x17cbb12b76d31ccc72553270b505ac54,0x1,0x0 +0x1,0x1,0x26,0x737b,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x759e8fb6f8a80d8fce8efdbd26d82e4,0x1,0x0 +0x1,0x1,0x27,0x737b,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x11a5b0cf036373ff04fa1590f8535f43,0x1,0x0 +0x1,0x1,0x28,0x737b,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x28cb8ef1fb08ff271b49d1816a451dbd,0x1,0x0 +0x1,0x1,0x29,0x737b,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x24cb561c666914c1966961e99226a0e7,0x1,0x0 +0x1,0x1,0x2a,0x737b,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x269a2a32ca8a7ead6dc1acb9b671d45b,0x1,0x0 +0x1,0x1,0x2b,0x737b,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0xd93846bfa6f32f7eb9458a7a98963640,0x1,0x0 +0x1,0x1,0x2c,0x737b,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x2eba69ac1e7fa1147b1dbdfde9190ebf,0x1,0x0 +0x1,0x1,0x2d,0x737b,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x92b120d2f924214364944984c66619c9,0x1,0x0 +0x1,0x1,0x2e,0x737b,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0xb3539f69dc72810362b4aa2260e18cf,0x1,0x0 +0x1,0x1,0x2f,0x737b,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x6e6230b3b5c234758d6944d67b361bfb,0x1,0x0 +0x1,0x1,0x30,0x737b,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x2ef88e7bca3f69d2612b56ce9699615f,0x1,0x0 +0x1,0x1,0x31,0x737b,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x12f87428792a957fd1737013855ac876,0x1,0x0 +0x1,0x1,0x32,0x737b,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x24f79206d5cb177e64b4d9053151ce77,0x1,0x0 +0x1,0x1,0x33,0x737b,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0xa45dabb1095f36a6edc58f5114644398,0x1,0x0 +0x1,0x1,0x34,0x737b,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x1db7f080e67a26c52952d71c7331ffbe,0x1,0x0 +0x1,0x1,0x35,0x737b,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0xdc137df9f4dd59feeb25c4f70d2ac3f5,0x1,0x0 +0x1,0x1,0x36,0x737b,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x1ad6a825f36bc860b8696c73736d33f8,0x1,0x0 +0x1,0x1,0x37,0x737b,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0xd82bd185f505f0ff786cf2e68ba47da6,0x1,0x0 +0x1,0x1,0x38,0x737b,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x1606a45c154325213c755b01be9903fa,0x1,0x0 +0x1,0x1,0x39,0x737b,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x419de110d5c0cce0a57990de0a7d1413,0x1,0x0 +0x1,0x1,0x3a,0x737b,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x8646892bb422186785938a4e3b5d520,0x1,0x0 +0x1,0x1,0x3b,0x737b,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0xb7a6a2366c9bac68585391b8bd024367,0x1,0x0 +0x1,0x1,0x3c,0x737b,0x0,0x0,0x1,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x1137fc12353dc8b52b4a9fddbbaa3a5b,0x0,0x1 +0x1,0x1,0x3d,0x737b,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x17cbb12b76d31ccc72553270b505ac54,0x0,0x1 +0x1,0x1,0x3e,0x737b,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x759e8fb6f8a80d8fce8efdbd26d82e4,0x0,0x1 +0x1,0x1,0x3f,0x737b,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x11a5b0cf036373ff04fa1590f8535f43,0x0,0x1 +0x1,0x1,0x40,0x737b,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x28cb8ef1fb08ff271b49d1816a451dbd,0x0,0x1 +0x1,0x1,0x41,0x737b,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x24cb561c666914c1966961e99226a0e7,0x0,0x1 +0x1,0x1,0x42,0x737b,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x269a2a32ca8a7ead6dc1acb9b671d45b,0x0,0x1 +0x1,0x1,0x43,0x737b,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0xd93846bfa6f32f7eb9458a7a98963640,0x0,0x1 +0x1,0x1,0x44,0x737b,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x2eba69ac1e7fa1147b1dbdfde9190ebf,0x0,0x1 +0x1,0x1,0x45,0x737b,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x92b120d2f924214364944984c66619c9,0x0,0x1 +0x1,0x1,0x46,0x737b,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0xb3539f69dc72810362b4aa2260e18cf,0x0,0x1 +0x1,0x1,0x47,0x737b,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x6e6230b3b5c234758d6944d67b361bfb,0x0,0x1 +0x1,0x1,0x48,0x737b,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x2ef88e7bca3f69d2612b56ce9699615f,0x0,0x1 +0x1,0x1,0x49,0x737b,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x12f87428792a957fd1737013855ac876,0x0,0x1 +0x1,0x1,0x4a,0x737b,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x24f79206d5cb177e64b4d9053151ce77,0x0,0x1 +0x1,0x1,0x4b,0x737b,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0xa45dabb1095f36a6edc58f5114644398,0x0,0x1 +0x1,0x1,0x4c,0x737b,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x1db7f080e67a26c52952d71c7331ffbe,0x0,0x1 +0x1,0x1,0x4d,0x737b,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0xdc137df9f4dd59feeb25c4f70d2ac3f5,0x0,0x1 +0x1,0x1,0x4e,0x737b,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x1ad6a825f36bc860b8696c73736d33f8,0x0,0x1 +0x1,0x1,0x4f,0x737b,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0xd82bd185f505f0ff786cf2e68ba47da6,0x0,0x1 +0x1,0x1,0x50,0x737b,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x1606a45c154325213c755b01be9903fa,0x0,0x1 +0x1,0x1,0x51,0x737b,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x419de110d5c0cce0a57990de0a7d1413,0x0,0x1 +0x1,0x1,0x52,0x737b,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x8646892bb422186785938a4e3b5d520,0x0,0x1 +0x1,0x1,0x53,0x737b,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0xb7a6a2366c9bac68585391b8bd024367,0x0,0x1 +0x1,0x1,0x54,0x737b,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x1996a3bf3f09f5c3d609d0341d07a22a,0x0,0x1 +0x1,0x1,0x55,0x737b,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x30cc16bfe7e74afdd0770ff169502c92,0x0,0x1 +0x1,0x1,0x56,0x737b,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x2c8c2d7e802418dea505c1856cb9f95b,0x0,0x1 +0x1,0x1,0x57,0x737b,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x1ca0a26bec7e4f73d03e9958dff2081a,0x0,0x1 +0x1,0x1,0x58,0x737b,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x198e9393920d483a7260bfb731fb5d25,0x0,0x1 +0x1,0x1,0x59,0x737b,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0xf1aa493335a9e71297e485b7aef312c2,0x0,0x1 +0x1,0x1,0x5a,0x737b,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x1800deef121f1e76426a00665e5c4479,0x0,0x1 +0x1,0x1,0x5b,0x737b,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x674322d4f75edadd46debd5cd992f6ed,0x0,0x1 +0x1,0x1,0x5c,0x737b,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x90689d0585ff075ec9e99ad690c3395,0x0,0x1 +0x1,0x1,0x5d,0x737b,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0xbc4b313370b38ef355acdadcd122975b,0x0,0x1 +0x1,0x1,0x5e,0x737b,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x12c85ea5db8c6deb4aab71808dcb408f,0x0,0x1 +0x1,0x1,0x5f,0x737b,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0xe3d1e7690c43d37b4ce6cc0166fa7daa,0x0,0x1 +0x1,0x1,0x60,0x737b,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x2,0x0,0x0,0x1 +0x1,0x1,0x61,0x737b,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x2,0x0,0x0,0x1 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 diff --git a/prover/zkevm/prover/ecpair/testdata/ecpair_trace_module.csv b/prover/zkevm/prover/ecpair/testdata/ecpair_trace_module.csv new file mode 100644 index 000000000..6426b4188 --- /dev/null +++ b/prover/zkevm/prover/ecpair/testdata/ecpair_trace_module.csv @@ -0,0 +1,257 @@ +ECPAIR_IS_ACTIVE,ECPAIR_UNALIGNED_PAIRING_DATA_IS_ACTIVE,ECPAIR_UNALIGNED_PAIRING_DATA_INDEX,ECPAIR_UNALIGNED_PAIRING_DATA_INSTANCE_ID,ECPAIR_UNALIGNED_PAIRING_DATA_IS_FIRST_LINE_OF_INSTANCE,ECPAIR_UNALIGNED_PAIRING_DATA_IS_ACCUMULATOR_INIT,ECPAIR_UNALIGNED_PAIRING_DATA_IS_FIRST_LINE_OF_PREV_ACC,ECPAIR_UNALIGNED_PAIRING_DATA_IS_ACCUMULATOR_PREV,ECPAIR_UNALIGNED_PAIRING_DATA_IS_FIRST_LINE_OF_CURR_ACC,ECPAIR_UNALIGNED_PAIRING_DATA_IS_ACCUMULATOR_CURR,ECPAIR_UNALIGNED_PAIRING_DATA_IS_RESULT,ECPAIR_UNALIGNED_PAIRING_DATA_IS_COMPUTED,ECPAIR_UNALIGNED_PAIRING_DATA_IS_PULLING,ECPAIR_UNALIGNED_PAIRING_DATA_PAIR_ID,ECPAIR_UNALIGNED_PAIRING_DATA_TOTAL_PAIRS,ECPAIR_UNALIGNED_PAIRING_DATA_LIMB,ECPAIR_UNALIGNED_PAIRING_DATA_TO_MILLER_LOOP_CIRCUIT,ECPAIR_UNALIGNED_PAIRING_DATA_TO_FINAL_EXP_CIRCUIT +0x1,0x1,0x0,0x3f,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x3,0x0,0x1,0x0 +0x1,0x1,0x1,0x3f,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x3,0x1,0x1,0x0 +0x1,0x1,0x2,0x3f,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x3,0x0,0x1,0x0 +0x1,0x1,0x3,0x3f,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x3,0x0,0x1,0x0 +0x1,0x1,0x4,0x3f,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x3,0x0,0x1,0x0 +0x1,0x1,0x5,0x3f,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x3,0x0,0x1,0x0 +0x1,0x1,0x6,0x3f,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x3,0x0,0x1,0x0 +0x1,0x1,0x7,0x3f,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x3,0x0,0x1,0x0 +0x1,0x1,0x8,0x3f,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x3,0x0,0x1,0x0 +0x1,0x1,0x9,0x3f,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x3,0x0,0x1,0x0 +0x1,0x1,0xa,0x3f,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x3,0x0,0x1,0x0 +0x1,0x1,0xb,0x3f,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x3,0x0,0x1,0x0 +0x1,0x1,0xc,0x3f,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x3,0x0,0x1,0x0 +0x1,0x1,0xd,0x3f,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x3,0x0,0x1,0x0 +0x1,0x1,0xe,0x3f,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x3,0x0,0x1,0x0 +0x1,0x1,0xf,0x3f,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x3,0x0,0x1,0x0 +0x1,0x1,0x10,0x3f,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x3,0x0,0x1,0x0 +0x1,0x1,0x11,0x3f,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x3,0x0,0x1,0x0 +0x1,0x1,0x12,0x3f,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x3,0x0,0x1,0x0 +0x1,0x1,0x13,0x3f,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x3,0x0,0x1,0x0 +0x1,0x1,0x14,0x3f,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x3,0x0,0x1,0x0 +0x1,0x1,0x15,0x3f,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x3,0x0,0x1,0x0 +0x1,0x1,0x16,0x3f,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x3,0x0,0x1,0x0 +0x1,0x1,0x17,0x3f,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x3,0x0,0x1,0x0 +0x1,0x1,0x18,0x3f,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x3,0x1395d002b3ca9180fb924650ef0656e,0x1,0x0 +0x1,0x1,0x19,0x3f,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x3,0xad838fd027d487fed681de0d674c30da,0x1,0x0 +0x1,0x1,0x1a,0x3f,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x3,0x97c3a9a072f9c85edf7a36812f8ee05,0x1,0x0 +0x1,0x1,0x1b,0x3f,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x3,0xe2cc73140749dcd7d29ceb34a8412188,0x1,0x0 +0x1,0x1,0x1c,0x3f,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x3,0x2bd3295ff81c577fe772543783411c36,0x1,0x0 +0x1,0x1,0x1d,0x3f,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x3,0xf463676d9692ca4250588fbad0b44dc7,0x1,0x0 +0x1,0x1,0x1e,0x3f,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x3,0x7d8d8329e62324af8091e3a4ffe5a57,0x1,0x0 +0x1,0x1,0x1f,0x3f,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x3,0xcb8664d1f5f6838c55261177118e9313,0x1,0x0 +0x1,0x1,0x20,0x3f,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x3,0x230f1851ba0d3d7d36c8603c7118c86b,0x1,0x0 +0x1,0x1,0x21,0x3f,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x3,0xd2b6a7a1610c4af9e907cb702beff1d8,0x1,0x0 +0x1,0x1,0x22,0x3f,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x3,0x12843e703009c1c1a2f1088dcf4d91e9,0x1,0x0 +0x1,0x1,0x23,0x3f,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x3,0xed43189aa6327cae9a68be22a1aee5cb,0x1,0x0 +0x1,0x1,0x24,0x3f,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x0,0x1,0x3,0x1cf132423a3757d094ef99ada67c9cbb,0x1,0x0 +0x1,0x1,0x25,0x3f,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x3,0xc05ccf866f830043032e06e07dd88a31,0x1,0x0 +0x1,0x1,0x26,0x3f,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x3,0xe30c42cccdf4b6d6c6b05a463b60438,0x1,0x0 +0x1,0x1,0x27,0x3f,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x3,0x170d4ed7935fd1235d19cfc5ee258ba9,0x1,0x0 +0x1,0x1,0x28,0x3f,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x3,0x2cf4fca7e570f69fd5ff51d0d0424699,0x1,0x0 +0x1,0x1,0x29,0x3f,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x3,0x54f670cce3aa1a95a1e3609a24de1507,0x1,0x0 +0x1,0x1,0x2a,0x3f,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x3,0x2e3f1c8b74e6d5303c5dade8d1338d3c,0x1,0x0 +0x1,0x1,0x2b,0x3f,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x3,0x4a0d2a9c4be4cbecd7975385e41cf3b,0x1,0x0 +0x1,0x1,0x2c,0x3f,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x3,0x1841621784db87a58dfc93fd299f7b3e,0x1,0x0 +0x1,0x1,0x2d,0x3f,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x3,0xf0e2f3f8f2a9afca5ce416419edefc72,0x1,0x0 +0x1,0x1,0x2e,0x3f,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x3,0x2f3f5baa49d8c5f9e7b7ae29843c5d35,0x1,0x0 +0x1,0x1,0x2f,0x3f,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x3,0x5f953e4c1e0813885afc2291cd154ede,0x1,0x0 +0x1,0x1,0x30,0x3f,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x3,0x1510a127c5c44cbd93e51dea529b9321,0x1,0x0 +0x1,0x1,0x31,0x3f,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x3,0x50cf06bd0bb7688b9965b90bcedc1af9,0x1,0x0 +0x1,0x1,0x32,0x3f,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x3,0xc9593cee20457e4c62ab5da575f2647,0x1,0x0 +0x1,0x1,0x33,0x3f,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x3,0xf06055f2fd530e59c2896039eab80ee7,0x1,0x0 +0x1,0x1,0x34,0x3f,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x3,0x1b3b112aba7d3a132fcb8c05ae86b218,0x1,0x0 +0x1,0x1,0x35,0x3f,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x3,0x4f132790848da73fa7883daae019a05c,0x1,0x0 +0x1,0x1,0x36,0x3f,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x3,0x233fc6eac88cfd1649495fdf1acdd1b,0x1,0x0 +0x1,0x1,0x37,0x3f,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x3,0xe5d86687e5043ba455a40e42f7d63e3b,0x1,0x0 +0x1,0x1,0x38,0x3f,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x3,0x24a697c910c684744ebad59980360b2c,0x1,0x0 +0x1,0x1,0x39,0x3f,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x3,0xf19c2c4ffd895fb7e84e7aaaf658b917,0x1,0x0 +0x1,0x1,0x3a,0x3f,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x3,0x1834997d6a586ada4ad6e9cf19b11316,0x1,0x0 +0x1,0x1,0x3b,0x3f,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x3,0xd0eae21499fa324cad4e71e9c7c2c161,0x1,0x0 +0x1,0x1,0x3c,0x3f,0x0,0x0,0x1,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x3,0x1cf132423a3757d094ef99ada67c9cbb,0x1,0x0 +0x1,0x1,0x3d,0x3f,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x3,0xc05ccf866f830043032e06e07dd88a31,0x1,0x0 +0x1,0x1,0x3e,0x3f,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x3,0xe30c42cccdf4b6d6c6b05a463b60438,0x1,0x0 +0x1,0x1,0x3f,0x3f,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x3,0x170d4ed7935fd1235d19cfc5ee258ba9,0x1,0x0 +0x1,0x1,0x40,0x3f,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x3,0x2cf4fca7e570f69fd5ff51d0d0424699,0x1,0x0 +0x1,0x1,0x41,0x3f,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x3,0x54f670cce3aa1a95a1e3609a24de1507,0x1,0x0 +0x1,0x1,0x42,0x3f,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x3,0x2e3f1c8b74e6d5303c5dade8d1338d3c,0x1,0x0 +0x1,0x1,0x43,0x3f,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x3,0x4a0d2a9c4be4cbecd7975385e41cf3b,0x1,0x0 +0x1,0x1,0x44,0x3f,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x3,0x1841621784db87a58dfc93fd299f7b3e,0x1,0x0 +0x1,0x1,0x45,0x3f,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x3,0xf0e2f3f8f2a9afca5ce416419edefc72,0x1,0x0 +0x1,0x1,0x46,0x3f,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x3,0x2f3f5baa49d8c5f9e7b7ae29843c5d35,0x1,0x0 +0x1,0x1,0x47,0x3f,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x3,0x5f953e4c1e0813885afc2291cd154ede,0x1,0x0 +0x1,0x1,0x48,0x3f,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x3,0x1510a127c5c44cbd93e51dea529b9321,0x1,0x0 +0x1,0x1,0x49,0x3f,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x3,0x50cf06bd0bb7688b9965b90bcedc1af9,0x1,0x0 +0x1,0x1,0x4a,0x3f,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x3,0xc9593cee20457e4c62ab5da575f2647,0x1,0x0 +0x1,0x1,0x4b,0x3f,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x3,0xf06055f2fd530e59c2896039eab80ee7,0x1,0x0 +0x1,0x1,0x4c,0x3f,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x3,0x1b3b112aba7d3a132fcb8c05ae86b218,0x1,0x0 +0x1,0x1,0x4d,0x3f,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x3,0x4f132790848da73fa7883daae019a05c,0x1,0x0 +0x1,0x1,0x4e,0x3f,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x3,0x233fc6eac88cfd1649495fdf1acdd1b,0x1,0x0 +0x1,0x1,0x4f,0x3f,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x3,0xe5d86687e5043ba455a40e42f7d63e3b,0x1,0x0 +0x1,0x1,0x50,0x3f,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x3,0x24a697c910c684744ebad59980360b2c,0x1,0x0 +0x1,0x1,0x51,0x3f,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x3,0xf19c2c4ffd895fb7e84e7aaaf658b917,0x1,0x0 +0x1,0x1,0x52,0x3f,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x3,0x1834997d6a586ada4ad6e9cf19b11316,0x1,0x0 +0x1,0x1,0x53,0x3f,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x3,0xd0eae21499fa324cad4e71e9c7c2c161,0x1,0x0 +0x1,0x1,0x54,0x3f,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x3,0x5dcb6449ff95e1a04c3132ce3be82a8,0x1,0x0 +0x1,0x1,0x55,0x3f,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x3,0x97811d2087e082e0399985449942a45b,0x1,0x0 +0x1,0x1,0x56,0x3f,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x3,0xcb5122006e9b7ceb5307fa4015b132b,0x1,0x0 +0x1,0x1,0x57,0x3f,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x3,0x3945bb972c83459f598659fc4b5a9d32,0x1,0x0 +0x1,0x1,0x58,0x3f,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x3,0x12618811f3e9fa06644d43cfe3f69c6c,0x1,0x0 +0x1,0x1,0x59,0x3f,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x3,0x17a738128de60f8f3ebb4266bab29be6,0x1,0x0 +0x1,0x1,0x5a,0x3f,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x3,0xa5a6c2ec01c4d1374078ae1bbea91d,0x1,0x0 +0x1,0x1,0x5b,0x3f,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x3,0xea8e938c1275226a1ce51db5e7de53d1,0x1,0x0 +0x1,0x1,0x5c,0x3f,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x3,0x2da43ecc11a0095a72454bb08fb4d111,0x1,0x0 +0x1,0x1,0x5d,0x3f,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x3,0x6facadcab482a1107ae67a12bb3c19f2,0x1,0x0 +0x1,0x1,0x5e,0x3f,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x3,0x1e2f128bf79945a370324b82c36c1e63,0x1,0x0 +0x1,0x1,0x5f,0x3f,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x3,0x509b122c023bd8163495526bb030a216,0x1,0x0 +0x1,0x1,0x60,0x3f,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x0,0x2,0x3,0x292cd168c3ef2c37a8f27c5bbe7c2dff,0x1,0x0 +0x1,0x1,0x61,0x3f,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x2,0x3,0x5a46ba655fbb57ec5efc46b9973b7d65,0x1,0x0 +0x1,0x1,0x62,0x3f,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x2,0x3,0x2cb7ca0140a3f91e02d365e4c31275f8,0x1,0x0 +0x1,0x1,0x63,0x3f,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x2,0x3,0xc1856d0a6cb28650b2d9266980ca00ef,0x1,0x0 +0x1,0x1,0x64,0x3f,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x2,0x3,0x19814a3786275c07e02bd384361d4b7e,0x1,0x0 +0x1,0x1,0x65,0x3f,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x2,0x3,0x6f30fe1bc74fb180719d75ef9a9609d3,0x1,0x0 +0x1,0x1,0x66,0x3f,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x2,0x3,0x17bf6e240bd7895eddbf10206905e6ad,0x1,0x0 +0x1,0x1,0x67,0x3f,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x2,0x3,0xffed4359fee5622b68a81e6314f292ce,0x1,0x0 +0x1,0x1,0x68,0x3f,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x2,0x3,0xff7294fed8bd9ec7e86e15b083c00b2,0x1,0x0 +0x1,0x1,0x69,0x3f,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x2,0x3,0x927517d94b16c0133605486bfd90e477,0x1,0x0 +0x1,0x1,0x6a,0x3f,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x2,0x3,0x191e2bbfd9f4989a3d1a54d21470f96e,0x1,0x0 +0x1,0x1,0x6b,0x3f,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x2,0x3,0xfbf902cf06d4d6d995258e0ea9a9df06,0x1,0x0 +0x1,0x1,0x6c,0x3f,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x2,0x3,0x141076b6ccff6c662090b71a1af7c79f,0x1,0x0 +0x1,0x1,0x6d,0x3f,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x2,0x3,0x26700ab52e2da324955b3865ef94f595,0x1,0x0 +0x1,0x1,0x6e,0x3f,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x2,0x3,0xfac823941439c8120d2c0a637e63e45,0x1,0x0 +0x1,0x1,0x6f,0x3f,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x2,0x3,0x832bca89f3a3bf0132fc34d8a9ba3c22,0x1,0x0 +0x1,0x1,0x70,0x3f,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x2,0x3,0xe3ab8880e570c3e1871ccac25453c9d,0x1,0x0 +0x1,0x1,0x71,0x3f,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x2,0x3,0x9da82ce39eb65dcda6b5e65d7f37e82e,0x1,0x0 +0x1,0x1,0x72,0x3f,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x2,0x3,0x3a1a183f2a698f9d2f14235c7c4e1fc,0x1,0x0 +0x1,0x1,0x73,0x3f,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x2,0x3,0x5e2ce6aad082abaeb72e02c435c01ff3,0x1,0x0 +0x1,0x1,0x74,0x3f,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x2,0x3,0x13b007062ca2e328423d9f6e4afbcdb5,0x1,0x0 +0x1,0x1,0x75,0x3f,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x2,0x3,0xcb16f68b149ea5375803535399011725,0x1,0x0 +0x1,0x1,0x76,0x3f,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x2,0x3,0x19523563e9858fcfded6c6ab452074cb,0x1,0x0 +0x1,0x1,0x77,0x3f,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x2,0x3,0xdb8f9c7ee417eb2ae8917809a44547ff,0x1,0x0 +0x1,0x1,0x78,0x3f,0x0,0x0,0x1,0x1,0x0,0x0,0x0,0x1,0x0,0x3,0x3,0x292cd168c3ef2c37a8f27c5bbe7c2dff,0x0,0x1 +0x1,0x1,0x79,0x3f,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x3,0x3,0x5a46ba655fbb57ec5efc46b9973b7d65,0x0,0x1 +0x1,0x1,0x7a,0x3f,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x3,0x3,0x2cb7ca0140a3f91e02d365e4c31275f8,0x0,0x1 +0x1,0x1,0x7b,0x3f,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x3,0x3,0xc1856d0a6cb28650b2d9266980ca00ef,0x0,0x1 +0x1,0x1,0x7c,0x3f,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x3,0x3,0x19814a3786275c07e02bd384361d4b7e,0x0,0x1 +0x1,0x1,0x7d,0x3f,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x3,0x3,0x6f30fe1bc74fb180719d75ef9a9609d3,0x0,0x1 +0x1,0x1,0x7e,0x3f,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x3,0x3,0x17bf6e240bd7895eddbf10206905e6ad,0x0,0x1 +0x1,0x1,0x7f,0x3f,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x3,0x3,0xffed4359fee5622b68a81e6314f292ce,0x0,0x1 +0x1,0x1,0x80,0x3f,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x3,0x3,0xff7294fed8bd9ec7e86e15b083c00b2,0x0,0x1 +0x1,0x1,0x81,0x3f,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x3,0x3,0x927517d94b16c0133605486bfd90e477,0x0,0x1 +0x1,0x1,0x82,0x3f,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x3,0x3,0x191e2bbfd9f4989a3d1a54d21470f96e,0x0,0x1 +0x1,0x1,0x83,0x3f,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x3,0x3,0xfbf902cf06d4d6d995258e0ea9a9df06,0x0,0x1 +0x1,0x1,0x84,0x3f,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x3,0x3,0x141076b6ccff6c662090b71a1af7c79f,0x0,0x1 +0x1,0x1,0x85,0x3f,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x3,0x3,0x26700ab52e2da324955b3865ef94f595,0x0,0x1 +0x1,0x1,0x86,0x3f,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x3,0x3,0xfac823941439c8120d2c0a637e63e45,0x0,0x1 +0x1,0x1,0x87,0x3f,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x3,0x3,0x832bca89f3a3bf0132fc34d8a9ba3c22,0x0,0x1 +0x1,0x1,0x88,0x3f,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x3,0x3,0xe3ab8880e570c3e1871ccac25453c9d,0x0,0x1 +0x1,0x1,0x89,0x3f,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x3,0x3,0x9da82ce39eb65dcda6b5e65d7f37e82e,0x0,0x1 +0x1,0x1,0x8a,0x3f,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x3,0x3,0x3a1a183f2a698f9d2f14235c7c4e1fc,0x0,0x1 +0x1,0x1,0x8b,0x3f,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x3,0x3,0x5e2ce6aad082abaeb72e02c435c01ff3,0x0,0x1 +0x1,0x1,0x8c,0x3f,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x3,0x3,0x13b007062ca2e328423d9f6e4afbcdb5,0x0,0x1 +0x1,0x1,0x8d,0x3f,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x3,0x3,0xcb16f68b149ea5375803535399011725,0x0,0x1 +0x1,0x1,0x8e,0x3f,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x3,0x3,0x19523563e9858fcfded6c6ab452074cb,0x0,0x1 +0x1,0x1,0x8f,0x3f,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x3,0x3,0xdb8f9c7ee417eb2ae8917809a44547ff,0x0,0x1 +0x1,0x1,0x90,0x3f,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x3,0x3,0x1296d042f33ccbb814746e187aa20af4,0x0,0x1 +0x1,0x1,0x91,0x3f,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x3,0x3,0x9bd503356de4846abee08da9e32ae2ac,0x0,0x1 +0x1,0x1,0x92,0x3f,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x3,0x3,0xb980019d2af83b353aa8c2efda45f16,0x0,0x1 +0x1,0x1,0x93,0x3f,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x3,0x3,0xce523b99452118be7ae5dd1e92e0e4ec,0x0,0x1 +0x1,0x1,0x94,0x3f,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x3,0x3,0x12cd1b1242354b35cd8d2493c487b52,0x0,0x1 +0x1,0x1,0x95,0x3f,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x3,0x3,0x411d111c80e8cfb97080e2db1af5f705,0x0,0x1 +0x1,0x1,0x96,0x3f,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x3,0x3,0x20ca232ed2582feeca2d56a589eec30c,0x0,0x1 +0x1,0x1,0x97,0x3f,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x3,0x3,0x27075a44aced8382d87cd43c011aeeb0,0x0,0x1 +0x1,0x1,0x98,0x3f,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x3,0x3,0x2df7d0d9ae47467ca500b528f38ac384,0x0,0x1 +0x1,0x1,0x99,0x3f,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x3,0x3,0x33885d6a59db6ecd7d27d37145e75360,0x0,0x1 +0x1,0x1,0x9a,0x3f,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x3,0x3,0x1e4d8d4d8878cad4de8dbb31ec11d1ec,0x0,0x1 +0x1,0x1,0x9b,0x3f,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x3,0x3,0xd7b40617c46bb7189ccab201b9bdbaab,0x0,0x1 +0x1,0x1,0x9c,0x3f,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x3,0x0,0x0,0x1 +0x1,0x1,0x9d,0x3f,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x3,0x1,0x0,0x1 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 diff --git a/prover/zkevm/prover/ecpair/testdata/ecpair_triple_pair_module.csv b/prover/zkevm/prover/ecpair/testdata/ecpair_triple_pair_module.csv index 1ef3848fe..a59d72f85 100644 --- a/prover/zkevm/prover/ecpair/testdata/ecpair_triple_pair_module.csv +++ b/prover/zkevm/prover/ecpair/testdata/ecpair_triple_pair_module.csv @@ -1,257 +1,257 @@ -ECPAIR_IS_ACTIVE,ECPAIR_UNALIGNED_PAIRING_DATA_IS_ACTIVE,ECPAIR_UNALIGNED_PAIRING_DATA_INDEX,ECPAIR_UNALIGNED_PAIRING_DATA_INSTANCE_ID,ECPAIR_UNALIGNED_PAIRING_DATA_PAIR_ID,ECPAIR_UNALIGNED_PAIRING_DATA_TOTAL_PAIRS,ECPAIR_UNALIGNED_PAIRING_DATA_IS_COMPUTED,ECPAIR_UNALIGNED_PAIRING_DATA_IS_PULLING,ECPAIR_UNALIGNED_PAIRING_DATA_IS_FIRST_LINE_OF_INSTANCE,ECPAIR_UNALIGNED_PAIRING_DATA_IS_ACCUMULATOR_INIT,ECPAIR_UNALIGNED_PAIRING_DATA_IS_FIRST_LINE_OF_PREV_ACC,ECPAIR_UNALIGNED_PAIRING_DATA_IS_ACCUMULATOR_PREV,ECPAIR_UNALIGNED_PAIRING_DATA_IS_FIRST_LINE_OF_CURR_ACC,ECPAIR_UNALIGNED_PAIRING_DATA_IS_ACCUMULATOR_CURR,ECPAIR_UNALIGNED_PAIRING_DATA_LIMB,ECPAIR_UNALIGNED_PAIRING_DATA_TO_MILLER_LOOP_CIRCUIT,ECPAIR_UNALIGNED_PAIRING_DATA_TO_FINAL_EXP_CIRCUIT -0x1,0x1,0x0,0x0,0x1,0x3,0x1,0x0,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0 -0x1,0x1,0x1,0x0,0x1,0x3,0x1,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x1,0x0 -0x1,0x1,0x2,0x0,0x1,0x3,0x1,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0 -0x1,0x1,0x3,0x0,0x1,0x3,0x1,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0 -0x1,0x1,0x4,0x0,0x1,0x3,0x1,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0 -0x1,0x1,0x5,0x0,0x1,0x3,0x1,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0 -0x1,0x1,0x6,0x0,0x1,0x3,0x1,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0 -0x1,0x1,0x7,0x0,0x1,0x3,0x1,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0 -0x1,0x1,0x8,0x0,0x1,0x3,0x1,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0 -0x1,0x1,0x9,0x0,0x1,0x3,0x1,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0 -0x1,0x1,0xa,0x0,0x1,0x3,0x1,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0 -0x1,0x1,0xb,0x0,0x1,0x3,0x1,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0 -0x1,0x1,0xc,0x0,0x1,0x3,0x1,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0 -0x1,0x1,0xd,0x0,0x1,0x3,0x1,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0 -0x1,0x1,0xe,0x0,0x1,0x3,0x1,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0 -0x1,0x1,0xf,0x0,0x1,0x3,0x1,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0 -0x1,0x1,0x10,0x0,0x1,0x3,0x1,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0 -0x1,0x1,0x11,0x0,0x1,0x3,0x1,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0 -0x1,0x1,0x12,0x0,0x1,0x3,0x1,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0 -0x1,0x1,0x13,0x0,0x1,0x3,0x1,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0 -0x1,0x1,0x14,0x0,0x1,0x3,0x1,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0 -0x1,0x1,0x15,0x0,0x1,0x3,0x1,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0 -0x1,0x1,0x16,0x0,0x1,0x3,0x1,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0 -0x1,0x1,0x17,0x0,0x1,0x3,0x1,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0 -0x1,0x1,0x18,0x0,0x1,0x3,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x100fb2006c3a4409ce06f6c2d535564c,0x1,0x0 -0x1,0x1,0x19,0x0,0x1,0x3,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x92e592aeb426d6c035bb8c0a50202e6d,0x1,0x0 -0x1,0x1,0x1a,0x0,0x1,0x3,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1275964141a90f3170592ade82174d09,0x1,0x0 -0x1,0x1,0x1b,0x0,0x1,0x3,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0xde3cc7f5b79f260f51c143e3268ba06d,0x1,0x0 -0x1,0x1,0x1c,0x0,0x1,0x3,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x2e607689d1161c5cb3d6ed870a5b6f47,0x1,0x0 -0x1,0x1,0x1d,0x0,0x1,0x3,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0xb19627c2c51d3d2eb72f81c540ff9f9d,0x1,0x0 -0x1,0x1,0x1e,0x0,0x1,0x3,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x09d2b2eb399326d9cc552e9753afaeab,0x1,0x0 -0x1,0x1,0x1f,0x0,0x1,0x3,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0xbb29985def8b5800f32145223ff61d48,0x1,0x0 -0x1,0x1,0x20,0x0,0x1,0x3,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x03a5907084b1f9ee93a1fa011b31b383,0x1,0x0 -0x1,0x1,0x21,0x0,0x1,0x3,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x60b7d50b789fbe32d3733176ffd9d46a,0x1,0x0 -0x1,0x1,0x22,0x0,0x1,0x3,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x2e8b82b3506125e8b67bb867604a8892,0x1,0x0 -0x1,0x1,0x23,0x0,0x1,0x3,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x7b9695a8d131627503a0f63bfe5d0cca,0x1,0x0 -0x1,0x1,0x24,0x0,0x1,0x3,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x3b453509cb62c429d8a86ea1cf46897,0x1,0x0 -0x1,0x1,0x25,0x0,0x1,0x3,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0xfc8f75a5184afbfee72be2a8ac39ab6,0x1,0x0 -0x1,0x1,0x26,0x0,0x1,0x3,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x258732ffd31c5ae816e163e3458108dd,0x1,0x0 -0x1,0x1,0x27,0x0,0x1,0x3,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x99caaa2e258abab37bb4b1e675e792b4,0x1,0x0 -0x1,0x1,0x28,0x0,0x1,0x3,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x8dc4617a012a931507f27b285f48a99,0x1,0x0 -0x1,0x1,0x29,0x0,0x1,0x3,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2c0cc58a0906a3a6ef6e5378a04addf2,0x1,0x0 -0x1,0x1,0x2a,0x0,0x1,0x3,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x185514250c1eaff2fdc813fd31c55772,0x1,0x0 -0x1,0x1,0x2b,0x0,0x1,0x3,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x81316979a26c9fdb191f6abac2a0bcf2,0x1,0x0 -0x1,0x1,0x2c,0x0,0x1,0x3,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x26a52e43327b03b40c3b36854698ed02,0x1,0x0 -0x1,0x1,0x2d,0x0,0x1,0x3,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x572116a2bc8995a07550a2c11b3f1bb3,0x1,0x0 -0x1,0x1,0x2e,0x0,0x1,0x3,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x22a813b81101fa27e07888a4c1ee151b,0x1,0x0 -0x1,0x1,0x2f,0x0,0x1,0x3,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0xd5c7de0e174ce72545ed2796a057e0f5,0x1,0x0 -0x1,0x1,0x30,0x0,0x1,0x3,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1755fc232224e41b6b375a49c842eed,0x1,0x0 -0x1,0x1,0x31,0x0,0x1,0x3,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0xe4e0cf3cce99d1664c5e8489205e9461,0x1,0x0 -0x1,0x1,0x32,0x0,0x1,0x3,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2b80c453b72e713a9ee7304f7c598ebe,0x1,0x0 -0x1,0x1,0x33,0x0,0x1,0x3,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0xe28aeb3c386d4c2dfe575197636a578b,0x1,0x0 -0x1,0x1,0x34,0x0,0x1,0x3,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x225235e07cb0c897a4d26f2f76019f3,0x1,0x0 -0x1,0x1,0x35,0x0,0x1,0x3,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0xec0c5349a3d4d57e9ab9e9b48f3ba9b3,0x1,0x0 -0x1,0x1,0x36,0x0,0x1,0x3,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2864b7882cf2e11ed3bffbff7cb788ca,0x1,0x0 -0x1,0x1,0x37,0x0,0x1,0x3,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x30f1e0743e45d9900320f9e6890f6817,0x1,0x0 -0x1,0x1,0x38,0x0,0x1,0x3,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x29293f07fccd8ac29bf0501e823696f,0x1,0x0 -0x1,0x1,0x39,0x0,0x1,0x3,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x71ba1b75f369441cf66cb0c6d8127ad0,0x1,0x0 -0x1,0x1,0x3a,0x0,0x1,0x3,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x15d7ace2db3651ba26cc0852ffa53be9,0x1,0x0 -0x1,0x1,0x3b,0x0,0x1,0x3,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x40a41876d29c7d3d9efea184a2f58712,0x1,0x0 -0x1,0x1,0x3c,0x0,0x2,0x3,0x1,0x0,0x0,0x0,0x1,0x1,0x0,0x0,0x3b453509cb62c429d8a86ea1cf46897,0x1,0x0 -0x1,0x1,0x3d,0x0,0x2,0x3,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0xfc8f75a5184afbfee72be2a8ac39ab6,0x1,0x0 -0x1,0x1,0x3e,0x0,0x2,0x3,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x258732ffd31c5ae816e163e3458108dd,0x1,0x0 -0x1,0x1,0x3f,0x0,0x2,0x3,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x99caaa2e258abab37bb4b1e675e792b4,0x1,0x0 -0x1,0x1,0x40,0x0,0x2,0x3,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x8dc4617a012a931507f27b285f48a99,0x1,0x0 -0x1,0x1,0x41,0x0,0x2,0x3,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x2c0cc58a0906a3a6ef6e5378a04addf2,0x1,0x0 -0x1,0x1,0x42,0x0,0x2,0x3,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x185514250c1eaff2fdc813fd31c55772,0x1,0x0 -0x1,0x1,0x43,0x0,0x2,0x3,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x81316979a26c9fdb191f6abac2a0bcf2,0x1,0x0 -0x1,0x1,0x44,0x0,0x2,0x3,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x26a52e43327b03b40c3b36854698ed02,0x1,0x0 -0x1,0x1,0x45,0x0,0x2,0x3,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x572116a2bc8995a07550a2c11b3f1bb3,0x1,0x0 -0x1,0x1,0x46,0x0,0x2,0x3,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x22a813b81101fa27e07888a4c1ee151b,0x1,0x0 -0x1,0x1,0x47,0x0,0x2,0x3,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0xd5c7de0e174ce72545ed2796a057e0f5,0x1,0x0 -0x1,0x1,0x48,0x0,0x2,0x3,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1755fc232224e41b6b375a49c842eed,0x1,0x0 -0x1,0x1,0x49,0x0,0x2,0x3,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0xe4e0cf3cce99d1664c5e8489205e9461,0x1,0x0 -0x1,0x1,0x4a,0x0,0x2,0x3,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x2b80c453b72e713a9ee7304f7c598ebe,0x1,0x0 -0x1,0x1,0x4b,0x0,0x2,0x3,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0xe28aeb3c386d4c2dfe575197636a578b,0x1,0x0 -0x1,0x1,0x4c,0x0,0x2,0x3,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x225235e07cb0c897a4d26f2f76019f3,0x1,0x0 -0x1,0x1,0x4d,0x0,0x2,0x3,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0xec0c5349a3d4d57e9ab9e9b48f3ba9b3,0x1,0x0 -0x1,0x1,0x4e,0x0,0x2,0x3,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x2864b7882cf2e11ed3bffbff7cb788ca,0x1,0x0 -0x1,0x1,0x4f,0x0,0x2,0x3,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x30f1e0743e45d9900320f9e6890f6817,0x1,0x0 -0x1,0x1,0x50,0x0,0x2,0x3,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x29293f07fccd8ac29bf0501e823696f,0x1,0x0 -0x1,0x1,0x51,0x0,0x2,0x3,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x71ba1b75f369441cf66cb0c6d8127ad0,0x1,0x0 -0x1,0x1,0x52,0x0,0x2,0x3,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x15d7ace2db3651ba26cc0852ffa53be9,0x1,0x0 -0x1,0x1,0x53,0x0,0x2,0x3,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x40a41876d29c7d3d9efea184a2f58712,0x1,0x0 -0x1,0x1,0x54,0x0,0x2,0x3,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1f5ca3dcd416ce988b93b505e473fbc8,0x1,0x0 -0x1,0x1,0x55,0x0,0x2,0x3,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0xa510b9a25ba4af91a01cbf2d66496ba7,0x1,0x0 -0x1,0x1,0x56,0x0,0x2,0x3,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x2ab07af451260653f5d92e48135636fe,0x1,0x0 -0x1,0x1,0x57,0x0,0x2,0x3,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x6e69bfad773e8c1806b4e4bb128048f9,0x1,0x0 -0x1,0x1,0x58,0x0,0x2,0x3,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1e311797d9d7b0c3b1658f72e16632e3,0x1,0x0 -0x1,0x1,0x59,0x0,0x2,0x3,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x927ad04f742ded7fe801e8df6e137325,0x1,0x0 -0x1,0x1,0x5a,0x0,0x2,0x3,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1d0510803ef7512c7915a6879d460c72,0x1,0x0 -0x1,0x1,0x5b,0x0,0x2,0x3,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x27480a98574d5d306828694e1640ec2b,0x1,0x0 -0x1,0x1,0x5c,0x0,0x2,0x3,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0bb8fd9936c7a8c8f4a3d9ce97735df5,0x1,0x0 -0x1,0x1,0x5d,0x0,0x2,0x3,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x41af0c73696dff5f92c6eb248f949a18,0x1,0x0 -0x1,0x1,0x5e,0x0,0x2,0x3,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x15f8308390c00f0a0e1ebcd08626f1ec,0x1,0x0 -0x1,0x1,0x5f,0x0,0x2,0x3,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x57a14cac88cd49f9d0e3caaa20ce36e9,0x1,0x0 -0x1,0x1,0x60,0x0,0x2,0x3,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x152e268cc785bd6c948a88b3091ef9a3,0x1,0x0 -0x1,0x1,0x61,0x0,0x2,0x3,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x708426323c268b89b2a5e02478ccdda6,0x1,0x0 -0x1,0x1,0x62,0x0,0x2,0x3,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2f6d0a4127a8a6f986490f9f8322397c,0x1,0x0 -0x1,0x1,0x63,0x0,0x2,0x3,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x82c9cdc9f0d6ec378eda15ec3dc78b6f,0x1,0x0 -0x1,0x1,0x64,0x0,0x2,0x3,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x21da9702fb1d05b6c0a1007d0b9c160e,0x1,0x0 -0x1,0x1,0x65,0x0,0x2,0x3,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x9d8d0a02fedddd4bce9598f5787c284,0x1,0x0 -0x1,0x1,0x66,0x0,0x2,0x3,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2b46be639fc122126b7e0efbc5398fe8,0x1,0x0 -0x1,0x1,0x67,0x0,0x2,0x3,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x67d9dd3ecc9160db686aaed5bbbd2cbc,0x1,0x0 -0x1,0x1,0x68,0x0,0x2,0x3,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x20d3e1ac646cf95fbf02ad4589eb173d,0x1,0x0 -0x1,0x1,0x69,0x0,0x2,0x3,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x8501b392226c7a7e7818b5781887ef0e,0x1,0x0 -0x1,0x1,0x6a,0x0,0x2,0x3,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0xcb19e117479b79a6b64d592612adf5d,0x1,0x0 -0x1,0x1,0x6b,0x0,0x2,0x3,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0xaacf84e0e323906338a778d53c6d57d2,0x1,0x0 -0x1,0x1,0x6c,0x0,0x2,0x3,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1dd39eb06e7c88b5e3fea51f0bcefc0d,0x1,0x0 -0x1,0x1,0x6d,0x0,0x2,0x3,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0xb11c23cd9f2f7108861555162026536d,0x1,0x0 -0x1,0x1,0x6e,0x0,0x2,0x3,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x290860069e0d24d4363147d4f3d6760a,0x1,0x0 -0x1,0x1,0x6f,0x0,0x2,0x3,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x4fb8917396a450547f84fb7e70c9999f,0x1,0x0 -0x1,0x1,0x70,0x0,0x2,0x3,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2ca828fba83798a17db205631e9903d,0x1,0x0 -0x1,0x1,0x71,0x0,0x2,0x3,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0xe19924a9209f0fe7c06025b0851fbfe9,0x1,0x0 -0x1,0x1,0x72,0x0,0x2,0x3,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x6f263094fe06ea7acc71974bc64d7dd,0x1,0x0 -0x1,0x1,0x73,0x0,0x2,0x3,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0xf167b0ea71dc77d57f39fd46d42db5e4,0x1,0x0 -0x1,0x1,0x74,0x0,0x2,0x3,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x12809c90c9533ba0d7159a9631812b01,0x1,0x0 -0x1,0x1,0x75,0x0,0x2,0x3,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0xef3180f718d6e3693eeaf24f05ff6804,0x1,0x0 -0x1,0x1,0x76,0x0,0x2,0x3,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1821399d4a5711ca9d4e6b605b0c6ff2,0x1,0x0 -0x1,0x1,0x77,0x0,0x2,0x3,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x89ca237ebf99d460e8d0a9301e74a664,0x1,0x0 -0x1,0x1,0x78,0x0,0x3,0x3,0x1,0x0,0x0,0x0,0x1,0x1,0x0,0x0,0x152e268cc785bd6c948a88b3091ef9a3,0x0,0x1 -0x1,0x1,0x79,0x0,0x3,0x3,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x708426323c268b89b2a5e02478ccdda6,0x0,0x1 -0x1,0x1,0x7a,0x0,0x3,0x3,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x2f6d0a4127a8a6f986490f9f8322397c,0x0,0x1 -0x1,0x1,0x7b,0x0,0x3,0x3,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x82c9cdc9f0d6ec378eda15ec3dc78b6f,0x0,0x1 -0x1,0x1,0x7c,0x0,0x3,0x3,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x21da9702fb1d05b6c0a1007d0b9c160e,0x0,0x1 -0x1,0x1,0x7d,0x0,0x3,0x3,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x9d8d0a02fedddd4bce9598f5787c284,0x0,0x1 -0x1,0x1,0x7e,0x0,0x3,0x3,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x2b46be639fc122126b7e0efbc5398fe8,0x0,0x1 -0x1,0x1,0x7f,0x0,0x3,0x3,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x67d9dd3ecc9160db686aaed5bbbd2cbc,0x0,0x1 -0x1,0x1,0x80,0x0,0x3,0x3,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x20d3e1ac646cf95fbf02ad4589eb173d,0x0,0x1 -0x1,0x1,0x81,0x0,0x3,0x3,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x8501b392226c7a7e7818b5781887ef0e,0x0,0x1 -0x1,0x1,0x82,0x0,0x3,0x3,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0xcb19e117479b79a6b64d592612adf5d,0x0,0x1 -0x1,0x1,0x83,0x0,0x3,0x3,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0xaacf84e0e323906338a778d53c6d57d2,0x0,0x1 -0x1,0x1,0x84,0x0,0x3,0x3,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1dd39eb06e7c88b5e3fea51f0bcefc0d,0x0,0x1 -0x1,0x1,0x85,0x0,0x3,0x3,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0xb11c23cd9f2f7108861555162026536d,0x0,0x1 -0x1,0x1,0x86,0x0,0x3,0x3,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x290860069e0d24d4363147d4f3d6760a,0x0,0x1 -0x1,0x1,0x87,0x0,0x3,0x3,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x4fb8917396a450547f84fb7e70c9999f,0x0,0x1 -0x1,0x1,0x88,0x0,0x3,0x3,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x2ca828fba83798a17db205631e9903d,0x0,0x1 -0x1,0x1,0x89,0x0,0x3,0x3,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0xe19924a9209f0fe7c06025b0851fbfe9,0x0,0x1 -0x1,0x1,0x8a,0x0,0x3,0x3,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x6f263094fe06ea7acc71974bc64d7dd,0x0,0x1 -0x1,0x1,0x8b,0x0,0x3,0x3,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0xf167b0ea71dc77d57f39fd46d42db5e4,0x0,0x1 -0x1,0x1,0x8c,0x0,0x3,0x3,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x12809c90c9533ba0d7159a9631812b01,0x0,0x1 -0x1,0x1,0x8d,0x0,0x3,0x3,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0xef3180f718d6e3693eeaf24f05ff6804,0x0,0x1 -0x1,0x1,0x8e,0x0,0x3,0x3,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1821399d4a5711ca9d4e6b605b0c6ff2,0x0,0x1 -0x1,0x1,0x8f,0x0,0x3,0x3,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x89ca237ebf99d460e8d0a9301e74a664,0x0,0x1 -0x1,0x1,0x90,0x0,0x3,0x3,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0c8671a7e8f372087c46b7b82c53c183,0x0,0x1 -0x1,0x1,0x91,0x0,0x3,0x3,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0xd09453270e38045cb7372662d4716f8d,0x0,0x1 -0x1,0x1,0x92,0x0,0x3,0x3,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x20dd05e87836797d4507cc8917ed1079,0x0,0x1 -0x1,0x1,0x93,0x0,0x3,0x3,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0xa10fe34dc7536969843e4cbe868a64ac,0x0,0x1 -0x1,0x1,0x94,0x0,0x3,0x3,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x24e48d89873ad5ebcf0f7022c01020b5,0x0,0x1 -0x1,0x1,0x95,0x0,0x3,0x3,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x10458a3dfc798231e6b5d5f17c8c9e1c,0x0,0x1 -0x1,0x1,0x96,0x0,0x3,0x3,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x2f3ba4b3c58fd37398ceef826e29c853,0x0,0x1 -0x1,0x1,0x97,0x0,0x3,0x3,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x7048f7fec19180f89f4961bf0b00e9c1,0x0,0x1 -0x1,0x1,0x98,0x0,0x3,0x3,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x2ed87dc23279bee95b8caada387b5f5e,0x0,0x1 -0x1,0x1,0x99,0x0,0x3,0x3,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x04fdd666fda2df2aac57457ecfb62014,0x0,0x1 -0x1,0x1,0x9a,0x0,0x3,0x3,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1b77c09a4389d4d50e5b78a8dca80583,0x0,0x1 -0x1,0x1,0x9b,0x0,0x3,0x3,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1056618bfe329ac4dcc8ee73ec818284,0x0,0x1 -0x1,0x1,0x9c,0x0,0x0,0x3,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1 -0x1,0x1,0x9d,0x0,0x0,0x3,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +ECPAIR_IS_ACTIVE,ECPAIR_UNALIGNED_PAIRING_DATA_IS_ACTIVE,ECPAIR_UNALIGNED_PAIRING_DATA_INDEX,ECPAIR_UNALIGNED_PAIRING_DATA_INSTANCE_ID,ECPAIR_UNALIGNED_PAIRING_DATA_IS_FIRST_LINE_OF_INSTANCE,ECPAIR_UNALIGNED_PAIRING_DATA_IS_ACCUMULATOR_INIT,ECPAIR_UNALIGNED_PAIRING_DATA_IS_FIRST_LINE_OF_PREV_ACC,ECPAIR_UNALIGNED_PAIRING_DATA_IS_ACCUMULATOR_PREV,ECPAIR_UNALIGNED_PAIRING_DATA_IS_FIRST_LINE_OF_CURR_ACC,ECPAIR_UNALIGNED_PAIRING_DATA_IS_ACCUMULATOR_CURR,ECPAIR_UNALIGNED_PAIRING_DATA_IS_RESULT,ECPAIR_UNALIGNED_PAIRING_DATA_IS_COMPUTED,ECPAIR_UNALIGNED_PAIRING_DATA_IS_PULLING,ECPAIR_UNALIGNED_PAIRING_DATA_PAIR_ID,ECPAIR_UNALIGNED_PAIRING_DATA_TOTAL_PAIRS,ECPAIR_UNALIGNED_PAIRING_DATA_LIMB,ECPAIR_UNALIGNED_PAIRING_DATA_TO_MILLER_LOOP_CIRCUIT,ECPAIR_UNALIGNED_PAIRING_DATA_TO_FINAL_EXP_CIRCUIT +0x1,0x1,0x0,0x0,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x3,0x0,0x1,0x0 +0x1,0x1,0x1,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x3,0x1,0x1,0x0 +0x1,0x1,0x2,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x3,0x0,0x1,0x0 +0x1,0x1,0x3,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x3,0x0,0x1,0x0 +0x1,0x1,0x4,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x3,0x0,0x1,0x0 +0x1,0x1,0x5,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x3,0x0,0x1,0x0 +0x1,0x1,0x6,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x3,0x0,0x1,0x0 +0x1,0x1,0x7,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x3,0x0,0x1,0x0 +0x1,0x1,0x8,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x3,0x0,0x1,0x0 +0x1,0x1,0x9,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x3,0x0,0x1,0x0 +0x1,0x1,0xa,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x3,0x0,0x1,0x0 +0x1,0x1,0xb,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x3,0x0,0x1,0x0 +0x1,0x1,0xc,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x3,0x0,0x1,0x0 +0x1,0x1,0xd,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x3,0x0,0x1,0x0 +0x1,0x1,0xe,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x3,0x0,0x1,0x0 +0x1,0x1,0xf,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x3,0x0,0x1,0x0 +0x1,0x1,0x10,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x3,0x0,0x1,0x0 +0x1,0x1,0x11,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x3,0x0,0x1,0x0 +0x1,0x1,0x12,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x3,0x0,0x1,0x0 +0x1,0x1,0x13,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x3,0x0,0x1,0x0 +0x1,0x1,0x14,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x3,0x0,0x1,0x0 +0x1,0x1,0x15,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x3,0x0,0x1,0x0 +0x1,0x1,0x16,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x3,0x0,0x1,0x0 +0x1,0x1,0x17,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x3,0x0,0x1,0x0 +0x1,0x1,0x18,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x3,0x100fb2006c3a4409ce06f6c2d535564c,0x1,0x0 +0x1,0x1,0x19,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x3,0x92e592aeb426d6c035bb8c0a50202e6d,0x1,0x0 +0x1,0x1,0x1a,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x3,0x1275964141a90f3170592ade82174d09,0x1,0x0 +0x1,0x1,0x1b,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x3,0xde3cc7f5b79f260f51c143e3268ba06d,0x1,0x0 +0x1,0x1,0x1c,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x3,0x2e607689d1161c5cb3d6ed870a5b6f47,0x1,0x0 +0x1,0x1,0x1d,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x3,0xb19627c2c51d3d2eb72f81c540ff9f9d,0x1,0x0 +0x1,0x1,0x1e,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x3,0x9d2b2eb399326d9cc552e9753afaeab,0x1,0x0 +0x1,0x1,0x1f,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x3,0xbb29985def8b5800f32145223ff61d48,0x1,0x0 +0x1,0x1,0x20,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x3,0x3a5907084b1f9ee93a1fa011b31b383,0x1,0x0 +0x1,0x1,0x21,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x3,0x60b7d50b789fbe32d3733176ffd9d46a,0x1,0x0 +0x1,0x1,0x22,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x3,0x2e8b82b3506125e8b67bb867604a8892,0x1,0x0 +0x1,0x1,0x23,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x3,0x7b9695a8d131627503a0f63bfe5d0cca,0x1,0x0 +0x1,0x1,0x24,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x0,0x1,0x3,0x3b453509cb62c429d8a86ea1cf46897,0x1,0x0 +0x1,0x1,0x25,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x3,0xfc8f75a5184afbfee72be2a8ac39ab6,0x1,0x0 +0x1,0x1,0x26,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x3,0x258732ffd31c5ae816e163e3458108dd,0x1,0x0 +0x1,0x1,0x27,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x3,0x99caaa2e258abab37bb4b1e675e792b4,0x1,0x0 +0x1,0x1,0x28,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x3,0x8dc4617a012a931507f27b285f48a99,0x1,0x0 +0x1,0x1,0x29,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x3,0x2c0cc58a0906a3a6ef6e5378a04addf2,0x1,0x0 +0x1,0x1,0x2a,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x3,0x185514250c1eaff2fdc813fd31c55772,0x1,0x0 +0x1,0x1,0x2b,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x3,0x81316979a26c9fdb191f6abac2a0bcf2,0x1,0x0 +0x1,0x1,0x2c,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x3,0x26a52e43327b03b40c3b36854698ed02,0x1,0x0 +0x1,0x1,0x2d,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x3,0x572116a2bc8995a07550a2c11b3f1bb3,0x1,0x0 +0x1,0x1,0x2e,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x3,0x22a813b81101fa27e07888a4c1ee151b,0x1,0x0 +0x1,0x1,0x2f,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x3,0xd5c7de0e174ce72545ed2796a057e0f5,0x1,0x0 +0x1,0x1,0x30,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x3,0x1755fc232224e41b6b375a49c842eed,0x1,0x0 +0x1,0x1,0x31,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x3,0xe4e0cf3cce99d1664c5e8489205e9461,0x1,0x0 +0x1,0x1,0x32,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x3,0x2b80c453b72e713a9ee7304f7c598ebe,0x1,0x0 +0x1,0x1,0x33,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x3,0xe28aeb3c386d4c2dfe575197636a578b,0x1,0x0 +0x1,0x1,0x34,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x3,0x225235e07cb0c897a4d26f2f76019f3,0x1,0x0 +0x1,0x1,0x35,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x3,0xec0c5349a3d4d57e9ab9e9b48f3ba9b3,0x1,0x0 +0x1,0x1,0x36,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x3,0x2864b7882cf2e11ed3bffbff7cb788ca,0x1,0x0 +0x1,0x1,0x37,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x3,0x30f1e0743e45d9900320f9e6890f6817,0x1,0x0 +0x1,0x1,0x38,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x3,0x29293f07fccd8ac29bf0501e823696f,0x1,0x0 +0x1,0x1,0x39,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x3,0x71ba1b75f369441cf66cb0c6d8127ad0,0x1,0x0 +0x1,0x1,0x3a,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x3,0x15d7ace2db3651ba26cc0852ffa53be9,0x1,0x0 +0x1,0x1,0x3b,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x3,0x40a41876d29c7d3d9efea184a2f58712,0x1,0x0 +0x1,0x1,0x3c,0x0,0x0,0x0,0x1,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x3,0x3b453509cb62c429d8a86ea1cf46897,0x1,0x0 +0x1,0x1,0x3d,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x3,0xfc8f75a5184afbfee72be2a8ac39ab6,0x1,0x0 +0x1,0x1,0x3e,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x3,0x258732ffd31c5ae816e163e3458108dd,0x1,0x0 +0x1,0x1,0x3f,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x3,0x99caaa2e258abab37bb4b1e675e792b4,0x1,0x0 +0x1,0x1,0x40,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x3,0x8dc4617a012a931507f27b285f48a99,0x1,0x0 +0x1,0x1,0x41,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x3,0x2c0cc58a0906a3a6ef6e5378a04addf2,0x1,0x0 +0x1,0x1,0x42,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x3,0x185514250c1eaff2fdc813fd31c55772,0x1,0x0 +0x1,0x1,0x43,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x3,0x81316979a26c9fdb191f6abac2a0bcf2,0x1,0x0 +0x1,0x1,0x44,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x3,0x26a52e43327b03b40c3b36854698ed02,0x1,0x0 +0x1,0x1,0x45,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x3,0x572116a2bc8995a07550a2c11b3f1bb3,0x1,0x0 +0x1,0x1,0x46,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x3,0x22a813b81101fa27e07888a4c1ee151b,0x1,0x0 +0x1,0x1,0x47,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x3,0xd5c7de0e174ce72545ed2796a057e0f5,0x1,0x0 +0x1,0x1,0x48,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x3,0x1755fc232224e41b6b375a49c842eed,0x1,0x0 +0x1,0x1,0x49,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x3,0xe4e0cf3cce99d1664c5e8489205e9461,0x1,0x0 +0x1,0x1,0x4a,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x3,0x2b80c453b72e713a9ee7304f7c598ebe,0x1,0x0 +0x1,0x1,0x4b,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x3,0xe28aeb3c386d4c2dfe575197636a578b,0x1,0x0 +0x1,0x1,0x4c,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x3,0x225235e07cb0c897a4d26f2f76019f3,0x1,0x0 +0x1,0x1,0x4d,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x3,0xec0c5349a3d4d57e9ab9e9b48f3ba9b3,0x1,0x0 +0x1,0x1,0x4e,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x3,0x2864b7882cf2e11ed3bffbff7cb788ca,0x1,0x0 +0x1,0x1,0x4f,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x3,0x30f1e0743e45d9900320f9e6890f6817,0x1,0x0 +0x1,0x1,0x50,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x3,0x29293f07fccd8ac29bf0501e823696f,0x1,0x0 +0x1,0x1,0x51,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x3,0x71ba1b75f369441cf66cb0c6d8127ad0,0x1,0x0 +0x1,0x1,0x52,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x3,0x15d7ace2db3651ba26cc0852ffa53be9,0x1,0x0 +0x1,0x1,0x53,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x3,0x40a41876d29c7d3d9efea184a2f58712,0x1,0x0 +0x1,0x1,0x54,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x3,0x1f5ca3dcd416ce988b93b505e473fbc8,0x1,0x0 +0x1,0x1,0x55,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x3,0xa510b9a25ba4af91a01cbf2d66496ba7,0x1,0x0 +0x1,0x1,0x56,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x3,0x2ab07af451260653f5d92e48135636fe,0x1,0x0 +0x1,0x1,0x57,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x3,0x6e69bfad773e8c1806b4e4bb128048f9,0x1,0x0 +0x1,0x1,0x58,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x3,0x1e311797d9d7b0c3b1658f72e16632e3,0x1,0x0 +0x1,0x1,0x59,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x3,0x927ad04f742ded7fe801e8df6e137325,0x1,0x0 +0x1,0x1,0x5a,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x3,0x1d0510803ef7512c7915a6879d460c72,0x1,0x0 +0x1,0x1,0x5b,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x3,0x27480a98574d5d306828694e1640ec2b,0x1,0x0 +0x1,0x1,0x5c,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x3,0xbb8fd9936c7a8c8f4a3d9ce97735df5,0x1,0x0 +0x1,0x1,0x5d,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x3,0x41af0c73696dff5f92c6eb248f949a18,0x1,0x0 +0x1,0x1,0x5e,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x3,0x15f8308390c00f0a0e1ebcd08626f1ec,0x1,0x0 +0x1,0x1,0x5f,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x3,0x57a14cac88cd49f9d0e3caaa20ce36e9,0x1,0x0 +0x1,0x1,0x60,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x0,0x2,0x3,0x152e268cc785bd6c948a88b3091ef9a3,0x1,0x0 +0x1,0x1,0x61,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x2,0x3,0x708426323c268b89b2a5e02478ccdda6,0x1,0x0 +0x1,0x1,0x62,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x2,0x3,0x2f6d0a4127a8a6f986490f9f8322397c,0x1,0x0 +0x1,0x1,0x63,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x2,0x3,0x82c9cdc9f0d6ec378eda15ec3dc78b6f,0x1,0x0 +0x1,0x1,0x64,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x2,0x3,0x21da9702fb1d05b6c0a1007d0b9c160e,0x1,0x0 +0x1,0x1,0x65,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x2,0x3,0x9d8d0a02fedddd4bce9598f5787c284,0x1,0x0 +0x1,0x1,0x66,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x2,0x3,0x2b46be639fc122126b7e0efbc5398fe8,0x1,0x0 +0x1,0x1,0x67,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x2,0x3,0x67d9dd3ecc9160db686aaed5bbbd2cbc,0x1,0x0 +0x1,0x1,0x68,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x2,0x3,0x20d3e1ac646cf95fbf02ad4589eb173d,0x1,0x0 +0x1,0x1,0x69,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x2,0x3,0x8501b392226c7a7e7818b5781887ef0e,0x1,0x0 +0x1,0x1,0x6a,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x2,0x3,0xcb19e117479b79a6b64d592612adf5d,0x1,0x0 +0x1,0x1,0x6b,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x2,0x3,0xaacf84e0e323906338a778d53c6d57d2,0x1,0x0 +0x1,0x1,0x6c,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x2,0x3,0x1dd39eb06e7c88b5e3fea51f0bcefc0d,0x1,0x0 +0x1,0x1,0x6d,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x2,0x3,0xb11c23cd9f2f7108861555162026536d,0x1,0x0 +0x1,0x1,0x6e,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x2,0x3,0x290860069e0d24d4363147d4f3d6760a,0x1,0x0 +0x1,0x1,0x6f,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x2,0x3,0x4fb8917396a450547f84fb7e70c9999f,0x1,0x0 +0x1,0x1,0x70,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x2,0x3,0x2ca828fba83798a17db205631e9903d,0x1,0x0 +0x1,0x1,0x71,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x2,0x3,0xe19924a9209f0fe7c06025b0851fbfe9,0x1,0x0 +0x1,0x1,0x72,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x2,0x3,0x6f263094fe06ea7acc71974bc64d7dd,0x1,0x0 +0x1,0x1,0x73,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x2,0x3,0xf167b0ea71dc77d57f39fd46d42db5e4,0x1,0x0 +0x1,0x1,0x74,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x2,0x3,0x12809c90c9533ba0d7159a9631812b01,0x1,0x0 +0x1,0x1,0x75,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x2,0x3,0xef3180f718d6e3693eeaf24f05ff6804,0x1,0x0 +0x1,0x1,0x76,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x2,0x3,0x1821399d4a5711ca9d4e6b605b0c6ff2,0x1,0x0 +0x1,0x1,0x77,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x2,0x3,0x89ca237ebf99d460e8d0a9301e74a664,0x1,0x0 +0x1,0x1,0x78,0x0,0x0,0x0,0x1,0x1,0x0,0x0,0x0,0x1,0x0,0x3,0x3,0x152e268cc785bd6c948a88b3091ef9a3,0x0,0x1 +0x1,0x1,0x79,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x3,0x3,0x708426323c268b89b2a5e02478ccdda6,0x0,0x1 +0x1,0x1,0x7a,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x3,0x3,0x2f6d0a4127a8a6f986490f9f8322397c,0x0,0x1 +0x1,0x1,0x7b,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x3,0x3,0x82c9cdc9f0d6ec378eda15ec3dc78b6f,0x0,0x1 +0x1,0x1,0x7c,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x3,0x3,0x21da9702fb1d05b6c0a1007d0b9c160e,0x0,0x1 +0x1,0x1,0x7d,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x3,0x3,0x9d8d0a02fedddd4bce9598f5787c284,0x0,0x1 +0x1,0x1,0x7e,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x3,0x3,0x2b46be639fc122126b7e0efbc5398fe8,0x0,0x1 +0x1,0x1,0x7f,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x3,0x3,0x67d9dd3ecc9160db686aaed5bbbd2cbc,0x0,0x1 +0x1,0x1,0x80,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x3,0x3,0x20d3e1ac646cf95fbf02ad4589eb173d,0x0,0x1 +0x1,0x1,0x81,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x3,0x3,0x8501b392226c7a7e7818b5781887ef0e,0x0,0x1 +0x1,0x1,0x82,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x3,0x3,0xcb19e117479b79a6b64d592612adf5d,0x0,0x1 +0x1,0x1,0x83,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x3,0x3,0xaacf84e0e323906338a778d53c6d57d2,0x0,0x1 +0x1,0x1,0x84,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x3,0x3,0x1dd39eb06e7c88b5e3fea51f0bcefc0d,0x0,0x1 +0x1,0x1,0x85,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x3,0x3,0xb11c23cd9f2f7108861555162026536d,0x0,0x1 +0x1,0x1,0x86,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x3,0x3,0x290860069e0d24d4363147d4f3d6760a,0x0,0x1 +0x1,0x1,0x87,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x3,0x3,0x4fb8917396a450547f84fb7e70c9999f,0x0,0x1 +0x1,0x1,0x88,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x3,0x3,0x2ca828fba83798a17db205631e9903d,0x0,0x1 +0x1,0x1,0x89,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x3,0x3,0xe19924a9209f0fe7c06025b0851fbfe9,0x0,0x1 +0x1,0x1,0x8a,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x3,0x3,0x6f263094fe06ea7acc71974bc64d7dd,0x0,0x1 +0x1,0x1,0x8b,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x3,0x3,0xf167b0ea71dc77d57f39fd46d42db5e4,0x0,0x1 +0x1,0x1,0x8c,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x3,0x3,0x12809c90c9533ba0d7159a9631812b01,0x0,0x1 +0x1,0x1,0x8d,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x3,0x3,0xef3180f718d6e3693eeaf24f05ff6804,0x0,0x1 +0x1,0x1,0x8e,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x3,0x3,0x1821399d4a5711ca9d4e6b605b0c6ff2,0x0,0x1 +0x1,0x1,0x8f,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x3,0x3,0x89ca237ebf99d460e8d0a9301e74a664,0x0,0x1 +0x1,0x1,0x90,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x3,0x3,0xc8671a7e8f372087c46b7b82c53c183,0x0,0x1 +0x1,0x1,0x91,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x3,0x3,0xd09453270e38045cb7372662d4716f8d,0x0,0x1 +0x1,0x1,0x92,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x3,0x3,0x20dd05e87836797d4507cc8917ed1079,0x0,0x1 +0x1,0x1,0x93,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x3,0x3,0xa10fe34dc7536969843e4cbe868a64ac,0x0,0x1 +0x1,0x1,0x94,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x3,0x3,0x24e48d89873ad5ebcf0f7022c01020b5,0x0,0x1 +0x1,0x1,0x95,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x3,0x3,0x10458a3dfc798231e6b5d5f17c8c9e1c,0x0,0x1 +0x1,0x1,0x96,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x3,0x3,0x2f3ba4b3c58fd37398ceef826e29c853,0x0,0x1 +0x1,0x1,0x97,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x3,0x3,0x7048f7fec19180f89f4961bf0b00e9c1,0x0,0x1 +0x1,0x1,0x98,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x3,0x3,0x2ed87dc23279bee95b8caada387b5f5e,0x0,0x1 +0x1,0x1,0x99,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x3,0x3,0x4fdd666fda2df2aac57457ecfb62014,0x0,0x1 +0x1,0x1,0x9a,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x3,0x3,0x1b77c09a4389d4d50e5b78a8dca80583,0x0,0x1 +0x1,0x1,0x9b,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x3,0x3,0x1056618bfe329ac4dcc8ee73ec818284,0x0,0x1 +0x1,0x1,0x9c,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x3,0x0,0x0,0x1 +0x1,0x1,0x9d,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x3,0x1,0x0,0x1 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 diff --git a/prover/zkevm/prover/ecpair/testdata/ecpair_two_pairings_module.csv b/prover/zkevm/prover/ecpair/testdata/ecpair_two_pairings_module.csv index 9a5b8368f..1ac1becf5 100644 --- a/prover/zkevm/prover/ecpair/testdata/ecpair_two_pairings_module.csv +++ b/prover/zkevm/prover/ecpair/testdata/ecpair_two_pairings_module.csv @@ -1,257 +1,257 @@ -ECPAIR_IS_ACTIVE,ECPAIR_UNALIGNED_PAIRING_DATA_IS_ACTIVE,ECPAIR_UNALIGNED_PAIRING_DATA_INDEX,ECPAIR_UNALIGNED_PAIRING_DATA_INSTANCE_ID,ECPAIR_UNALIGNED_PAIRING_DATA_IS_FIRST_LINE_OF_INSTANCE,ECPAIR_UNALIGNED_PAIRING_DATA_IS_ACCUMULATOR_INIT,ECPAIR_UNALIGNED_PAIRING_DATA_IS_FIRST_LINE_OF_PREV_ACC,ECPAIR_UNALIGNED_PAIRING_DATA_IS_ACCUMULATOR_PREV,ECPAIR_UNALIGNED_PAIRING_DATA_IS_FIRST_LINE_OF_CURR_ACC,ECPAIR_UNALIGNED_PAIRING_DATA_IS_ACCUMULATOR_CURR,ECPAIR_UNALIGNED_PAIRING_DATA_IS_COMPUTED,ECPAIR_UNALIGNED_PAIRING_DATA_IS_PULLING,ECPAIR_UNALIGNED_PAIRING_DATA_PAIR_ID,ECPAIR_UNALIGNED_PAIRING_DATA_TOTAL_PAIRS,ECPAIR_UNALIGNED_PAIRING_DATA_LIMB,ECPAIR_UNALIGNED_PAIRING_DATA_TO_MILLER_LOOP_CIRCUIT,ECPAIR_UNALIGNED_PAIRING_DATA_TO_FINAL_EXP_CIRCUIT -0x1,0x1,0x0,0x0,0x1,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x1,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x1,0x1,0x0 -0x1,0x1,0x2,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x3,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x4,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x5,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x6,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x7,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x8,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x9,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0xa,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0xb,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0xc,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0xd,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0xe,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0xf,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x10,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x11,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x12,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x13,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x14,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x15,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x16,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x17,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x18,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x13364879816394e38a2d72bde23bda93,0x1,0x0 -0x1,0x1,0x19,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0xcd39885c6bfdedbc45e6bafcfc8fa685,0x1,0x0 -0x1,0x1,0x1a,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x0e0e4c9d03746d287b341d52461946a1,0x1,0x0 -0x1,0x1,0x1b,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0xc865002c35ba9bd6b789fc26a526d121,0x1,0x0 -0x1,0x1,0x1c,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x0e82be8514331e947408a3a27a54d580,0x1,0x0 -0x1,0x1,0x1d,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x9866db37d74db5abc7de8f0d3d0f7ee3,0x1,0x0 -0x1,0x1,0x1e,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x0f89c9a7bb2eb9418d2d89310306196d,0x1,0x0 -0x1,0x1,0x1f,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0xf1ae8d9de0173f3e1151487bb5157cd7,0x1,0x0 -0x1,0x1,0x20,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x10b30b9925aace81dcec2ccce77c3eea,0x1,0x0 -0x1,0x1,0x21,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0xa949c366d7cd71a6a6748bcdd996b762,0x1,0x0 -0x1,0x1,0x22,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x11497987c563ade267b3bdfcc9c04022,0x1,0x0 -0x1,0x1,0x23,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x3e25664c3bcdd28858b1daa7ac249034,0x1,0x0 -0x1,0x1,0x24,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x1,0x0,0x1,0x2,0x1fc57e97fc7f579bbc2ba220d9b10d46,0x1,0x0 -0x1,0x1,0x25,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x4c95627608bdbb0235762c7048400f93,0x1,0x0 -0x1,0x1,0x26,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x2b4305dcdfcf51d41a169cbe7b4e89d4,0x1,0x0 -0x1,0x1,0x27,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x59f4578a51cdbe050925fc0b9312aa86,0x1,0x0 -0x1,0x1,0x28,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x1133d6c9d0cacf4e7cd03b8ae8654f3b,0x1,0x0 -0x1,0x1,0x29,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0xfbfc80323c91c70825d4aa8accfd77b8,0x1,0x0 -0x1,0x1,0x2a,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x2b45ce688738a571621b63dba9880856,0x1,0x0 -0x1,0x1,0x2b,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x9dd4ff917cefc257d7cfe3ea571e206a,0x1,0x0 -0x1,0x1,0x2c,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x653b8af047158278411df902874a82a,0x1,0x0 -0x1,0x1,0x2d,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x401206aafb12aa7c2d704f51f115d8c2,0x1,0x0 -0x1,0x1,0x2e,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x1373a842ceca78f2ae076804f168559c,0x1,0x0 -0x1,0x1,0x2f,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x1781cbb3451085c1166bdadbc7c92688,0x1,0x0 -0x1,0x1,0x30,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x2c8c1f272129cf6b0866ad1d8f3ac818,0x1,0x0 -0x1,0x1,0x31,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x2f12833bfd8a1711d7947461776699df,0x1,0x0 -0x1,0x1,0x32,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x16e10599cfcd3537d808d197ce64c2c5,0x1,0x0 -0x1,0x1,0x33,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0xdaf005b2c0be94b08c52e30acfb098e,0x1,0x0 -0x1,0x1,0x34,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0xd5d04cfad426760d9019d3d15b98aee,0x1,0x0 -0x1,0x1,0x35,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x8c37f28a10bb3cfa2f3971505c77db23,0x1,0x0 -0x1,0x1,0x36,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x22af99c52785193aa8920826c0d96380,0x1,0x0 -0x1,0x1,0x37,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0xe8213976bbbab27922a2cd8c8fe4adeb,0x1,0x0 -0x1,0x1,0x38,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0xa6356a8a0caaec7d1a28661b990a20b,0x1,0x0 -0x1,0x1,0x39,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x217f227c48e2682613693d3afb8231e,0x1,0x0 -0x1,0x1,0x3a,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x5641ef4d251e87484afef7cae876258,0x1,0x0 -0x1,0x1,0x3b,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0xc199d8553a68a9408d2603bd9ff29c36,0x1,0x0 -0x1,0x1,0x3c,0x0,0x0,0x0,0x1,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x1fc57e97fc7f579bbc2ba220d9b10d46,0x0,0x1 -0x1,0x1,0x3d,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x4c95627608bdbb0235762c7048400f93,0x0,0x1 -0x1,0x1,0x3e,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x2b4305dcdfcf51d41a169cbe7b4e89d4,0x0,0x1 -0x1,0x1,0x3f,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x59f4578a51cdbe050925fc0b9312aa86,0x0,0x1 -0x1,0x1,0x40,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x1133d6c9d0cacf4e7cd03b8ae8654f3b,0x0,0x1 -0x1,0x1,0x41,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0xfbfc80323c91c70825d4aa8accfd77b8,0x0,0x1 -0x1,0x1,0x42,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x2b45ce688738a571621b63dba9880856,0x0,0x1 -0x1,0x1,0x43,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x9dd4ff917cefc257d7cfe3ea571e206a,0x0,0x1 -0x1,0x1,0x44,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x653b8af047158278411df902874a82a,0x0,0x1 -0x1,0x1,0x45,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x401206aafb12aa7c2d704f51f115d8c2,0x0,0x1 -0x1,0x1,0x46,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x1373a842ceca78f2ae076804f168559c,0x0,0x1 -0x1,0x1,0x47,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x1781cbb3451085c1166bdadbc7c92688,0x0,0x1 -0x1,0x1,0x48,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x2c8c1f272129cf6b0866ad1d8f3ac818,0x0,0x1 -0x1,0x1,0x49,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x2f12833bfd8a1711d7947461776699df,0x0,0x1 -0x1,0x1,0x4a,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x16e10599cfcd3537d808d197ce64c2c5,0x0,0x1 -0x1,0x1,0x4b,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0xdaf005b2c0be94b08c52e30acfb098e,0x0,0x1 -0x1,0x1,0x4c,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0xd5d04cfad426760d9019d3d15b98aee,0x0,0x1 -0x1,0x1,0x4d,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x8c37f28a10bb3cfa2f3971505c77db23,0x0,0x1 -0x1,0x1,0x4e,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x22af99c52785193aa8920826c0d96380,0x0,0x1 -0x1,0x1,0x4f,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0xe8213976bbbab27922a2cd8c8fe4adeb,0x0,0x1 -0x1,0x1,0x50,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0xa6356a8a0caaec7d1a28661b990a20b,0x0,0x1 -0x1,0x1,0x51,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x217f227c48e2682613693d3afb8231e,0x0,0x1 -0x1,0x1,0x52,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x5641ef4d251e87484afef7cae876258,0x0,0x1 -0x1,0x1,0x53,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0xc199d8553a68a9408d2603bd9ff29c36,0x0,0x1 -0x1,0x1,0x54,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x0b9624a62e115247146d4643e8d4daf0,0x0,0x1 -0x1,0x1,0x55,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x7ff180000fcf9f02c84cc5692b2c0526,0x0,0x1 -0x1,0x1,0x56,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x1cb9908c06bf3099f1538277102b31e3,0x0,0x1 -0x1,0x1,0x57,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x1d022dc64770bc130df14daef72830e4,0x0,0x1 -0x1,0x1,0x58,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x2977858b214a3cb43fa4024976dd1675,0x0,0x1 -0x1,0x1,0x59,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x9b1bf5367e6318da3545e697b9931671,0x0,0x1 -0x1,0x1,0x5a,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x06fcfd4b9ca03fb145ff273e480efda3,0x0,0x1 -0x1,0x1,0x5b,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0xc8a7aef64882efcbd8920b4458e1ef3d,0x0,0x1 -0x1,0x1,0x5c,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x281508326108309778f9cdf9c39a4c4d,0x0,0x1 -0x1,0x1,0x5d,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0xc90a405c0cfbfd5d20fec4e47acce66f,0x0,0x1 -0x1,0x1,0x5e,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x10d24b6f0b87c1e3f78b80b967bac765,0x0,0x1 -0x1,0x1,0x5f,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x763f38c53a4377e9a97e2761758a92f1,0x0,0x1 -0x1,0x1,0x60,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x2,0x0,0x0,0x1 -0x1,0x1,0x61,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x2,0x1,0x0,0x1 -0x1,0x1,0x0,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x1,0x1,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x1,0x1,0x0 -0x1,0x1,0x2,0x1,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x3,0x1,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x4,0x1,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x5,0x1,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x6,0x1,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x7,0x1,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x8,0x1,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x9,0x1,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0xa,0x1,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0xb,0x1,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0xc,0x1,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0xd,0x1,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0xe,0x1,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0xf,0x1,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x10,0x1,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x11,0x1,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x12,0x1,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x13,0x1,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x14,0x1,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x15,0x1,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x16,0x1,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x17,0x1,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x18,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x0b9624a62e115247146d4643e8d4daf0,0x1,0x0 -0x1,0x1,0x19,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x7ff180000fcf9f02c84cc5692b2c0526,0x1,0x0 -0x1,0x1,0x1a,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x13aabde6da726f8fc6fcc33f7156267a,0x1,0x0 -0x1,0x1,0x1b,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x7a7f3ccb21010e7a2e2f3e67e154cc63,0x1,0x0 -0x1,0x1,0x1c,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x0e82be8514331e947408a3a27a54d580,0x1,0x0 -0x1,0x1,0x1d,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x9866db37d74db5abc7de8f0d3d0f7ee3,0x1,0x0 -0x1,0x1,0x1e,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x0f89c9a7bb2eb9418d2d89310306196d,0x1,0x0 -0x1,0x1,0x1f,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0xf1ae8d9de0173f3e1151487bb5157cd7,0x1,0x0 -0x1,0x1,0x20,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x10b30b9925aace81dcec2ccce77c3eea,0x1,0x0 -0x1,0x1,0x21,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0xa949c366d7cd71a6a6748bcdd996b762,0x1,0x0 -0x1,0x1,0x22,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x11497987c563ade267b3bdfcc9c04022,0x1,0x0 -0x1,0x1,0x23,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x3e25664c3bcdd28858b1daa7ac249034,0x1,0x0 -0x1,0x1,0x24,0x1,0x0,0x0,0x0,0x0,0x1,0x1,0x1,0x0,0x1,0x2,0x1d986c0862b80ece8d231a383cb73943,0x1,0x0 -0x1,0x1,0x25,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x3dbbc8770d85f0584f6dc86875624cea,0x1,0x0 -0x1,0x1,0x26,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x3c51f8072e2a8a07f6a06f5088e9ab2,0x1,0x0 -0x1,0x1,0x27,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0xdbc106c833cd19dffcb9e1073ec1805c,0x1,0x0 -0x1,0x1,0x28,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x24ef30331e45aacaa2c0db503198129d,0x1,0x0 -0x1,0x1,0x29,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x698da943542b3b26946e11a08dc6144,0x1,0x0 -0x1,0x1,0x2a,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x229bffeec7cae24f754f3353492e06b7,0x1,0x0 -0x1,0x1,0x2b,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x38b7714ed0c32e48e7afaf62a4efa110,0x1,0x0 -0x1,0x1,0x2c,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x10bc1cc6e37e745faa3ed918cc36edc9,0x1,0x0 -0x1,0x1,0x2d,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x21edc644688a0705476f795d39af8b66,0x1,0x0 -0x1,0x1,0x2e,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x2adcf726eec4f68995c3207f92aea375,0x1,0x0 -0x1,0x1,0x2f,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0xfcd13ed4fe7b43ad615735680a4485e7,0x1,0x0 -0x1,0x1,0x30,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x1f0e7e775eefc2a5672928b4efc2c508,0x1,0x0 -0x1,0x1,0x31,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0xd1b9522023a1105027220223481cad5e,0x1,0x0 -0x1,0x1,0x32,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x241401f805f060cf5e55b76d0a1d9703,0x1,0x0 -0x1,0x1,0x33,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x623d8250a84288f9a9d6b32e4a79ab25,0x1,0x0 -0x1,0x1,0x34,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x2aefa1de34a54b19496ac527550823fc,0x1,0x0 -0x1,0x1,0x35,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x4b742adbe4a5e836b5a4c3c601d721be,0x1,0x0 -0x1,0x1,0x36,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x2feeac4095267db703b602ff985fc423,0x1,0x0 -0x1,0x1,0x37,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x235e6c11ea98a28c6a34a72c6ee2ddc,0x1,0x0 -0x1,0x1,0x38,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x1d75dcc79d6ddd435182ca5de99635c0,0x1,0x0 -0x1,0x1,0x39,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x212f3e7e80bdfa698ac725005f8dae63,0x1,0x0 -0x1,0x1,0x3a,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x5aeef8c0490c8356ffdd4913155eb21,0x1,0x0 -0x1,0x1,0x3b,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0xd66a1367a4c8c3f6c041b4227c1bf352,0x1,0x0 -0x1,0x1,0x3c,0x1,0x0,0x0,0x1,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x1d986c0862b80ece8d231a383cb73943,0x0,0x1 -0x1,0x1,0x3d,0x1,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x3dbbc8770d85f0584f6dc86875624cea,0x0,0x1 -0x1,0x1,0x3e,0x1,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x3c51f8072e2a8a07f6a06f5088e9ab2,0x0,0x1 -0x1,0x1,0x3f,0x1,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0xdbc106c833cd19dffcb9e1073ec1805c,0x0,0x1 -0x1,0x1,0x40,0x1,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x24ef30331e45aacaa2c0db503198129d,0x0,0x1 -0x1,0x1,0x41,0x1,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x698da943542b3b26946e11a08dc6144,0x0,0x1 -0x1,0x1,0x42,0x1,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x229bffeec7cae24f754f3353492e06b7,0x0,0x1 -0x1,0x1,0x43,0x1,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x38b7714ed0c32e48e7afaf62a4efa110,0x0,0x1 -0x1,0x1,0x44,0x1,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x10bc1cc6e37e745faa3ed918cc36edc9,0x0,0x1 -0x1,0x1,0x45,0x1,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x21edc644688a0705476f795d39af8b66,0x0,0x1 -0x1,0x1,0x46,0x1,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x2adcf726eec4f68995c3207f92aea375,0x0,0x1 -0x1,0x1,0x47,0x1,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0xfcd13ed4fe7b43ad615735680a4485e7,0x0,0x1 -0x1,0x1,0x48,0x1,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x1f0e7e775eefc2a5672928b4efc2c508,0x0,0x1 -0x1,0x1,0x49,0x1,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0xd1b9522023a1105027220223481cad5e,0x0,0x1 -0x1,0x1,0x4a,0x1,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x241401f805f060cf5e55b76d0a1d9703,0x0,0x1 -0x1,0x1,0x4b,0x1,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x623d8250a84288f9a9d6b32e4a79ab25,0x0,0x1 -0x1,0x1,0x4c,0x1,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x2aefa1de34a54b19496ac527550823fc,0x0,0x1 -0x1,0x1,0x4d,0x1,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x4b742adbe4a5e836b5a4c3c601d721be,0x0,0x1 -0x1,0x1,0x4e,0x1,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x2feeac4095267db703b602ff985fc423,0x0,0x1 -0x1,0x1,0x4f,0x1,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x235e6c11ea98a28c6a34a72c6ee2ddc,0x0,0x1 -0x1,0x1,0x50,0x1,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x1d75dcc79d6ddd435182ca5de99635c0,0x0,0x1 -0x1,0x1,0x51,0x1,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x212f3e7e80bdfa698ac725005f8dae63,0x0,0x1 -0x1,0x1,0x52,0x1,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x5aeef8c0490c8356ffdd4913155eb21,0x0,0x1 -0x1,0x1,0x53,0x1,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0xd66a1367a4c8c3f6c041b4227c1bf352,0x0,0x1 -0x1,0x1,0x54,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x0b9624a62e115247146d4643e8d4daf0,0x0,0x1 -0x1,0x1,0x55,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x7ff180000fcf9f02c84cc5692b2c0526,0x0,0x1 -0x1,0x1,0x56,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x1cb9908c06bf3099f1538277102b31e3,0x0,0x1 -0x1,0x1,0x57,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x1d022dc64770bc130df14daef72830e4,0x0,0x1 -0x1,0x1,0x58,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x0e82be8514331e947408a3a27a54d580,0x0,0x1 -0x1,0x1,0x59,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x9866db37d74db5abc7de8f0d3d0f7ee3,0x0,0x1 -0x1,0x1,0x5a,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x0f89c9a7bb2eb9418d2d89310306196d,0x0,0x1 -0x1,0x1,0x5b,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0xf1ae8d9de0173f3e1151487bb5157cd7,0x0,0x1 -0x1,0x1,0x5c,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x10b30b9925aace81dcec2ccce77c3eea,0x0,0x1 -0x1,0x1,0x5d,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0xa949c366d7cd71a6a6748bcdd996b762,0x0,0x1 -0x1,0x1,0x5e,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x11497987c563ade267b3bdfcc9c04022,0x0,0x1 -0x1,0x1,0x5f,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x3e25664c3bcdd28858b1daa7ac249034,0x0,0x1 -0x1,0x1,0x60,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x2,0x0,0x0,0x1 -0x1,0x1,0x61,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x2,0x1,0x0,0x1 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +ECPAIR_IS_ACTIVE,ECPAIR_UNALIGNED_PAIRING_DATA_IS_ACTIVE,ECPAIR_UNALIGNED_PAIRING_DATA_INDEX,ECPAIR_UNALIGNED_PAIRING_DATA_INSTANCE_ID,ECPAIR_UNALIGNED_PAIRING_DATA_IS_FIRST_LINE_OF_INSTANCE,ECPAIR_UNALIGNED_PAIRING_DATA_IS_ACCUMULATOR_INIT,ECPAIR_UNALIGNED_PAIRING_DATA_IS_FIRST_LINE_OF_PREV_ACC,ECPAIR_UNALIGNED_PAIRING_DATA_IS_ACCUMULATOR_PREV,ECPAIR_UNALIGNED_PAIRING_DATA_IS_FIRST_LINE_OF_CURR_ACC,ECPAIR_UNALIGNED_PAIRING_DATA_IS_ACCUMULATOR_CURR,ECPAIR_UNALIGNED_PAIRING_DATA_IS_RESULT,ECPAIR_UNALIGNED_PAIRING_DATA_IS_COMPUTED,ECPAIR_UNALIGNED_PAIRING_DATA_IS_PULLING,ECPAIR_UNALIGNED_PAIRING_DATA_PAIR_ID,ECPAIR_UNALIGNED_PAIRING_DATA_TOTAL_PAIRS,ECPAIR_UNALIGNED_PAIRING_DATA_LIMB,ECPAIR_UNALIGNED_PAIRING_DATA_TO_MILLER_LOOP_CIRCUIT,ECPAIR_UNALIGNED_PAIRING_DATA_TO_FINAL_EXP_CIRCUIT +0x1,0x1,0x0,0x0,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x1,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x1,0x1,0x0 +0x1,0x1,0x2,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x3,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x4,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x5,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x6,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x7,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x8,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x9,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0xa,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0xb,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0xc,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0xd,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0xe,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0xf,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x10,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x11,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x12,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x13,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x14,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x15,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x16,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x17,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x18,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x13364879816394e38a2d72bde23bda93,0x1,0x0 +0x1,0x1,0x19,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0xcd39885c6bfdedbc45e6bafcfc8fa685,0x1,0x0 +0x1,0x1,0x1a,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0xe0e4c9d03746d287b341d52461946a1,0x1,0x0 +0x1,0x1,0x1b,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0xc865002c35ba9bd6b789fc26a526d121,0x1,0x0 +0x1,0x1,0x1c,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0xe82be8514331e947408a3a27a54d580,0x1,0x0 +0x1,0x1,0x1d,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x9866db37d74db5abc7de8f0d3d0f7ee3,0x1,0x0 +0x1,0x1,0x1e,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0xf89c9a7bb2eb9418d2d89310306196d,0x1,0x0 +0x1,0x1,0x1f,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0xf1ae8d9de0173f3e1151487bb5157cd7,0x1,0x0 +0x1,0x1,0x20,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x10b30b9925aace81dcec2ccce77c3eea,0x1,0x0 +0x1,0x1,0x21,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0xa949c366d7cd71a6a6748bcdd996b762,0x1,0x0 +0x1,0x1,0x22,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x11497987c563ade267b3bdfcc9c04022,0x1,0x0 +0x1,0x1,0x23,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x3e25664c3bcdd28858b1daa7ac249034,0x1,0x0 +0x1,0x1,0x24,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x0,0x1,0x2,0x1fc57e97fc7f579bbc2ba220d9b10d46,0x1,0x0 +0x1,0x1,0x25,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x4c95627608bdbb0235762c7048400f93,0x1,0x0 +0x1,0x1,0x26,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x2b4305dcdfcf51d41a169cbe7b4e89d4,0x1,0x0 +0x1,0x1,0x27,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x59f4578a51cdbe050925fc0b9312aa86,0x1,0x0 +0x1,0x1,0x28,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x1133d6c9d0cacf4e7cd03b8ae8654f3b,0x1,0x0 +0x1,0x1,0x29,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0xfbfc80323c91c70825d4aa8accfd77b8,0x1,0x0 +0x1,0x1,0x2a,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x2b45ce688738a571621b63dba9880856,0x1,0x0 +0x1,0x1,0x2b,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x9dd4ff917cefc257d7cfe3ea571e206a,0x1,0x0 +0x1,0x1,0x2c,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x653b8af047158278411df902874a82a,0x1,0x0 +0x1,0x1,0x2d,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x401206aafb12aa7c2d704f51f115d8c2,0x1,0x0 +0x1,0x1,0x2e,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x1373a842ceca78f2ae076804f168559c,0x1,0x0 +0x1,0x1,0x2f,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x1781cbb3451085c1166bdadbc7c92688,0x1,0x0 +0x1,0x1,0x30,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x2c8c1f272129cf6b0866ad1d8f3ac818,0x1,0x0 +0x1,0x1,0x31,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x2f12833bfd8a1711d7947461776699df,0x1,0x0 +0x1,0x1,0x32,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x16e10599cfcd3537d808d197ce64c2c5,0x1,0x0 +0x1,0x1,0x33,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0xdaf005b2c0be94b08c52e30acfb098e,0x1,0x0 +0x1,0x1,0x34,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0xd5d04cfad426760d9019d3d15b98aee,0x1,0x0 +0x1,0x1,0x35,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x8c37f28a10bb3cfa2f3971505c77db23,0x1,0x0 +0x1,0x1,0x36,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x22af99c52785193aa8920826c0d96380,0x1,0x0 +0x1,0x1,0x37,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0xe8213976bbbab27922a2cd8c8fe4adeb,0x1,0x0 +0x1,0x1,0x38,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0xa6356a8a0caaec7d1a28661b990a20b,0x1,0x0 +0x1,0x1,0x39,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x217f227c48e2682613693d3afb8231e,0x1,0x0 +0x1,0x1,0x3a,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x5641ef4d251e87484afef7cae876258,0x1,0x0 +0x1,0x1,0x3b,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0xc199d8553a68a9408d2603bd9ff29c36,0x1,0x0 +0x1,0x1,0x3c,0x0,0x0,0x0,0x1,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x1fc57e97fc7f579bbc2ba220d9b10d46,0x0,0x1 +0x1,0x1,0x3d,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x4c95627608bdbb0235762c7048400f93,0x0,0x1 +0x1,0x1,0x3e,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x2b4305dcdfcf51d41a169cbe7b4e89d4,0x0,0x1 +0x1,0x1,0x3f,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x59f4578a51cdbe050925fc0b9312aa86,0x0,0x1 +0x1,0x1,0x40,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x1133d6c9d0cacf4e7cd03b8ae8654f3b,0x0,0x1 +0x1,0x1,0x41,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0xfbfc80323c91c70825d4aa8accfd77b8,0x0,0x1 +0x1,0x1,0x42,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x2b45ce688738a571621b63dba9880856,0x0,0x1 +0x1,0x1,0x43,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x9dd4ff917cefc257d7cfe3ea571e206a,0x0,0x1 +0x1,0x1,0x44,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x653b8af047158278411df902874a82a,0x0,0x1 +0x1,0x1,0x45,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x401206aafb12aa7c2d704f51f115d8c2,0x0,0x1 +0x1,0x1,0x46,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x1373a842ceca78f2ae076804f168559c,0x0,0x1 +0x1,0x1,0x47,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x1781cbb3451085c1166bdadbc7c92688,0x0,0x1 +0x1,0x1,0x48,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x2c8c1f272129cf6b0866ad1d8f3ac818,0x0,0x1 +0x1,0x1,0x49,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x2f12833bfd8a1711d7947461776699df,0x0,0x1 +0x1,0x1,0x4a,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x16e10599cfcd3537d808d197ce64c2c5,0x0,0x1 +0x1,0x1,0x4b,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0xdaf005b2c0be94b08c52e30acfb098e,0x0,0x1 +0x1,0x1,0x4c,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0xd5d04cfad426760d9019d3d15b98aee,0x0,0x1 +0x1,0x1,0x4d,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x8c37f28a10bb3cfa2f3971505c77db23,0x0,0x1 +0x1,0x1,0x4e,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x22af99c52785193aa8920826c0d96380,0x0,0x1 +0x1,0x1,0x4f,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0xe8213976bbbab27922a2cd8c8fe4adeb,0x0,0x1 +0x1,0x1,0x50,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0xa6356a8a0caaec7d1a28661b990a20b,0x0,0x1 +0x1,0x1,0x51,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x217f227c48e2682613693d3afb8231e,0x0,0x1 +0x1,0x1,0x52,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x5641ef4d251e87484afef7cae876258,0x0,0x1 +0x1,0x1,0x53,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0xc199d8553a68a9408d2603bd9ff29c36,0x0,0x1 +0x1,0x1,0x54,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0xb9624a62e115247146d4643e8d4daf0,0x0,0x1 +0x1,0x1,0x55,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x7ff180000fcf9f02c84cc5692b2c0526,0x0,0x1 +0x1,0x1,0x56,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x1cb9908c06bf3099f1538277102b31e3,0x0,0x1 +0x1,0x1,0x57,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x1d022dc64770bc130df14daef72830e4,0x0,0x1 +0x1,0x1,0x58,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x2977858b214a3cb43fa4024976dd1675,0x0,0x1 +0x1,0x1,0x59,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x9b1bf5367e6318da3545e697b9931671,0x0,0x1 +0x1,0x1,0x5a,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x6fcfd4b9ca03fb145ff273e480efda3,0x0,0x1 +0x1,0x1,0x5b,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0xc8a7aef64882efcbd8920b4458e1ef3d,0x0,0x1 +0x1,0x1,0x5c,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x281508326108309778f9cdf9c39a4c4d,0x0,0x1 +0x1,0x1,0x5d,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0xc90a405c0cfbfd5d20fec4e47acce66f,0x0,0x1 +0x1,0x1,0x5e,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x10d24b6f0b87c1e3f78b80b967bac765,0x0,0x1 +0x1,0x1,0x5f,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x763f38c53a4377e9a97e2761758a92f1,0x0,0x1 +0x1,0x1,0x60,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x2,0x0,0x0,0x1 +0x1,0x1,0x61,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x2,0x1,0x0,0x1 +0x1,0x1,0x0,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x1,0x1,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x1,0x1,0x0 +0x1,0x1,0x2,0x1,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x3,0x1,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x4,0x1,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x5,0x1,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x6,0x1,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x7,0x1,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x8,0x1,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x9,0x1,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0xa,0x1,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0xb,0x1,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0xc,0x1,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0xd,0x1,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0xe,0x1,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0xf,0x1,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x10,0x1,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x11,0x1,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x12,0x1,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x13,0x1,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x14,0x1,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x15,0x1,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x16,0x1,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x17,0x1,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x18,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0xb9624a62e115247146d4643e8d4daf0,0x1,0x0 +0x1,0x1,0x19,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x7ff180000fcf9f02c84cc5692b2c0526,0x1,0x0 +0x1,0x1,0x1a,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x13aabde6da726f8fc6fcc33f7156267a,0x1,0x0 +0x1,0x1,0x1b,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x7a7f3ccb21010e7a2e2f3e67e154cc63,0x1,0x0 +0x1,0x1,0x1c,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0xe82be8514331e947408a3a27a54d580,0x1,0x0 +0x1,0x1,0x1d,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x9866db37d74db5abc7de8f0d3d0f7ee3,0x1,0x0 +0x1,0x1,0x1e,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0xf89c9a7bb2eb9418d2d89310306196d,0x1,0x0 +0x1,0x1,0x1f,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0xf1ae8d9de0173f3e1151487bb5157cd7,0x1,0x0 +0x1,0x1,0x20,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x10b30b9925aace81dcec2ccce77c3eea,0x1,0x0 +0x1,0x1,0x21,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0xa949c366d7cd71a6a6748bcdd996b762,0x1,0x0 +0x1,0x1,0x22,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x11497987c563ade267b3bdfcc9c04022,0x1,0x0 +0x1,0x1,0x23,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x3e25664c3bcdd28858b1daa7ac249034,0x1,0x0 +0x1,0x1,0x24,0x1,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x0,0x1,0x2,0x1d986c0862b80ece8d231a383cb73943,0x1,0x0 +0x1,0x1,0x25,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x3dbbc8770d85f0584f6dc86875624cea,0x1,0x0 +0x1,0x1,0x26,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x3c51f8072e2a8a07f6a06f5088e9ab2,0x1,0x0 +0x1,0x1,0x27,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0xdbc106c833cd19dffcb9e1073ec1805c,0x1,0x0 +0x1,0x1,0x28,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x24ef30331e45aacaa2c0db503198129d,0x1,0x0 +0x1,0x1,0x29,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x698da943542b3b26946e11a08dc6144,0x1,0x0 +0x1,0x1,0x2a,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x229bffeec7cae24f754f3353492e06b7,0x1,0x0 +0x1,0x1,0x2b,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x38b7714ed0c32e48e7afaf62a4efa110,0x1,0x0 +0x1,0x1,0x2c,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x10bc1cc6e37e745faa3ed918cc36edc9,0x1,0x0 +0x1,0x1,0x2d,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x21edc644688a0705476f795d39af8b66,0x1,0x0 +0x1,0x1,0x2e,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x2adcf726eec4f68995c3207f92aea375,0x1,0x0 +0x1,0x1,0x2f,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0xfcd13ed4fe7b43ad615735680a4485e7,0x1,0x0 +0x1,0x1,0x30,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x1f0e7e775eefc2a5672928b4efc2c508,0x1,0x0 +0x1,0x1,0x31,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0xd1b9522023a1105027220223481cad5e,0x1,0x0 +0x1,0x1,0x32,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x241401f805f060cf5e55b76d0a1d9703,0x1,0x0 +0x1,0x1,0x33,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x623d8250a84288f9a9d6b32e4a79ab25,0x1,0x0 +0x1,0x1,0x34,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x2aefa1de34a54b19496ac527550823fc,0x1,0x0 +0x1,0x1,0x35,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x4b742adbe4a5e836b5a4c3c601d721be,0x1,0x0 +0x1,0x1,0x36,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x2feeac4095267db703b602ff985fc423,0x1,0x0 +0x1,0x1,0x37,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x235e6c11ea98a28c6a34a72c6ee2ddc,0x1,0x0 +0x1,0x1,0x38,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x1d75dcc79d6ddd435182ca5de99635c0,0x1,0x0 +0x1,0x1,0x39,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x212f3e7e80bdfa698ac725005f8dae63,0x1,0x0 +0x1,0x1,0x3a,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x5aeef8c0490c8356ffdd4913155eb21,0x1,0x0 +0x1,0x1,0x3b,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0xd66a1367a4c8c3f6c041b4227c1bf352,0x1,0x0 +0x1,0x1,0x3c,0x1,0x0,0x0,0x1,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x1d986c0862b80ece8d231a383cb73943,0x0,0x1 +0x1,0x1,0x3d,0x1,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x3dbbc8770d85f0584f6dc86875624cea,0x0,0x1 +0x1,0x1,0x3e,0x1,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x3c51f8072e2a8a07f6a06f5088e9ab2,0x0,0x1 +0x1,0x1,0x3f,0x1,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0xdbc106c833cd19dffcb9e1073ec1805c,0x0,0x1 +0x1,0x1,0x40,0x1,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x24ef30331e45aacaa2c0db503198129d,0x0,0x1 +0x1,0x1,0x41,0x1,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x698da943542b3b26946e11a08dc6144,0x0,0x1 +0x1,0x1,0x42,0x1,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x229bffeec7cae24f754f3353492e06b7,0x0,0x1 +0x1,0x1,0x43,0x1,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x38b7714ed0c32e48e7afaf62a4efa110,0x0,0x1 +0x1,0x1,0x44,0x1,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x10bc1cc6e37e745faa3ed918cc36edc9,0x0,0x1 +0x1,0x1,0x45,0x1,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x21edc644688a0705476f795d39af8b66,0x0,0x1 +0x1,0x1,0x46,0x1,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x2adcf726eec4f68995c3207f92aea375,0x0,0x1 +0x1,0x1,0x47,0x1,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0xfcd13ed4fe7b43ad615735680a4485e7,0x0,0x1 +0x1,0x1,0x48,0x1,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x1f0e7e775eefc2a5672928b4efc2c508,0x0,0x1 +0x1,0x1,0x49,0x1,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0xd1b9522023a1105027220223481cad5e,0x0,0x1 +0x1,0x1,0x4a,0x1,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x241401f805f060cf5e55b76d0a1d9703,0x0,0x1 +0x1,0x1,0x4b,0x1,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x623d8250a84288f9a9d6b32e4a79ab25,0x0,0x1 +0x1,0x1,0x4c,0x1,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x2aefa1de34a54b19496ac527550823fc,0x0,0x1 +0x1,0x1,0x4d,0x1,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x4b742adbe4a5e836b5a4c3c601d721be,0x0,0x1 +0x1,0x1,0x4e,0x1,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x2feeac4095267db703b602ff985fc423,0x0,0x1 +0x1,0x1,0x4f,0x1,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x235e6c11ea98a28c6a34a72c6ee2ddc,0x0,0x1 +0x1,0x1,0x50,0x1,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x1d75dcc79d6ddd435182ca5de99635c0,0x0,0x1 +0x1,0x1,0x51,0x1,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x212f3e7e80bdfa698ac725005f8dae63,0x0,0x1 +0x1,0x1,0x52,0x1,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x5aeef8c0490c8356ffdd4913155eb21,0x0,0x1 +0x1,0x1,0x53,0x1,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0xd66a1367a4c8c3f6c041b4227c1bf352,0x0,0x1 +0x1,0x1,0x54,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0xb9624a62e115247146d4643e8d4daf0,0x0,0x1 +0x1,0x1,0x55,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x7ff180000fcf9f02c84cc5692b2c0526,0x0,0x1 +0x1,0x1,0x56,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x1cb9908c06bf3099f1538277102b31e3,0x0,0x1 +0x1,0x1,0x57,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x1d022dc64770bc130df14daef72830e4,0x0,0x1 +0x1,0x1,0x58,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0xe82be8514331e947408a3a27a54d580,0x0,0x1 +0x1,0x1,0x59,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x9866db37d74db5abc7de8f0d3d0f7ee3,0x0,0x1 +0x1,0x1,0x5a,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0xf89c9a7bb2eb9418d2d89310306196d,0x0,0x1 +0x1,0x1,0x5b,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0xf1ae8d9de0173f3e1151487bb5157cd7,0x0,0x1 +0x1,0x1,0x5c,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x10b30b9925aace81dcec2ccce77c3eea,0x0,0x1 +0x1,0x1,0x5d,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0xa949c366d7cd71a6a6748bcdd996b762,0x0,0x1 +0x1,0x1,0x5e,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x11497987c563ade267b3bdfcc9c04022,0x0,0x1 +0x1,0x1,0x5f,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x3e25664c3bcdd28858b1daa7ac249034,0x0,0x1 +0x1,0x1,0x60,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x2,0x0,0x0,0x1 +0x1,0x1,0x61,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x2,0x1,0x0,0x1 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 diff --git a/prover/zkevm/prover/ecpair/testdata/testdata_generator_manual_test.go b/prover/zkevm/prover/ecpair/testdata/testdata_generator_manual_test.go new file mode 100644 index 000000000..7f0eb91a3 --- /dev/null +++ b/prover/zkevm/prover/ecpair/testdata/testdata_generator_manual_test.go @@ -0,0 +1,765 @@ +package testdata + +import ( + "crypto/rand" + "fmt" + "math/big" + "testing" + + "github.com/consensys/gnark-crypto/ecc/bn254" + "github.com/consensys/gnark-crypto/ecc/bn254/fp" + "github.com/consensys/gnark-crypto/ecc/bn254/fr" + "github.com/consensys/gnark/test" +) + +func TestPairingCheckData(t *testing.T) { + t.Skip("skipping test, called manually when needed") + assert := test.NewAssert(t) + _, _, p, q := bn254.Generators() + + var u, v fr.Element + u.SetInt64(1234) + v.SetInt64(5678) + // u.SetRandom() + // v.SetRandom() + + p.ScalarMultiplication(&p, u.BigInt(new(big.Int))) + q.ScalarMultiplication(&q, v.BigInt(new(big.Int))) + + var p1, p2 bn254.G1Affine + var q1, q2 bn254.G2Affine + p1.Double(&p) + p2.Neg(&p) + q1.Set(&q) + q2.Double(&q) + + ok, err := bn254.PairingCheck([]bn254.G1Affine{p1, p2}, []bn254.G2Affine{q1, q2}) + assert.NoError(err) + assert.True(ok) + + px := p1.X.Bytes() + py := p1.Y.Bytes() + fmt.Printf("0x%x\n0x%x\n0x%x\n0x%x\n", px[0:16], px[16:32], py[0:16], py[16:32]) + qxre := q1.X.A0.Bytes() + qxim := q1.X.A1.Bytes() + qyre := q1.Y.A0.Bytes() + qyim := q1.Y.A1.Bytes() + fmt.Printf("0x%x\n0x%x\n0x%x\n0x%x\n0x%x\n0x%x\n0x%x\n0x%x\n", + qxre[0:16], qxre[16:32], qxim[0:16], qxim[16:32], qyre[0:16], qyre[16:32], qyim[0:16], qyim[16:32]) + + p2x := p2.X.Bytes() + p2y := p2.Y.Bytes() + fmt.Printf("0x%x\n0x%x\n0x%x\n0x%x\n", p2x[0:16], p2x[16:32], p2y[0:16], p2y[16:32]) + q2xre := q2.X.A0.Bytes() + q2xim := q2.X.A1.Bytes() + q2yre := q2.Y.A0.Bytes() + q2yim := q2.Y.A1.Bytes() + fmt.Printf("0x%x\n0x%x\n0x%x\n0x%x\n0x%x\n0x%x\n0x%x\n0x%x\n", + q2xre[0:16], q2xre[16:32], q2xim[0:16], q2xim[16:32], q2yre[0:16], q2yre[16:32], q2yim[0:16], q2yim[16:32]) +} + +func TestPairingFailingCheckData(t *testing.T) { + t.Skip("skipping test, called manually when needed") + assert := test.NewAssert(t) + var p2 bn254.G1Affine + var q2 bn254.G2Affine + _, _, p, q := bn254.Generators() + + var u, v fr.Element + u.SetInt64(6235) + v.SetInt64(76235) + // u.SetRandom() + // v.SetRandom() + + p.ScalarMultiplication(&p, big.NewInt(12390)) + q.ScalarMultiplication(&q, big.NewInt(12489)) + p2.ScalarMultiplicationBase(big.NewInt(79975)) + q2.ScalarMultiplicationBase(big.NewInt(48916)) + + ok, err := bn254.PairingCheck([]bn254.G1Affine{p, p2}, []bn254.G2Affine{q, q2}) + assert.NoError(err) + assert.False(ok) + + px := p.X.Bytes() + py := p.Y.Bytes() + fmt.Printf("0x%x\n0x%x\n0x%x\n0x%x\n", px[0:16], px[16:32], py[0:16], py[16:32]) + qxre := q.X.A0.Bytes() + qxim := q.X.A1.Bytes() + qyre := q.Y.A0.Bytes() + qyim := q.Y.A1.Bytes() + fmt.Printf("0x%x\n0x%x\n0x%x\n0x%x\n0x%x\n0x%x\n0x%x\n0x%x\n", + qxre[0:16], qxre[16:32], qxim[0:16], qxim[16:32], qyre[0:16], qyre[16:32], qyim[0:16], qyim[16:32]) + + p2x := p2.X.Bytes() + p2y := p2.Y.Bytes() + fmt.Printf("0x%x\n0x%x\n0x%x\n0x%x\n", p2x[0:16], p2x[16:32], p2y[0:16], p2y[16:32]) + q2xre := q2.X.A0.Bytes() + q2xim := q2.X.A1.Bytes() + q2yre := q2.Y.A0.Bytes() + q2yim := q2.Y.A1.Bytes() + fmt.Printf("0x%x\n0x%x\n0x%x\n0x%x\n0x%x\n0x%x\n0x%x\n0x%x\n", + q2xre[0:16], q2xre[16:32], q2xim[0:16], q2xim[16:32], q2yre[0:16], q2yre[16:32], q2yim[0:16], q2yim[16:32]) +} + +func TestAddData(t *testing.T) { + t.Skip("skipping test, called manually when needed") + for i := 0; i < 4; i++ { + var p, q bn254.G1Affine + s1, err := rand.Int(rand.Reader, fr.Modulus()) + if err != nil { + t.Fatal(err) + } + s2, err := rand.Int(rand.Reader, fr.Modulus()) + if err != nil { + t.Fatal(err) + } + // s1 = big.NewInt(0) + // s2 = big.NewInt(0) + p.ScalarMultiplicationBase(s1) + q.ScalarMultiplicationBase(s2) + var r bn254.G1Affine + r.Add(&p, &q) + + pxb := p.X.Bytes() + pyb := p.Y.Bytes() + qxb := q.X.Bytes() + qyb := q.Y.Bytes() + rxb := r.X.Bytes() + ryb := r.Y.Bytes() + fmt.Println(i) + fmt.Printf("PXHI=0x%x\nPXLO=0x%x\nPYHI=0x%x\nPYLO=0x%x\nQXHI=0x%x\nQXLO=0x%x\nQYHI=0x%x\nQYLO=0x%x\nQXHI=0x%x\nQXLO=0x%x\nRYHI=0x%x\nRYLO=0x%x\n", + pxb[0:16], pxb[16:32], + pyb[0:16], pyb[16:32], + qxb[0:16], qxb[16:32], + qyb[0:16], qyb[16:32], + rxb[0:16], rxb[16:32], + ryb[0:16], ryb[16:32], + ) + } +} + +// small points +// malformed +// large coordinates +// coordinates in range but not satisfying the curve equation +// well-formed +// just a few points of the C1 curve drawn at random +// large points +// malformed +// large coordinates +// small coordinates but not satisfying the curve equation +// small coordinates, satisfying the curve equation but not belonging to the G2 subgroup +// well-formed +// just a few points on G2 drawn at random + +func TestDataSmallMalformedLarge(t *testing.T) { + t.Skip("skipping test, called manually when needed") + fmt.Println("fp = ", fp.Modulus()) + _, _, p, _ := bn254.Generators() + // var px [32]byte + // p.X.BigInt(new(big.Int)).FillBytes(px[:]) + // pb := p.X.Bytes() + // if !bytes.Equal(pb[:], px[:]) { + // t.Fatal("failed to marshal point") + // } + + // bound 2^256-modulus + bound := new(big.Int).Lsh(big.NewInt(1), 256) + bound.Sub(bound, fp.Modulus()) + + var buf [32]byte + + // test 1, X large and Y in range + x, _ := rand.Int(rand.Reader, bound) + x.Add(x, fp.Modulus()) + y, _ := rand.Int(rand.Reader, fp.Modulus()) + fmt.Println("= X large and Y in range (not necessarily satisfying curve equation) =") + x.FillBytes(buf[:]) + fmt.Printf("X = 0x%x\n", buf[:]) + y.FillBytes(buf[:]) + fmt.Printf("Y = 0x%x\n", buf[:]) + + // test 2, X large and Y in range + x, _ = rand.Int(rand.Reader, fp.Modulus()) + y, _ = rand.Int(rand.Reader, bound) + y.Add(y, fp.Modulus()) + fmt.Println("= X in range and Y large (not necessarily satisfying curve equation) =") + x.FillBytes(buf[:]) + fmt.Printf("X = 0x%x\n", buf[:]) + y.FillBytes(buf[:]) + fmt.Printf("Y = 0x%x\n", buf[:]) + + // test 3, X large and Y large + x, _ = rand.Int(rand.Reader, bound) + x.Add(x, fp.Modulus()) + y, _ = rand.Int(rand.Reader, bound) + y.Add(y, fp.Modulus()) + fmt.Println("= X large and Y large (not necessarily satisfying curve equation) =") + x.FillBytes(buf[:]) + fmt.Printf("X = 0x%x\n", buf[:]) + y.FillBytes(buf[:]) + fmt.Printf("Y = 0x%x\n", buf[:]) + + // test 4 - test 1 but satisfying curve equation + s, _ := rand.Int(rand.Reader, fr.Modulus()) + p.ScalarMultiplicationBase(s) + px := p.X.BigInt(new(big.Int)) + px.Add(px, fp.Modulus()) + fmt.Println("= X large and Y in range (satisfying curve equation) =") + px.FillBytes(buf[:]) + fmt.Printf("X = 0x%x\n", buf[:]) + p.Y.BigInt(new(big.Int)).FillBytes(buf[:]) + fmt.Printf("Y = 0x%x\n", buf[:]) + + // test 5 - test 2 but satisfying curve equation + s, _ = rand.Int(rand.Reader, fr.Modulus()) + p.ScalarMultiplicationBase(s) + py := p.X.BigInt(new(big.Int)) + py.Add(py, fp.Modulus()) + fmt.Println("= X in range and Y large (satisfying curve equation) =") + p.X.BigInt(new(big.Int)).FillBytes(buf[:]) + fmt.Printf("X = 0x%x\n", buf[:]) + py.FillBytes(buf[:]) + fmt.Printf("Y = 0x%x\n", buf[:]) + + // test 6 - test 3 but satisfying curve equation + s, _ = rand.Int(rand.Reader, fr.Modulus()) + p.ScalarMultiplicationBase(s) + px = p.X.BigInt(new(big.Int)) + px.Add(px, fp.Modulus()) + py = p.Y.BigInt(new(big.Int)) + py.Add(py, fp.Modulus()) + fmt.Println("= X large and Y large (satisfying curve equation) =") + px.FillBytes(buf[:]) + fmt.Printf("X = 0x%x\n", buf[:]) + py.FillBytes(buf[:]) + fmt.Printf("Y = 0x%x\n", buf[:]) +} + +func TestDataSmallMalformedNotCurve(t *testing.T) { + t.Skip("skipping test, called manually when needed") + px, _ := rand.Int(rand.Reader, fp.Modulus()) + py, _ := rand.Int(rand.Reader, fp.Modulus()) + var p bn254.G1Affine + p.X.SetBigInt(px) + p.Y.SetBigInt(py) + if p.IsOnCurve() { + t.Fatal("point is on curve") + } + fmt.Println("= X and Y in range but not satisfying curve equation =") + var buf [32]byte + px.FillBytes(buf[:]) + fmt.Printf("X = 0x%x\n", buf[:]) + py.FillBytes(buf[:]) + fmt.Printf("Y = 0x%x\n", buf[:]) +} + +func TestDataSmallWell(t *testing.T) { + t.Skip("skipping test, called manually when needed") + for i := 0; i < 5; i++ { + var p bn254.G1Affine + s, _ := rand.Int(rand.Reader, fr.Modulus()) + p.ScalarMultiplicationBase(s) + fmt.Println("= random point in G1 =") + var buf [32]byte + p.X.BigInt(new(big.Int)).FillBytes(buf[:]) + fmt.Printf("X = 0x%x\n", buf[:]) + p.Y.BigInt(new(big.Int)).FillBytes(buf[:]) + fmt.Printf("Y = 0x%x\n", buf[:]) + } +} + +func TestDataLargeMalformedLarge(t *testing.T) { + t.Skip("skipping test, called manually when needed") + // bound 2^256-modulus + bound := new(big.Int).Lsh(big.NewInt(1), 256) + bound.Sub(bound, fp.Modulus()) + + var buf [32]byte + + // test 1, XA large, XB in range, YA in range, YB in range + xa, _ := rand.Int(rand.Reader, bound) + xa.Add(xa, fp.Modulus()) + xb, _ := rand.Int(rand.Reader, fp.Modulus()) + ya, _ := rand.Int(rand.Reader, fp.Modulus()) + yb, _ := rand.Int(rand.Reader, fp.Modulus()) + var q bn254.G2Affine + q.X.A0.SetBigInt(xa) + q.X.A1.SetBigInt(xb) + q.Y.A0.SetBigInt(ya) + q.Y.A1.SetBigInt(yb) + if q.IsOnCurve() { + t.Fatal("point is on curve") + } + fmt.Println("= XA large, XB in range, YA in range, YB in range =") + xa.FillBytes(buf[:]) + fmt.Printf("XA = 0x%x\n", buf[:]) + xb.FillBytes(buf[:]) + fmt.Printf("XB = 0x%x\n", buf[:]) + ya.FillBytes(buf[:]) + fmt.Printf("YA = 0x%x\n", buf[:]) + yb.FillBytes(buf[:]) + fmt.Printf("YB = 0x%x\n", buf[:]) + + // test 2, XA in range, XB large, YA in range, YB in range + xa, _ = rand.Int(rand.Reader, fp.Modulus()) + xb, _ = rand.Int(rand.Reader, bound) + xb.Add(xb, fp.Modulus()) + ya, _ = rand.Int(rand.Reader, fp.Modulus()) + yb, _ = rand.Int(rand.Reader, fp.Modulus()) + q.X.A0.SetBigInt(xa) + q.X.A1.SetBigInt(xb) + q.Y.A0.SetBigInt(ya) + q.Y.A1.SetBigInt(yb) + if q.IsOnCurve() { + t.Fatal("point is on curve") + } + fmt.Println("= XA in range, XB large, YA in range, YB in range =") + xa.FillBytes(buf[:]) + fmt.Printf("XA = 0x%x\n", buf[:]) + xb.FillBytes(buf[:]) + fmt.Printf("XB = 0x%x\n", buf[:]) + ya.FillBytes(buf[:]) + fmt.Printf("YA = 0x%x\n", buf[:]) + yb.FillBytes(buf[:]) + fmt.Printf("YB = 0x%x\n", buf[:]) + + // test 3, XA in range, XB in range, YA large, YB in range + xa, _ = rand.Int(rand.Reader, fp.Modulus()) + xb, _ = rand.Int(rand.Reader, fp.Modulus()) + ya, _ = rand.Int(rand.Reader, bound) + ya.Add(ya, fp.Modulus()) + yb, _ = rand.Int(rand.Reader, fp.Modulus()) + q.X.A0.SetBigInt(xa) + q.X.A1.SetBigInt(xb) + q.Y.A0.SetBigInt(ya) + q.Y.A1.SetBigInt(yb) + if q.IsOnCurve() { + t.Fatal("point is on curve") + } + fmt.Println("= XA in range, XB in range, YA large, YB in range =") + xa.FillBytes(buf[:]) + fmt.Printf("XA = 0x%x\n", buf[:]) + xb.FillBytes(buf[:]) + fmt.Printf("XB = 0x%x\n", buf[:]) + ya.FillBytes(buf[:]) + fmt.Printf("YA = 0x%x\n", buf[:]) + yb.FillBytes(buf[:]) + fmt.Printf("YB = 0x%x\n", buf[:]) + + // test 4, XA in range, XB in range, YA in range, YB large + xa, _ = rand.Int(rand.Reader, fp.Modulus()) + xb, _ = rand.Int(rand.Reader, fp.Modulus()) + ya, _ = rand.Int(rand.Reader, fp.Modulus()) + yb, _ = rand.Int(rand.Reader, bound) + yb.Add(yb, fp.Modulus()) + q.X.A0.SetBigInt(xa) + q.X.A1.SetBigInt(xb) + q.Y.A0.SetBigInt(ya) + q.Y.A1.SetBigInt(yb) + if q.IsOnCurve() { + t.Fatal("point is on curve") + } + fmt.Println("= XA in range, XB in range, YA in range, YB large =") + xa.FillBytes(buf[:]) + fmt.Printf("XA = 0x%x\n", buf[:]) + xb.FillBytes(buf[:]) + fmt.Printf("XB = 0x%x\n", buf[:]) + ya.FillBytes(buf[:]) + fmt.Printf("YA = 0x%x\n", buf[:]) + yb.FillBytes(buf[:]) + fmt.Printf("YB = 0x%x\n", buf[:]) + + // test 5, point in subgroup, but overflowing + s, _ := rand.Int(rand.Reader, fr.Modulus()) + q.ScalarMultiplicationBase(s) + xa = q.X.A0.BigInt(new(big.Int)) + xa.Add(xa, fp.Modulus()) + xb = q.X.A1.BigInt(new(big.Int)) + xb.Add(xb, fp.Modulus()) + ya = q.Y.A0.BigInt(new(big.Int)) + ya.Add(ya, fp.Modulus()) + yb = q.Y.A1.BigInt(new(big.Int)) + yb.Add(yb, fp.Modulus()) + q.X.A0.SetBigInt(xa) + q.X.A1.SetBigInt(xb) + q.Y.A0.SetBigInt(ya) + q.Y.A1.SetBigInt(yb) + if !q.IsOnCurve() { + t.Fatal("point is on curve") + } + fmt.Println("= point in subgroup, but overflowing =") + xa.FillBytes(buf[:]) + fmt.Printf("XA = 0x%x\n", buf[:]) + xb.FillBytes(buf[:]) + fmt.Printf("XB = 0x%x\n", buf[:]) + ya.FillBytes(buf[:]) + fmt.Printf("YA = 0x%x\n", buf[:]) + yb.FillBytes(buf[:]) + fmt.Printf("YB = 0x%x\n", buf[:]) +} + +func TestDataLargeMalformedNotCurve(t *testing.T) { + t.Skip("skipping test, called manually when needed") + var q bn254.G2Affine + var buf [32]byte + xa, _ := rand.Int(rand.Reader, fp.Modulus()) + xb, _ := rand.Int(rand.Reader, fp.Modulus()) + ya, _ := rand.Int(rand.Reader, fp.Modulus()) + yb, _ := rand.Int(rand.Reader, fp.Modulus()) + yb.Add(yb, fp.Modulus()) + q.X.A0.SetBigInt(xa) + q.X.A1.SetBigInt(xb) + q.Y.A0.SetBigInt(ya) + q.Y.A1.SetBigInt(yb) + if q.IsOnCurve() { + t.Fatal("point is on curve") + } + fmt.Println("= point not on curve =") + xa.FillBytes(buf[:]) + fmt.Printf("XA = 0x%x\n", buf[:]) + xb.FillBytes(buf[:]) + fmt.Printf("XB = 0x%x\n", buf[:]) + ya.FillBytes(buf[:]) + fmt.Printf("YA = 0x%x\n", buf[:]) + yb.FillBytes(buf[:]) + fmt.Printf("YB = 0x%x\n", buf[:]) +} + +func TestDataLargeMalformedNotSubgroup(t *testing.T) { + t.Skip("skipping test, called manually when needed") + var x, right, left, tmp, z, ZZ bn254.E2 + for { + xa, _ := rand.Int(rand.Reader, fp.Modulus()) + xb, _ := rand.Int(rand.Reader, fp.Modulus()) + x.A0.SetBigInt(xa) + x.A1.SetBigInt(xb) + za, _ := rand.Int(rand.Reader, fp.Modulus()) + zb, _ := rand.Int(rand.Reader, fp.Modulus()) + z.A0.SetBigInt(za) + z.A1.SetBigInt(zb) + right.Square(&x).Mul(&right, &x) + ZZ.Square(&z) + tmp.Square(&ZZ).Mul(&tmp, &ZZ) + tmp.MulBybTwistCurveCoeff(&tmp) + right.Add(&right, &tmp) + if right.Legendre() == 1 { + break + } + } + left.Sqrt(&right) + QJac := bn254.G2Jac{ + X: x, + Y: left, + Z: z, + } + if !QJac.IsOnCurve() { + t.Fatal("point is not on curve Jac") + } + var q bn254.G2Affine + q.FromJacobian(&QJac) + if !q.IsOnCurve() { + t.Fatal("point is not on curve") + } + if q.IsInSubGroup() { + t.Fatal("point is in subgroup") + } + + var buf [32]byte + fmt.Println("= point not in subgroup but on curve =") + q.X.A0.BigInt(new(big.Int)).FillBytes(buf[:]) + fmt.Printf("XA = 0x%x\n", buf[:]) + q.X.A1.BigInt(new(big.Int)).FillBytes(buf[:]) + fmt.Printf("XB = 0x%x\n", buf[:]) + q.Y.A0.BigInt(new(big.Int)).FillBytes(buf[:]) + fmt.Printf("YA = 0x%x\n", buf[:]) + q.Y.A1.BigInt(new(big.Int)).FillBytes(buf[:]) + fmt.Printf("YB = 0x%x\n", buf[:]) +} + +func TestDataLargeWell(t *testing.T) { + t.Skip("skipping test, called manually when needed") + for i := 0; i < 5; i++ { + var q bn254.G2Affine + s, _ := rand.Int(rand.Reader, fr.Modulus()) + q.ScalarMultiplicationBase(s) + fmt.Println("= random point in G2 =") + var buf [32]byte + q.X.A0.BigInt(new(big.Int)).FillBytes(buf[:]) + fmt.Printf("XA = 0x%x\n", buf[:]) + q.X.A1.BigInt(new(big.Int)).FillBytes(buf[:]) + fmt.Printf("XB = 0x%x\n", buf[:]) + q.Y.A0.BigInt(new(big.Int)).FillBytes(buf[:]) + fmt.Printf("YA = 0x%x\n", buf[:]) + q.Y.A1.BigInt(new(big.Int)).FillBytes(buf[:]) + fmt.Printf("YB = 0x%x\n", buf[:]) + } +} + +func TestDataValidPairing(t *testing.T) { + t.Skip("skipping test, called manually when needed") + assert := test.NewAssert(t) + // pairing where result is 1. Two pairs of inputs + + // sp1 * sq1 + sp2 * sq2 == 0 + // sq2 = (-sp1 * sq1) / sp2 + var p1, p2 bn254.G1Affine + var q1, q2 bn254.G2Affine + sp1, _ := rand.Int(rand.Reader, fr.Modulus()) + sp2, _ := rand.Int(rand.Reader, fr.Modulus()) + sq1, _ := rand.Int(rand.Reader, fr.Modulus()) + tmp := new(big.Int) + tmp.ModInverse(sp2, fr.Modulus()) + tmp.Mul(tmp, sp1) + tmp.Mul(tmp, sq1) + tmp.Neg(tmp) + sq2 := new(big.Int).Mod(tmp, fr.Modulus()) + + p1.ScalarMultiplicationBase(sp1) + p2.ScalarMultiplicationBase(sp2) + q1.ScalarMultiplicationBase(sq1) + q2.ScalarMultiplicationBase(sq2) + ok, err := bn254.PairingCheck([]bn254.G1Affine{p1, p2}, []bn254.G2Affine{q1, q2}) + assert.NoError(err) + assert.True(ok) + fmt.Println("= double successful pairing =") + printP(p1) + printQ(q1) + fmt.Println() + printP(p2) + printQ(q2) + + // pairing where result is 1. Three pairs of inputs + // e(a, 2b) * e(2a, 2b) * e(-2a, 3b) == 1 + // 2 + 4 - 6 == 0 + var p3 bn254.G1Affine + var q3 bn254.G2Affine + sq2, _ = rand.Int(rand.Reader, fr.Modulus()) + sp3, _ := rand.Int(rand.Reader, fr.Modulus()) + n := new(big.Int) + n.Add(n, new(big.Int).Mul(sp1, sq1)) + n.Add(n, new(big.Int).Mul(sp2, sq2)) + tmp.ModInverse(sp3, fr.Modulus()) + tmp.Mul(tmp, n) + tmp.Neg(tmp) + sq3 := new(big.Int).Mod(tmp, fr.Modulus()) + + p1.ScalarMultiplicationBase(sp1) + p2.ScalarMultiplicationBase(sp2) + p3.ScalarMultiplicationBase(sp3) + q1.ScalarMultiplicationBase(sq1) + q2.ScalarMultiplicationBase(sq2) + q3.ScalarMultiplicationBase(sq3) + ok, err = bn254.PairingCheck([]bn254.G1Affine{p1, p2, p3}, []bn254.G2Affine{q1, q2, q3}) + assert.NoError(err) + assert.True(ok) + fmt.Print("\n\n") + fmt.Println("= triple successful pairing =") + printP(p1) + printQ(q1) + fmt.Println() + printP(p2) + printQ(q2) + fmt.Println() + printP(p3) + printQ(q3) + + printPLimbs(p1) + printQLimbs(q1) + printPLimbs(p2) + printQLimbs(q2) + printPLimbs(p3) + printQLimbs(q3) + + // pairing where result is 1. Four pairs of inputs + // e(a, 2b) * e(3a, b) * e(a, 5b) * e(-2a, 5b) == 1 + // 2 + 3 + 5 - 10 == 0 + var p4 bn254.G1Affine + var q4 bn254.G2Affine + sq3, _ = rand.Int(rand.Reader, fr.Modulus()) + sp4, _ := rand.Int(rand.Reader, fr.Modulus()) + n = new(big.Int) + n.Add(n, new(big.Int).Mul(sp1, sq1)) + n.Add(n, new(big.Int).Mul(sp2, sq2)) + n.Add(n, new(big.Int).Mul(sp3, sq3)) + tmp.ModInverse(sp4, fr.Modulus()) + tmp.Mul(tmp, n) + tmp.Neg(tmp) + sq4 := new(big.Int).Mod(tmp, fr.Modulus()) + + p1.ScalarMultiplicationBase(sp1) + p2.ScalarMultiplicationBase(sp2) + p3.ScalarMultiplicationBase(sp3) + p4.ScalarMultiplicationBase(sp4) + q1.ScalarMultiplicationBase(sq1) + q2.ScalarMultiplicationBase(sq2) + q3.ScalarMultiplicationBase(sq3) + q4.ScalarMultiplicationBase(sq4) + ok, err = bn254.PairingCheck([]bn254.G1Affine{p1, p2, p3, p4}, []bn254.G2Affine{q1, q2, q3, q4}) + assert.NoError(err) + assert.True(ok) + fmt.Print("\n\n") + fmt.Println("= quadruple successful pairing =") + printP(p1) + printQ(q1) + fmt.Println() + printP(p2) + printQ(q2) + fmt.Println() + printP(p3) + printQ(q3) + fmt.Println() + printP(p4) + printQ(q4) +} + +func TestG2TestData(t *testing.T) { + t.Skip("skipping test, called manually when needed") + assert := test.NewAssert(t) + // test for a point not on the curve + var Q bn254.G2Affine + _, err := Q.X.A0.SetString("0x119606e6d3ea97cea4eff54433f5c7dbc026b8d0670ddfbe6441e31225028d31") + assert.NoError(err) + _, err = Q.X.A1.SetString("0x1d3df5be6084324da6333a6ad1367091ca9fbceb70179ec484543a58b8cb5d63") + assert.NoError(err) + _, err = Q.Y.A0.SetString("0x1b9a36ea373fe2c5b713557042ce6deb2907d34e12be595f9bbe84c144de86ef") + assert.NoError(err) + _, err = Q.Y.A1.SetString("0x49fe60975e8c78b7b31a6ed16a338ac8b28cf6a065cfd2ca47e9402882518ba0") + assert.NoError(err) + assert.False(Q.IsOnCurve()) + printQLimbs(Q) + + // test for a point on curve not in G2 + _, err = Q.X.A0.SetString("0x07192b9fd0e2a32e3e1caa8e59462b757326d48f641924e6a1d00d66478913eb") + assert.NoError(err) + _, err = Q.X.A1.SetString("0x15ce93f1b1c4946dd6cfbb3d287d9c9a1cdedb264bda7aada0844416d8a47a63") + assert.NoError(err) + _, err = Q.Y.A0.SetString("0x0fa65a9b48ba018361ed081e3b9e958451de5d9e8ae0bd251833ebb4b2fafc96") + assert.NoError(err) + _, err = Q.Y.A1.SetString("0x06e1f5e20f68f6dfa8a91a3bea048df66d9eaf56cc7f11215401f7e05027e0c6") + assert.NoError(err) + assert.True(Q.IsOnCurve()) + assert.False(Q.IsInSubGroup()) + printQLimbs(Q) + + // test for a point in G2 + Q.ScalarMultiplicationBase(big.NewInt(5678)) + printQLimbs(Q) +} + +func TestDummyMillerLoopData(t *testing.T) { + t.Skip("skipping test, called manually when needed") + assert := test.NewAssert(t) + _, _, p, q := bn254.Generators() + lines := bn254.PrecomputeLines(q) + mlres, err := bn254.MillerLoopFixedQ( + []bn254.G1Affine{p}, + [][2][len(bn254.LoopCounter)]bn254.LineEvaluationAff{lines}, + ) + assert.NoError(err) + var one bn254.GT + one.SetOne() + printTLimbs(one) + fmt.Println() + printPLimbs(p) + fmt.Println() + printQLimbs(q) + fmt.Println() + printTLimbs(mlres) +} + +func TestDummyMillerLoopFinalExpData(t *testing.T) { + t.Skip("skipping test, called manually when needed") + assert := test.NewAssert(t) + _, _, p, q := bn254.Generators() + var negP bn254.G1Affine + negP.ScalarMultiplicationBase(big.NewInt(-1)) + lines := bn254.PrecomputeLines(q) + mlres, err := bn254.MillerLoopFixedQ( + []bn254.G1Affine{negP}, + [][2][len(bn254.LoopCounter)]bn254.LineEvaluationAff{lines}, + ) + printTLimbs(mlres) + assert.NoError(err) + + mlres2, err := bn254.MillerLoopFixedQ( + []bn254.G1Affine{p}, + [][2][len(bn254.LoopCounter)]bn254.LineEvaluationAff{lines}, + ) + assert.NoError(err) + mlres.Mul(&mlres, &mlres2) + res := bn254.FinalExponentiation(&mlres) + assert.True(res.IsOne()) + assert.NoError(err) + // var one bn254.GT + fmt.Println() + printPLimbs(p) + fmt.Println() + printQLimbs(q) + // fmt.Println() + // printTLimbs(mlres) +} + +func TestDummyG2CheckData(t *testing.T) { + t.Skip("skipping test, called manually when needed") + assert := test.NewAssert(t) + _, _, _, q := bn254.Generators() + ok := q.IsInSubGroup() + assert.True(ok) + printQLimbs(q) +} + +func printP(P bn254.G1Affine) { + var buf [32]byte + P.X.BigInt(new(big.Int)).FillBytes(buf[:]) + fmt.Printf("Ax = 0x%x\n", buf[:]) + P.Y.BigInt(new(big.Int)).FillBytes(buf[:]) + fmt.Printf("Ay = 0x%x\n", buf[:]) +} + +func printQ(Q bn254.G2Affine) { + var buf [32]byte + Q.X.A0.BigInt(new(big.Int)).FillBytes(buf[:]) + fmt.Printf("BxRe = 0x%x\n", buf[:]) + Q.X.A1.BigInt(new(big.Int)).FillBytes(buf[:]) + fmt.Printf("BxIm = 0x%x\n", buf[:]) + Q.Y.A0.BigInt(new(big.Int)).FillBytes(buf[:]) + fmt.Printf("ByRe = 0x%x\n", buf[:]) + Q.Y.A1.BigInt(new(big.Int)).FillBytes(buf[:]) + fmt.Printf("ByIm = 0x%x\n", buf[:]) +} + +func printPLimbs(P bn254.G1Affine) { + px := P.X.Bytes() + py := P.Y.Bytes() + fmt.Printf("0x%x\n0x%x\n0x%x\n0x%x\n", px[0:16], px[16:32], py[0:16], py[16:32]) +} + +func printQLimbs(Q bn254.G2Affine) { + qxre := Q.X.A0.Bytes() + qxim := Q.X.A1.Bytes() + qyre := Q.Y.A0.Bytes() + qyim := Q.Y.A1.Bytes() + fmt.Printf("0x%x\n0x%x\n0x%x\n0x%x\n0x%x\n0x%x\n0x%x\n0x%x\n", + qxre[0:16], qxre[16:32], qxim[0:16], qxim[16:32], qyre[0:16], qyre[16:32], qyim[0:16], qyim[16:32]) +} + +func printTLimbs(T bn254.GT) { + for i, bb := range [][32]byte{ + T.C0.B0.A0.Bytes(), + T.C0.B0.A1.Bytes(), + T.C0.B1.A0.Bytes(), + T.C0.B1.A1.Bytes(), + T.C0.B2.A0.Bytes(), + T.C0.B2.A1.Bytes(), + T.C1.B0.A0.Bytes(), + T.C1.B0.A1.Bytes(), + T.C1.B1.A0.Bytes(), + T.C1.B1.A1.Bytes(), + T.C1.B2.A0.Bytes(), + T.C1.B2.A1.Bytes(), + } { + _ = i + fmt.Printf("0x%x\n0x%x\n", bb[0:16], bb[16:32]) + } +} diff --git a/prover/zkevm/prover/ecpair/testdata/testdata_generator_test.go b/prover/zkevm/prover/ecpair/testdata/testdata_generator_test.go new file mode 100644 index 000000000..483ddd902 --- /dev/null +++ b/prover/zkevm/prover/ecpair/testdata/testdata_generator_test.go @@ -0,0 +1,583 @@ +package testdata + +import ( + "crypto/rand" + "encoding/csv" + "fmt" + "math/big" + "os" + "strconv" + "testing" + + "github.com/consensys/gnark-crypto/ecc/bn254" + "github.com/consensys/gnark-crypto/ecc/bn254/fp" + "github.com/consensys/gnark-crypto/ecc/bn254/fr" +) + +type inputType int + +const ( + fullTrivial inputType = iota // (0, 0) + leftTrivialValid // (0, Q) + leftTrivialInvalid // (0, Q') where Q' is not in G2 + rightTrivialValid // (P, 0) + rightTrivialInvalid // (P', 0) where P' is not in G1 + nonTrivialLeftInvalid // (P, Q) where P is not in G1 + nonTrivialRightInvalid // (P, Q) where Q is not in G2 + fullInvalid // (P, Q) where P and Q not in G1 and G2 respectively + nonTrivial // (P, Q) +) + +var choices = []inputType{fullTrivial, leftTrivialValid, leftTrivialInvalid, rightTrivialValid, rightTrivialInvalid, nonTrivialLeftInvalid, nonTrivialRightInvalid, fullInvalid, nonTrivial} + +func (i inputType) String() string { + switch i { + case fullTrivial: + return "full-trivial" + case leftTrivialValid: + return "left-trivial-valid" + case leftTrivialInvalid: + return "left-trivial-invalid" + case rightTrivialValid: + return "right-trivial-valid" + case rightTrivialInvalid: + return "right-trivial-invalid" + case nonTrivialLeftInvalid: + return "non-trivial-left-invalid" + case nonTrivialRightInvalid: + return "non-trivial-right-invalid" + case fullInvalid: + return "full-invalid" + case nonTrivial: + return "non-trivial" + default: + panic("unknown") + } +} + +func generateG1Infinity() bn254.G1Affine { + var p bn254.G1Affine + p.SetInfinity() + return p +} + +func generateG2Infinity() bn254.G2Affine { + var q bn254.G2Affine + q.SetInfinity() + return q +} + +func generateG1Invalid() bn254.G1Affine { + var p bn254.G1Affine + for { + px, _ := rand.Int(rand.Reader, fp.Modulus()) + py, _ := rand.Int(rand.Reader, fp.Modulus()) + p.X.SetBigInt(px) + p.Y.SetBigInt(py) + if !p.IsOnCurve() { + return p + } + } +} + +func generateG2Invalid() bn254.G2Affine { + var x, right, left, tmp, z, ZZ bn254.E2 + for { + xa, _ := rand.Int(rand.Reader, fp.Modulus()) + xb, _ := rand.Int(rand.Reader, fp.Modulus()) + x.A0.SetBigInt(xa) + x.A1.SetBigInt(xb) + za, _ := rand.Int(rand.Reader, fp.Modulus()) + zb, _ := rand.Int(rand.Reader, fp.Modulus()) + z.A0.SetBigInt(za) + z.A1.SetBigInt(zb) + right.Square(&x).Mul(&right, &x) + ZZ.Square(&z) + tmp.Square(&ZZ).Mul(&tmp, &ZZ) + tmp.MulBybTwistCurveCoeff(&tmp) + right.Add(&right, &tmp) + if right.Legendre() != 1 { + continue + } + left.Sqrt(&right) + QJac := bn254.G2Jac{ + X: x, + Y: left, + Z: z, + } + if !QJac.IsOnCurve() { + panic("point is not on curve Jac") + } + var q bn254.G2Affine + q.FromJacobian(&QJac) + if !q.IsOnCurve() { + continue + } + if q.IsInSubGroup() { + continue + } + return q + } +} + +func generateG1Valid() bn254.G1Affine { + var p bn254.G1Affine + var s fr.Element + s.SetRandom() + p.ScalarMultiplicationBase(s.BigInt(new(big.Int))) + return p +} + +func generateG2Valid() bn254.G2Affine { + var q bn254.G2Affine + var s fr.Element + s.SetRandom() + q.ScalarMultiplicationBase(s.BigInt(new(big.Int))) + return q +} + +func (i inputType) generatePair() (generatedPair inputPair) { + // here the pairingResult return value indicates if this input pair is + // invalid, i.e. it makes the whole pairing check to fail + // + // the cancelMemberships indicates if we should cancel the membership checks + // for other inputs in the pairing check. This is usually when G1 point is + // invalid in which case we don't need to check other G2 points. + var ip inputPair + ip.inputType = i + switch i { + case fullTrivial: + ip.P = generateG1Infinity() + ip.Q = generateG2Infinity() + ip.ToPairingCircuit = false + ip.ToMembershipCircuit = false + ip.MembershipSuccess = true + return ip + case leftTrivialValid: + ip.P = generateG1Infinity() + ip.Q = generateG2Valid() + ip.ToPairingCircuit = false + ip.ToMembershipCircuit = true + ip.MembershipSuccess = true + return ip + case leftTrivialInvalid: + ip.P = generateG1Infinity() + ip.Q = generateG2Invalid() + ip.ToPairingCircuit = false + ip.ToMembershipCircuit = true + ip.MembershipSuccess = false + return ip + case rightTrivialValid: + ip.P = generateG1Valid() + ip.Q = generateG2Infinity() + ip.ToPairingCircuit = false + ip.ToMembershipCircuit = false + ip.MembershipSuccess = true + return ip + case rightTrivialInvalid: + ip.P = generateG1Invalid() + ip.Q = generateG2Infinity() + ip.ToPairingCircuit = false + ip.ToMembershipCircuit = false + ip.MembershipSuccess = false + return ip + case nonTrivialLeftInvalid: + ip.P = generateG1Invalid() + ip.Q = generateG2Valid() + ip.ToPairingCircuit = false + ip.ToMembershipCircuit = false + ip.MembershipSuccess = false + return ip + case nonTrivialRightInvalid: + ip.P = generateG1Valid() + ip.Q = generateG2Invalid() + ip.ToPairingCircuit = false + ip.ToMembershipCircuit = true + ip.MembershipSuccess = false + return ip + case fullInvalid: + ip.P = generateG1Invalid() + ip.Q = generateG2Invalid() + ip.ToPairingCircuit = false + ip.ToMembershipCircuit = false + ip.MembershipSuccess = false + return ip + case nonTrivial: + ip.P = generateG1Valid() + ip.Q = generateG2Valid() + ip.ToPairingCircuit = true + ip.ToMembershipCircuit = false + ip.MembershipSuccess = false + return ip + default: + panic("not handled") + } +} + +type inputs []inputType + +type inputPair struct { + P bn254.G1Affine + Q bn254.G2Affine + + ToPairingCircuit bool + ToMembershipCircuit bool + + MembershipSuccess bool + + inputType inputType +} + +type testCase struct { + inputPairs []inputPair + inputs inputs + result bool +} + +func (l inputs) nbNonTrivial() int { + count := 0 + for _, input := range l { + if input == nonTrivial { + count++ + } + } + return count +} + +func (l inputs) generateValidInputs() []inputPair { + nb := l.nbNonTrivial() + sp := make([]fr.Element, nb) + sq := make([]fr.Element, nb) + for i := 0; i < nb; i++ { + sp[i].SetRandom() + sq[i].SetRandom() + } + var acc, tmp fr.Element + for i := 0; i < nb-1; i++ { + tmp.Mul(&sp[i], &sq[i]) + acc.Add(&acc, &tmp) + } + acc.Neg(&acc) + sq[nb-1].Div(&acc, &sp[nb-1]) + + pairs := make([]inputPair, nb) + var Ps []bn254.G1Affine + var Qs []bn254.G2Affine + bi := new(big.Int) + for i := 0; i < nb; i++ { + pairs[i].P.ScalarMultiplicationBase(sp[i].BigInt(bi)) + pairs[i].Q.ScalarMultiplicationBase(sq[i].BigInt(bi)) + pairs[i].ToPairingCircuit = true + pairs[i].ToMembershipCircuit = false + pairs[i].inputType = nonTrivial + pairs[i].MembershipSuccess = true + // for sanity check + Ps = append(Ps, pairs[i].P) + Qs = append(Qs, pairs[i].Q) + } + // sanity check + ok, err := bn254.PairingCheck(Ps, Qs) + if err != nil { + panic(err) + } + if !ok { + panic("invalid pairing") + } + return pairs +} + +func (l inputs) generateInvalidInputs() []inputPair { + nb := l.nbNonTrivial() + var s fr.Element + pairs := make([]inputPair, nb) + for i := 0; i < nb; i++ { + s.SetRandom() + pairs[i].P.ScalarMultiplicationBase(s.BigInt(new(big.Int))) + s.SetRandom() + pairs[i].Q.ScalarMultiplicationBase(s.BigInt(new(big.Int))) + pairs[i].ToPairingCircuit = true + pairs[i].ToMembershipCircuit = false + pairs[i].inputType = nonTrivial + pairs[i].MembershipSuccess = true + } + return pairs +} + +func (l inputs) generateTestCase() []testCase { + // count how many instances of what we have + counts := make(map[inputType]int) + for _, input := range l { + counts[input]++ + } + pairs := make([]inputPair, len(l)) + // if there is any invalid G1 point, we don't need to run anything + if counts[rightTrivialInvalid] > 0 || counts[nonTrivialLeftInvalid] > 0 || counts[fullInvalid] > 0 { + for i, input := range l { + pairs[i] = input.generatePair() + pairs[i].ToPairingCircuit = false + pairs[i].ToMembershipCircuit = false + pairs[i].MembershipSuccess = false + } + return []testCase{{inputPairs: pairs, result: false, inputs: l}} + } + // if there is any invalid G2 point, we only need to run membership check for that point + if counts[leftTrivialInvalid] > 0 || counts[nonTrivialRightInvalid] > 0 { + isFirstInvalid := true + for i, input := range l { + pairs[i] = input.generatePair() + pairs[i].ToPairingCircuit = false + if input == leftTrivialInvalid || input == nonTrivialRightInvalid { + pairs[i].ToMembershipCircuit = true + pairs[i].MembershipSuccess = false + if isFirstInvalid { + isFirstInvalid = false + } else { + pairs[i].ToPairingCircuit = false + } + } else { + pairs[i].ToMembershipCircuit = false + } + } + return []testCase{{inputPairs: pairs, result: false, inputs: l}} + } + // if for all points G2 are 0, we don't need to run anything + if counts[rightTrivialValid] == len(l) { + for i, input := range l { + pairs[i] = input.generatePair() + } + return []testCase{{inputPairs: pairs, result: true, inputs: l}} + } + + if l.nbNonTrivial() == 0 { + // should be combination of fullTrivial and leftTrivialValid. Then the G2 points need to go to the membership circuit + for i, input := range l { + pairs[i] = input.generatePair() + } + return []testCase{{inputPairs: pairs, result: true, inputs: l}} + } + if l.nbNonTrivial() == 1 { + invalidInputs := l.generateInvalidInputs() + for i, input := range l { + if input == nonTrivial { + pairs[i] = invalidInputs[0] + } else { + pairs[i] = input.generatePair() + } + } + return []testCase{{inputPairs: pairs, result: false, inputs: l}} + } + if l.nbNonTrivial() > 1 { + validInputs := l.generateValidInputs() + invalidInputs := l.generateInvalidInputs() + validPairs := make([]inputPair, len(l)) + invalidPairs := make([]inputPair, len(l)) + for i, input := range l { + if input == nonTrivial { + validPairs[i] = validInputs[0] + invalidPairs[i] = invalidInputs[0] + validInputs = validInputs[1:] + invalidInputs = invalidInputs[1:] + } else { + validPairs[i] = input.generatePair() + invalidPairs[i] = input.generatePair() + } + } + return []testCase{{inputPairs: validPairs, result: true, inputs: l}, {inputPairs: invalidPairs, result: false, inputs: l}} + } + panic("unexpected 2") +} + +func (ip *inputPair) WriteCSV(w *csv.Writer, ecdataId, ecDataIndex, acc, total int) (newIndex int, err error) { + // split G1 and G2 into limbs + px := ip.P.X.Bytes() + py := ip.P.Y.Bytes() + qxre := ip.Q.X.A0.Bytes() + qxim := ip.Q.X.A1.Bytes() + qyre := ip.Q.Y.A0.Bytes() + qyim := ip.Q.Y.A1.Bytes() + + limbs := []string{ + fmt.Sprintf("0x%x", px[0:16]), + fmt.Sprintf("0x%x", px[16:32]), + fmt.Sprintf("0x%x", py[0:16]), + fmt.Sprintf("0x%x", py[16:32]), + fmt.Sprintf("0x%x", qxim[0:16]), + fmt.Sprintf("0x%x", qxim[16:32]), + fmt.Sprintf("0x%x", qxre[0:16]), + fmt.Sprintf("0x%x", qxre[16:32]), + fmt.Sprintf("0x%x", qyim[0:16]), + fmt.Sprintf("0x%x", qyim[16:32]), + fmt.Sprintf("0x%x", qyre[0:16]), + fmt.Sprintf("0x%x", qyre[16:32]), + } + records := make([][]string, len(limbs)) + var ( + inputPairSuccess = formatBoolAsInt(ip.MembershipSuccess) + ToPairingCircuit = formatBoolAsInt(ip.ToPairingCircuit) + ) + for i, limb := range limbs { + isG2Part := i >= 4 + records[i] = []string{ + strconv.Itoa(ecdataId), + limb, + inputPairSuccess, + strconv.Itoa(ecDataIndex + i), + "1", + "0", + strconv.Itoa(acc), + strconv.Itoa(total), + ToPairingCircuit, + formatBoolAsInt(ip.ToMembershipCircuit && isG2Part), + } + } + if err := w.WriteAll(records); err != nil { + return ecDataIndex, err + } + return ecDataIndex + len(limbs), nil +} + +func (tc *testCase) WriteCSV(w *csv.Writer, ecdataId int) error { + var err error + var hasPairing bool + index := 0 + for i, ip := range tc.inputPairs { + if index, err = ip.WriteCSV(w, ecdataId, index, i+1, len(tc.inputPairs)); err != nil { + return err + } + hasPairing = hasPairing || ip.ToPairingCircuit + } + // write result + if err = w.Write([]string{ + strconv.Itoa(ecdataId), + "0", + formatBoolAsInt(tc.result), + "0", + "0", + "1", + "0", + strconv.Itoa(len(tc.inputPairs)), + formatBoolAsInt(hasPairing), + "0", + }); err != nil { + return err + } + if err = w.Write([]string{ + strconv.Itoa(ecdataId), + formatBoolAsInt(tc.result), + formatBoolAsInt(tc.result), + "1", + "0", + "1", + "0", + strconv.Itoa(len(tc.inputPairs)), + formatBoolAsInt(hasPairing), + "0", + }); err != nil { + return err + } + return nil +} + +func writeHeader(w *csv.Writer) error { + // record is + // - ECDATA_ID (int random increasing) + // - ECDATA_LIMB (int 128 bits) + // - ECDATA_SUCCESS_BIT (bool) + // - ECDATA_INDEX (int) + // - ECDATA_IS_DATA (bool) + // - ECDATA_IS_RES (bool) + // - ECDATA_ACC_PAIRINGS (int) + // - ECDATA_TOTAL_PAIRINGS (int) + // - ECDATA_CS_PAIRING (bool) + // - ECDATA_CS_G2_MEMBERSHIP (bool) + return w.Write([]string{ + "ECDATA_ID", + "ECDATA_LIMB", + "ECDATA_SUCCESS_BIT", + "ECDATA_INDEX", + "ECDATA_IS_DATA", + "ECDATA_IS_RES", + "ECDATA_ACC_PAIRINGS", + "ECDATA_TOTAL_PAIRINGS", + "ECDATA_CS_PAIRING", + "ECDATA_CS_G2_MEMBERSHIP", + }) +} + +func formatBoolAsInt(b bool) string { + if b { + return "1" + } + return "0" +} + +func generateTestCases(length int) []testCase { + // generate all possible combinations of inputs + // for each combination, generate all possible test cases + cartesianProduct := func(list []inputs) []inputs { + var ret []inputs + if len(list) == 0 { + for _, input := range choices { + ret = append(ret, inputs{input}) + } + return ret + } + for _, curr := range list { + for _, input := range choices { + newCurr := make(inputs, len(curr), len(curr)+1) + copy(newCurr, curr) + ret = append(ret, append(newCurr, input)) + } + } + return ret + } + cases := cartesianProduct(nil) + for i := 1; i < length; i++ { + cases = cartesianProduct(cases) + } + var allTestCases []testCase + for _, tc := range cases { + allTestCases = append(allTestCases, tc.generateTestCase()...) + } + return allTestCases +} + +func TestGenerateECPairTestCases(t *testing.T) { + t.Skip("long test, run manually when needed") + var generatedCases []testCase + for i := 1; i <= 5; i++ { + generatedCases = append(generatedCases, generateTestCases(i)...) + } + for i, tc := range generatedCases { + f, err := os.Create(fmt.Sprintf("generated/case-%06d_input.csv", i+1)) + if err != nil { + t.Fatal(err) + } + defer f.Close() + w := csv.NewWriter(f) + defer w.Flush() + if err := writeHeader(w); err != nil { + t.Fatal(err) + } + if err := tc.WriteCSV(w, i+1); err != nil { + t.Fatal(err) + } + } + fmt.Println(len(generatedCases)) +} + +func TestWriteTestCase(t *testing.T) { + // sanity test that nothing fails/panics etc + input := inputs{nonTrivial, nonTrivial, nonTrivial} + w := csv.NewWriter(os.Stdout) + if err := writeHeader(w); err != nil { + panic(err) + } + defer w.Flush() + testCases := input.generateTestCase() + for i, tc := range testCases { + if err := tc.WriteCSV(w, i); err != nil { + panic(err) + } + } +} diff --git a/prover/zkevm/zkevm.go b/prover/zkevm/zkevm.go index f3633e903..b17f5c229 100644 --- a/prover/zkevm/zkevm.go +++ b/prover/zkevm/zkevm.go @@ -7,6 +7,7 @@ import ( "github.com/consensys/linea-monorepo/prover/zkevm/arithmetization" "github.com/consensys/linea-monorepo/prover/zkevm/prover/ecarith" "github.com/consensys/linea-monorepo/prover/zkevm/prover/ecdsa" + "github.com/consensys/linea-monorepo/prover/zkevm/prover/ecpair" "github.com/consensys/linea-monorepo/prover/zkevm/prover/hash/keccak" "github.com/consensys/linea-monorepo/prover/zkevm/prover/hash/sha2" "github.com/consensys/linea-monorepo/prover/zkevm/prover/modexp" @@ -41,7 +42,7 @@ type ZkEvm struct { ecmul *ecarith.EcMul // ecpair is the module responsible for the proving the calls the ecpairing // precompile - // ecpair *ecpair.ECPair + ecpair *ecpair.ECPair // sha2 is the module responsible for doing the computation of the sha2 // precompile. sha2 *sha2.Sha2SingleProvider @@ -99,9 +100,9 @@ func newZkEVM(b *wizard.Builder, s *Settings) *ZkEvm { modexp = modexp.NewModuleZkEvm(comp, s.Modexp) ecadd = ecarith.NewEcAddZkEvm(comp, &s.Ecadd) ecmul = ecarith.NewEcMulZkEvm(comp, &s.Ecmul) - // ecpair = ecpair.NewECPairZkEvm(comp, &s.Ecpair) - sha2 = sha2.NewSha2ZkEvm(comp, s.Sha2) - publicInput = publicInput.NewPublicInputZkEVM(comp, &s.PublicInput, &stateManager.StateSummary) + ecpair = ecpair.NewECPairZkEvm(comp, &s.Ecpair) + sha2 = sha2.NewSha2ZkEvm(comp, s.Sha2) + publicInput = publicInput.NewPublicInputZkEVM(comp, &s.PublicInput, &stateManager.StateSummary) ) return &ZkEvm{ @@ -112,9 +113,9 @@ func newZkEVM(b *wizard.Builder, s *Settings) *ZkEvm { modexp: modexp, ecadd: ecadd, ecmul: ecmul, - // ecpair: ecpair, - sha2: sha2, - PublicInput: &publicInput, + ecpair: ecpair, + sha2: sha2, + PublicInput: &publicInput, } } @@ -135,7 +136,7 @@ func (z *ZkEvm) prove(input *Witness) (prover wizard.ProverStep) { z.modexp.Assign(run) z.ecadd.Assign(run) z.ecmul.Assign(run) - // z.ecpair.Assign(run) + z.ecpair.Assign(run) z.sha2.Run(run) z.PublicInput.Assign(run, input.L2BridgeAddress) }