Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package linea.staterecovery

import io.vertx.core.Vertx
import io.vertx.junit5.VertxExtension
import linea.contract.l1.LineaContractVersion
import linea.contract.l1.LineaRollupContractVersion
import linea.domain.BlockParameter
import linea.domain.RetryConfig
import linea.ethapi.EthLogsSearcherImpl
Expand Down Expand Up @@ -51,7 +51,7 @@ class LineaSubmissionEventsClientIntTest {
)

val rollupDeploymentFuture = ContractsManager.get()
.deployLineaRollup(numberOfOperators = 2, contractVersion = LineaContractVersion.V6)
.deployLineaRollup(numberOfOperators = 2, contractVersion = LineaRollupContractVersion.V6)
// load files from FS while smc deploy
aggregationsAndBlobs = loadBlobsAndAggregationsSortedAndGrouped(
blobsResponsesDir = "$testDataDir/compression/responses",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package linea.staterecovery

import io.vertx.core.Vertx
import io.vertx.junit5.VertxExtension
import linea.contract.l1.LineaContractVersion
import linea.contract.l1.LineaRollupContractVersion
import linea.domain.BlockNumberAndHash
import linea.domain.BlockParameter
import linea.domain.RetryConfig
Expand Down Expand Up @@ -76,7 +76,7 @@ class StateRecoveryAppWithFakeExecutionClientIntTest {
FakeStateManagerClientBasedOnBlobsRecords(blobRecords = aggregationsAndBlobs.flatMap { it.blobs })

val rollupDeploymentResult = ContractsManager.get()
.deployLineaRollup(numberOfOperators = 2, contractVersion = LineaContractVersion.V6).get()
.deployLineaRollup(numberOfOperators = 2, contractVersion = LineaRollupContractVersion.V6).get()

this.appConfigs = StateRecoveryApp.Config(
l1EarliestSearchBlock = BlockParameter.Tag.EARLIEST,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import build.linea.clients.StateManagerV1JsonRpcClient
import io.micrometer.core.instrument.simple.SimpleMeterRegistry
import io.vertx.core.Vertx
import io.vertx.junit5.VertxExtension
import linea.contract.l1.LineaContractVersion
import linea.contract.l1.LineaRollupContractVersion
import linea.log4j.configureLoggers
import linea.staterecovery.test.assertBesuAndShomeiRecoveredAsExpected
import linea.staterecovery.test.execCommandAndAssertSuccess
Expand Down Expand Up @@ -82,7 +82,7 @@ class StateRecoveryWithRealBesuAndStateManagerIntTest {
@Order(1)
fun `should recover status from genesis - seed data replay`() {
this.rollupDeploymentResult = ContractsManager.get()
.deployLineaRollup(numberOfOperators = 2, contractVersion = LineaContractVersion.V6)
.deployLineaRollup(numberOfOperators = 2, contractVersion = LineaRollupContractVersion.V6)
.get()
log.info("LineaRollup address={}", rollupDeploymentResult.contractAddress)
contractClientForBlobSubmission = rollupDeploymentResult.rollupOperatorClient
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package linea.staterecovery.datafetching

import io.vertx.core.Vertx
import io.vertx.junit5.VertxExtension
import linea.contract.l1.LineaContractVersion
import linea.contract.l1.LineaRollupContractVersion
import linea.domain.BlockParameter
import linea.domain.RetryConfig
import linea.log4j.configureLoggers
Expand Down Expand Up @@ -69,7 +69,7 @@ class SubmissionsFetchingTaskIntTest {
extraBlobsWithoutAggregation = 0,
)
val rollupDeploymentResult = ContractsManager.get()
.deployLineaRollup(numberOfOperators = 2, contractVersion = LineaContractVersion.V6).get()
.deployLineaRollup(numberOfOperators = 2, contractVersion = LineaRollupContractVersion.V6).get()

appClients = createAppClients(
vertx = vertx,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,12 @@ data class L1SubmissionConfig(
val fallbackGasPrice: FallbackGasPriceConfig,
val blob: BlobSubmissionConfig,
val aggregation: AggregationSubmissionConfig,
val dataSubmission: DataSubmission,
) : FeatureToggle {
enum class DataSubmission {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DataSubmission is not appropriate IMO

suggestions:

  • DataAvailability
  • DataStorageMode
  • L2DaType

@julien-marchand any inputs on this?

This will have impact on logic/proving once filly implemented

ROLLUP,
VALIDIUM,
}
override val disabled: Boolean
get() = blob.disabled && aggregation.disabled

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import linea.coordinator.config.v2.toml.decoders.BlockParameterDecoder
import linea.coordinator.config.v2.toml.decoders.BlockParameterNumberDecoder
import linea.coordinator.config.v2.toml.decoders.BlockParameterTagDecoder
import linea.coordinator.config.v2.toml.decoders.TomlByteArrayHexDecoder
import linea.coordinator.config.v2.toml.decoders.TomlDataSubmissionDecoder
import linea.coordinator.config.v2.toml.decoders.TomlKotlinDurationDecoder
import linea.coordinator.config.v2.toml.decoders.TomlSignerTypeDecoder
import org.apache.logging.log4j.Level
Expand All @@ -31,6 +32,7 @@ fun ConfigLoaderBuilder.addCoordinatorTomlDecoders(strict: Boolean): ConfigLoade
.addDecoder(TomlByteArrayHexDecoder())
.addDecoder(TomlKotlinDurationDecoder())
.addDecoder(TomlSignerTypeDecoder())
.addDecoder(TomlDataSubmissionDecoder())
.apply { if (strict) this.strict() }
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,28 @@ data class L1SubmissionConfigToml(
val fallbackGasPrice: FallbackGasPriceToml,
val blob: BlobSubmissionConfigToml,
val aggregation: AggregationSubmissionToml,
val dataSubmission: DataSubmission = DataSubmission.ROLLUP,
) {

enum class DataSubmission(val mame: String) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, name is an enum class attribute, I can either override name or have a different variable name. I just followed a similar enum that we use for TOML config SignerType

ROLLUP("rollup"),
VALIDIUM("validium"),
;

companion object {
fun valueOfIgnoreCase(name: String): DataSubmission {
return DataSubmission.entries.firstOrNull { it.name.equals(name, ignoreCase = true) }
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Unused property in DataSubmission enum

The DataSubmission enum defines a mame property but valueOfIgnoreCase uses it.name instead of it.mame for comparison. This is inconsistent with the SignerType enum pattern which uses it.mame. The defined property serves no purpose and creates dead code, breaking the established pattern in the codebase.

Fix in Cursor Fix in Web

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please address this. Also, I don't thing we need the name property...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok, I was just following what was done for a similar TOML config enum SignerType

?: throw IllegalArgumentException("Unknown data submission type: $name")
}
}
fun reified(): L1SubmissionConfig.DataSubmission {
return when (this) {
ROLLUP -> L1SubmissionConfig.DataSubmission.ROLLUP
VALIDIUM -> L1SubmissionConfig.DataSubmission.VALIDIUM
}
}
}

data class DynamicGasPriceCapToml(
val disabled: Boolean = false,
val gasPriceCapCalculation: GasPriceCapCalculationToml,
Expand Down Expand Up @@ -167,6 +187,7 @@ data class L1SubmissionConfigToml(
gas = this.aggregation.gas.reified(),
signer = this.aggregation.signer.reified(),
),
dataSubmission = this.dataSubmission.reified(),
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import com.sksamuel.hoplite.StringNode
import com.sksamuel.hoplite.decoder.Decoder
import com.sksamuel.hoplite.fp.invalid
import com.sksamuel.hoplite.fp.valid
import linea.coordinator.config.v2.toml.L1SubmissionConfigToml
import linea.coordinator.config.v2.toml.SignerConfigToml
import linea.kotlin.decodeHex
import kotlin.reflect.KType
Expand Down Expand Up @@ -81,3 +82,28 @@ class TomlSignerTypeDecoder : Decoder<SignerConfigToml.SignerType> {
return type.classifier == SignerConfigToml.SignerType::class
}
}

class TomlDataSubmissionDecoder : Decoder<L1SubmissionConfigToml.DataSubmission> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why do we need a specific decoder. Toml library shall handle that out for the box, no?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, i did not experiment with enum and toml library, I just followed a similar pattern we have for SignerType. You can notice the TomlSignerTypeDecoder just above this class.

override fun decode(
node: Node,
type: KType,
context: DecoderContext,
): ConfigResult<L1SubmissionConfigToml.DataSubmission> {
return when (node) {
is StringNode -> runCatching {
L1SubmissionConfigToml.DataSubmission.valueOfIgnoreCase(node.value.lowercase())
}.fold(
{ it.valid() },
{ ConfigFailure.DecodeError(node, type).invalid() },
)

else -> {
ConfigFailure.DecodeError(node, type).invalid()
}
}
}

override fun supports(type: KType): Boolean {
return type.classifier == L1SubmissionConfigToml.DataSubmission::class
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,15 @@ import io.vertx.core.Vertx
import io.vertx.core.http.HttpVersion
import io.vertx.core.net.PfxOptions
import io.vertx.ext.web.client.WebClientOptions
import linea.coordinator.config.v2.SignerConfig
import linea.kotlin.encodeHex
import linea.web3j.SmartContractErrors
import linea.web3j.transactionmanager.AsyncFriendlyTransactionManager
import net.consensys.linea.contract.l1.Web3JLineaRollupSmartContractClient
import net.consensys.linea.contract.l1.Web3JLineaValidiumSmartContractClient
import net.consensys.linea.httprest.client.VertxHttpRestClient
import net.consensys.zkevm.coordinator.clients.smartcontract.LineaRollupSmartContractClient
import net.consensys.zkevm.coordinator.clients.smartcontract.LineaValidiumSmartContractClient
import net.consensys.zkevm.ethereum.crypto.Web3SignerRestClient
import net.consensys.zkevm.ethereum.crypto.Web3SignerTxSignService
import net.consensys.zkevm.ethereum.signing.ECKeypairSignerAdapter
Expand All @@ -27,7 +30,7 @@ import javax.net.ssl.TrustManagerFactory

fun createTransactionManager(
vertx: Vertx,
signerConfig: linea.coordinator.config.v2.SignerConfig,
signerConfig: SignerConfig,
client: Web3j,
): AsyncFriendlyTransactionManager {
fun loadKeyAndTrustStoreFromFiles(
Expand Down Expand Up @@ -78,11 +81,11 @@ fun createTransactionManager(
}

val transactionSignService = when (signerConfig.type) {
linea.coordinator.config.v2.SignerConfig.SignerType.WEB3J -> {
SignerConfig.SignerType.WEB3J -> {
TxSignServiceImpl(Credentials.create(signerConfig.web3j!!.privateKey.encodeHex()))
}

linea.coordinator.config.v2.SignerConfig.SignerType.WEB3SIGNER -> {
SignerConfig.SignerType.WEB3SIGNER -> {
val web3SignerConfig = signerConfig.web3signer!!
val endpoint = web3SignerConfig.endpoint
val webClientOptions: WebClientOptions =
Expand Down Expand Up @@ -131,3 +134,21 @@ fun createLineaRollupContractClient(
useEthEstimateGas = useEthEstimateGas,
)
}

fun createLineaValidiumContractClient(
contractAddress: String,
transactionManager: AsyncFriendlyTransactionManager,
contractGasProvider: ContractGasProvider,
web3jClient: Web3j,
smartContractErrors: SmartContractErrors,
useEthEstimateGas: Boolean,
): LineaValidiumSmartContractClient {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this looks duplicated. Have you considered

fun createLineaContractClient(
  dataAvailabiltyType:  DataSubmission
  contractAddress: String,
  transactionManager: AsyncFriendlyTransactionManager,
  contractGasProvider: ContractGasProvider,
  web3jClient: Web3j,
  smartContractErrors: SmartContractErrors,
  useEthEstimateGas: Boolean,
):

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that is better.

return Web3JLineaValidiumSmartContractClient.load(
contractAddress = contractAddress,
web3j = web3jClient,
transactionManager = transactionManager,
contractGasProvider = contractGasProvider,
smartContractErrors = smartContractErrors,
useEthEstimateGas = useEthEstimateGas,
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import linea.contract.l1.LineaRollupSmartContractClientReadOnly
import linea.contract.l1.Web3JLineaRollupSmartContractClientReadOnly
import linea.coordinator.config.toJsonRpcRetry
import linea.coordinator.config.v2.CoordinatorConfig
import linea.coordinator.config.v2.L1SubmissionConfig
import linea.coordinator.config.v2.Type2StateProofManagerConfig
import linea.coordinator.config.v2.isDisabled
import linea.coordinator.config.v2.isEnabled
Expand Down Expand Up @@ -46,6 +47,7 @@ import net.consensys.zkevm.coordinator.app.conflation.ConflationApp
import net.consensys.zkevm.coordinator.app.conflation.ConflationAppHelper.resumeConflationFrom
import net.consensys.zkevm.coordinator.clients.ShomeiClient
import net.consensys.zkevm.coordinator.clients.smartcontract.LineaRollupSmartContractClient
import net.consensys.zkevm.coordinator.clients.smartcontract.LineaSmartContractClient
import net.consensys.zkevm.domain.BlobSubmittedEvent
import net.consensys.zkevm.domain.FinalizationSubmittedEvent
import net.consensys.zkevm.ethereum.coordination.EventDispatcher
Expand Down Expand Up @@ -294,7 +296,7 @@ class L1DependentApp(
lastFinalizedBlock,
).get()

private val lineaSmartContractClientForDataSubmission: LineaRollupSmartContractClient = run {
private val lineaSmartContractClientForDataSubmission: LineaSmartContractClient = run {
// The below gas provider will act as the primary gas provider if L1
// dynamic gas pricing is disabled and will act as a fallback gas provider
// if L1 dynamic gas pricing is enabled
Expand All @@ -313,20 +315,32 @@ class L1DependentApp(
rpcUrl = configs.l1Submission.blob.l1Endpoint.toString(),
log = LogManager.getLogger("clients.l1.eth.data-submission"),
)
createLineaRollupContractClient(
contractAddress = configs.protocol.l1.contractAddress,
transactionManager = createTransactionManager(
vertx,
signerConfig = configs.l1Submission.blob.signer,
client = l1Web3jClient,
),
contractGasProvider = primaryOrFallbackGasProvider,
web3jClient = l1Web3jClient,
smartContractErrors = smartContractErrors,
// eth_estimateGas would fail because we submit multiple blob tx
// and 2nd would fail with revert reason
useEthEstimateGas = false,
val transactionManager = createTransactionManager(
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Null pointer exception for Validium blob gas cap

The code force-unwraps maxFeePerBlobGasCap!! when creating gas providers for both ROLLUP and VALIDIUM modes. Since maxFeePerBlobGasCap is nullable and Validium doesn't use EIP-4844 blobs, this will throw a NullPointerException when running in Validium mode if the configuration doesn't provide this optional value. The gas provider creation should handle Validium differently or require the value only for ROLLUP mode.

Additional Locations (1)

Fix in Cursor Fix in Web

vertx,
signerConfig = configs.l1Submission.blob.signer,
client = l1Web3jClient,
)
when (configs.l1Submission.dataSubmission) {
L1SubmissionConfig.DataSubmission.ROLLUP -> createLineaRollupContractClient(
contractAddress = configs.protocol.l1.contractAddress,
transactionManager = transactionManager,
contractGasProvider = primaryOrFallbackGasProvider,
web3jClient = l1Web3jClient,
smartContractErrors = smartContractErrors,
// eth_estimateGas would fail because we submit multiple blob tx
// and 2nd would fail with revert reason
useEthEstimateGas = false,
)

L1SubmissionConfig.DataSubmission.VALIDIUM -> createLineaValidiumContractClient(
contractAddress = configs.protocol.l1.contractAddress,
transactionManager = transactionManager,
contractGasProvider = primaryOrFallbackGasProvider,
web3jClient = l1Web3jClient,
smartContractErrors = smartContractErrors,
useEthEstimateGas = false,
)
}
}

private val highestAcceptedBlobTracker = HighestULongTracker(lastProcessedBlockNumber).also {
Expand All @@ -340,7 +354,7 @@ class L1DependentApp(

private val alreadySubmittedBlobsFilter =
L1ShnarfBasedAlreadySubmittedBlobsFilter(
lineaRollup = lineaSmartContractClientForDataSubmission,
lineaSmartContractClientReadOnly = lineaSmartContractClientForDataSubmission,
acceptedBlobEndBlockNumberConsumer = { highestAcceptedBlobTracker(it) },
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ class L1SubmissionConfigParsingTest {
val toml = """
[l1-submission]
disabled = true
data-submission = "validium"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In our meeting with @julien-marchand we agreed on this config layout

[l1-submission.blob]
data-availability = "ROLLUP, PRIVIDIUM, VALIDIUM"

What's the motivation/rationale to:

  1. put it on upper level, l1-submission
  2. change the name to data-submission?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. I did not put under l1-submission.blob because validium also involves shnarf submission. So overall it is how data (shnarf and blobs) are available not just blobs.
  2. I forgot what name we had decided on, I will update it to data-availability.

[l1-submission.dynamic-gas-price-cap]
disabled = true
[l1-submission.dynamic-gas-price-cap.gas-price-cap-calculation]
Expand Down Expand Up @@ -118,6 +119,7 @@ class L1SubmissionConfigParsingTest {
val config =
L1SubmissionConfigToml(
disabled = true,
dataSubmission = L1SubmissionConfigToml.DataSubmission.VALIDIUM,
dynamicGasPriceCap = L1SubmissionConfigToml.DynamicGasPriceCapToml(
disabled = true,
gasPriceCapCalculation = L1SubmissionConfigToml.DynamicGasPriceCapToml.GasPriceCapCalculationToml(
Expand Down Expand Up @@ -377,6 +379,7 @@ class L1SubmissionConfigParsingTest {

@Test
fun `should parse l1 submission minimal config`() {
assertThat(parseConfig<WrapperConfig>(tomlMinimal).l1Submission).isEqualTo(configMinimal)
val config = parseConfig<WrapperConfig>(tomlMinimal)
assertThat(config.l1Submission).isEqualTo(configMinimal)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package net.consensys.linea.contract.l1

import build.linea.contract.ValidiumV1
import linea.web3j.transactionmanager.AsyncFriendlyTransactionManager
import net.consensys.linea.contract.Web3JContractAsyncHelper
import org.web3j.abi.datatypes.Function
import org.web3j.protocol.Web3j
import org.web3j.protocol.core.RemoteFunctionCall
import org.web3j.protocol.core.methods.response.TransactionReceipt
import org.web3j.tx.gas.ContractGasProvider
import java.math.BigInteger

internal class LineaValidiumEnhancedWrapper(
contractAddress: String,
web3j: Web3j,
transactionManager: AsyncFriendlyTransactionManager,
contractGasProvider: ContractGasProvider,
private val web3jContractHelper: Web3JContractAsyncHelper,
) : ValidiumV1(
contractAddress,
web3j,
transactionManager,
contractGasProvider,
) {
@Synchronized
override fun executeRemoteCallTransaction(
function: Function,
weiValue: BigInteger,
): RemoteFunctionCall<TransactionReceipt> = web3jContractHelper.executeRemoteCallTransaction(function, weiValue)

@Synchronized
override fun executeRemoteCallTransaction(
function: Function,
): RemoteFunctionCall<TransactionReceipt> = web3jContractHelper.executeRemoteCallTransaction(
function,
BigInteger.ZERO,
)
}
Loading
Loading