coordinator: support for smart contract v6 (#240)

* coordinator: support for smart contract v6
This commit is contained in:
Pedro Novais
2024-10-24 17:32:39 +01:00
committed by GitHub
parent 95732b4f0b
commit 24366fc9f1
15 changed files with 424 additions and 192 deletions

View File

@@ -80,6 +80,21 @@ deploy-linea-rollup:
LINEA_ROLLUP_GENESIS_TIMESTAMP=1683325137 \
npx hardhat deploy --no-compile --network zkevm_dev --tags PlonkVerifier,LineaRollupV5
deploy-linea-rollup-v6:
# WARNING: FOR LOCAL DEV ONLY - DO NOT REUSE THESE KEYS ELSEWHERE
cd contracts/; \
PRIVATE_KEY=$${DEPLOYMENT_PRIVATE_KEY:-0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80} \
BLOCKCHAIN_NODE=http:\\localhost:8445/ \
PLONKVERIFIER_NAME=IntegrationTestTrueVerifier \
LINEA_ROLLUP_INITIAL_STATE_ROOT_HASH=0x072ead6777750dc20232d1cee8dc9a395c2d350df4bbaa5096c6f59b214dcecd \
LINEA_ROLLUP_INITIAL_L2_BLOCK_NUMBER=0 \
LINEA_ROLLUP_SECURITY_COUNCIL=0x90F79bf6EB2c4f870365E785982E1f101E93b906 \
LINEA_ROLLUP_OPERATORS=$${LINEA_ROLLUP_OPERATORS:-0x70997970C51812dc3A010C7d01b50e0d17dc79C8,0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC} \
LINEA_ROLLUP_RATE_LIMIT_PERIOD=86400 \
LINEA_ROLLUP_RATE_LIMIT_AMOUNT=1000000000000000000000 \
LINEA_ROLLUP_GENESIS_TIMESTAMP=1683325137 \
npx hardhat deploy --no-compile --network zkevm_dev --tags PlonkVerifier,LineaRollup
deploy-l2messageservice:
# WARNING: FOR LOCAL DEV ONLY - DO NOT REUSE THESE KEYS ELSEWHERE
cd contracts/; \

View File

@@ -7,6 +7,7 @@ dependencies {
implementation project(':jvm-libs:linea:web3j-extensions')
api 'build.linea:l1-rollup-contract-client:0.0.1'
api 'build.linea:l2-message-service-contract-client:0.0.1'
implementation(project(':jvm-libs:linea:linea-contracts:l1-rollup'))
api ("org.web3j:core:${libs.versions.web3j.get()}") {
exclude group: 'org.slf4j', module: 'slf4j-nop'

View File

@@ -0,0 +1,153 @@
package net.consensys.linea.contract.l1
import build.linea.contract.LineaRollupV6
import net.consensys.toBigInteger
import net.consensys.zkevm.coordinator.clients.smartcontract.LineaContractVersion
import net.consensys.zkevm.domain.BlobRecord
import net.consensys.zkevm.domain.ProofToFinalize
import org.web3j.abi.TypeReference
import org.web3j.abi.datatypes.DynamicArray
import org.web3j.abi.datatypes.DynamicBytes
import org.web3j.abi.datatypes.Function
import org.web3j.abi.datatypes.Type
import org.web3j.abi.datatypes.generated.Bytes32
import org.web3j.abi.datatypes.generated.Uint256
import java.math.BigInteger
import java.util.Arrays
internal fun buildSubmitBlobsFunction(
version: LineaContractVersion,
blobs: List<BlobRecord>
): Function {
return when (version) {
LineaContractVersion.V5 -> buildSubmitBlobsFunction(blobs)
LineaContractVersion.V6 -> buildSubmitBlobsFunctionV6(blobs)
}
}
internal fun buildSubmitBlobsFunctionV6(
blobs: List<BlobRecord>
): Function {
val blobsSubmissionData = blobs.map { blob ->
val blobCompressionProof = blob.blobCompressionProof!!
// BlobSubmission(BigInteger dataEvaluationClaim, byte[] kzgCommitment, byte[] kzgProof,
// byte[] finalStateRootHash, byte[] snarkHash)
LineaRollupV6.BlobSubmission(
/*dataEvaluationClaim*/ BigInteger(blobCompressionProof.expectedY),
/*kzgCommitment*/ blobCompressionProof.commitment,
/*kzgProof*/ blobCompressionProof.kzgProofContract,
/*finalStateRootHash*/ blobCompressionProof.finalStateRootHash,
/*snarkHash*/ blobCompressionProof.snarkHash
)
}
/**
function submitBlobs(
BlobSubmission[] calldata _blobSubmissions,
bytes32 _parentShnarf,
bytes32 _finalBlobShnarf
)
*/
return Function(
LineaRollupV6.FUNC_SUBMITBLOBS,
Arrays.asList<Type<*>>(
DynamicArray(LineaRollupV6.BlobSubmission::class.java, blobsSubmissionData),
Bytes32(blobs.first().blobCompressionProof!!.prevShnarf),
Bytes32(blobs.last().blobCompressionProof!!.expectedShnarf)
),
emptyList<TypeReference<*>>()
)
}
fun buildFinalizeBlocksFunction(
version: LineaContractVersion,
aggregationProof: ProofToFinalize,
aggregationLastBlob: BlobRecord,
parentShnarf: ByteArray,
parentL1RollingHash: ByteArray,
parentL1RollingHashMessageNumber: Long
): Function {
when (version) {
LineaContractVersion.V5 -> {
return buildFinalizeBlobsFunction(
aggregationProof,
aggregationLastBlob,
parentShnarf,
parentL1RollingHash,
parentL1RollingHashMessageNumber
)
}
LineaContractVersion.V6 -> {
return buildFinalizeBlockFunctionV6(
aggregationProof,
aggregationLastBlob,
parentL1RollingHash,
parentL1RollingHashMessageNumber
)
}
}
}
internal fun buildFinalizeBlockFunctionV6(
aggregationProof: ProofToFinalize,
aggregationLastBlob: BlobRecord,
parentL1RollingHash: ByteArray,
parentL1RollingHashMessageNumber: Long
): Function {
val aggregationEndBlobInfo = LineaRollupV6.ShnarfData(
/*parentShnarf*/ aggregationLastBlob.blobCompressionProof!!.prevShnarf,
/*snarkHash*/ aggregationLastBlob.blobCompressionProof!!.snarkHash,
/*finalStateRootHash*/ aggregationLastBlob.blobCompressionProof!!.finalStateRootHash,
/*dataEvaluationPoint*/ aggregationLastBlob.blobCompressionProof!!.expectedX,
/*dataEvaluationClaim*/ aggregationLastBlob.blobCompressionProof!!.expectedY
)
// FinalizationDataV3(
// byte[] parentStateRootHash,
// BigInteger endBlockNumber,
// ShnarfData shnarfData,
// BigInteger lastFinalizedTimestamp,
// BigInteger finalTimestamp,
// byte[] lastFinalizedL1RollingHash,
// byte[] l1RollingHash,
// BigInteger lastFinalizedL1RollingHashMessageNumber,
// BigInteger l1RollingHashMessageNumber,
// BigInteger l2MerkleTreesDepth,
// List<byte[]> l2MerkleRoots,
// byte[] l2MessagingBlocksOffsets
// )
val finalizationData = LineaRollupV6.FinalizationDataV3(
/*parentStateRootHash*/ aggregationProof.parentStateRootHash,
/*endBlockNumber*/ aggregationProof.endBlockNumber.toBigInteger(),
/*shnarfData*/ aggregationEndBlobInfo,
/*lastFinalizedTimestamp*/ aggregationProof.parentAggregationLastBlockTimestamp.epochSeconds.toBigInteger(),
/*finalTimestamp*/ aggregationProof.finalTimestamp.epochSeconds.toBigInteger(),
/*lastFinalizedL1RollingHash*/ parentL1RollingHash,
/*l1RollingHash*/ aggregationProof.l1RollingHash,
/*lastFinalizedL1RollingHashMessageNumber*/ parentL1RollingHashMessageNumber.toBigInteger(),
/*l1RollingHashMessageNumber*/ aggregationProof.l1RollingHashMessageNumber.toBigInteger(),
/*l2MerkleTreesDepth*/ aggregationProof.l2MerkleTreesDepth.toBigInteger(),
/*l2MerkleRoots*/ aggregationProof.l2MerkleRoots,
/*l2MessagingBlocksOffsets*/ aggregationProof.l2MessagingBlocksOffsets
)
/**
* function finalizeBlocks(
* bytes calldata _aggregatedProof,
* uint256 _proofType,
* FinalizationDataV3 calldata _finalizationData
* )
*/
val function = Function(
LineaRollupV6.FUNC_FINALIZEBLOCKS,
Arrays.asList<Type<*>>(
DynamicBytes(aggregationProof.aggregatedProof),
Uint256(aggregationProof.aggregatedVerifierIndex.toLong()),
finalizationData
),
emptyList<TypeReference<*>>()
)
return function
}

View File

@@ -105,53 +105,39 @@ class Web3JLineaRollupSmartContractClient internal constructor(
}
}
override fun submitBlobs(
blobs: List<BlobRecord>,
gasPriceCaps: GasPriceCaps?
): SafeFuture<String> {
return submitBlobsV5(blobs, gasPriceCaps)
}
/**
* Sends EIP4844 blob carrying transaction to the smart contract.
* Uses SMC `submitBlobs` function that supports multiple blobs per call.
*/
private fun submitBlobsV5(
override fun submitBlobs(
blobs: List<BlobRecord>,
gasPriceCaps: GasPriceCaps?
): SafeFuture<String> {
require(blobs.size in 1..6) { "Blobs size=${blobs.size} must be between 1 and 6." }
val function = buildSubmitBlobsFunction(
blobs
)
return helper.sendBlobCarryingTransactionAndGetTxHash(
function = function,
blobs = blobs.map { it.blobCompressionProof!!.compressedData },
gasPriceCaps = gasPriceCaps
)
return getVersion()
.thenCompose { version ->
val function = buildSubmitBlobsFunction(version, blobs)
helper.sendBlobCarryingTransactionAndGetTxHash(
function = function,
blobs = blobs.map { it.blobCompressionProof!!.compressedData },
gasPriceCaps = gasPriceCaps
)
}
}
override fun submitBlobsEthCall(
blobs: List<BlobRecord>,
gasPriceCaps: GasPriceCaps?
): SafeFuture<String?> {
return submitBlobsEthCallImpl(blobs, gasPriceCaps)
}
private fun submitBlobsEthCallImpl(
blobs: List<BlobRecord>,
gasPriceCaps: GasPriceCaps? = null
): SafeFuture<String?> {
val function = buildSubmitBlobsFunction(blobs)
val transaction = helper.createEip4844Transaction(
function,
blobs.map { it.blobCompressionProof!!.compressedData }.toWeb3JTxBlob(),
gasPriceCaps
)
return web3j.informativeEthCall(transaction, smartContractErrors)
return getVersion()
.thenCompose { version ->
val function = buildSubmitBlobsFunction(version, blobs)
val transaction = helper.createEip4844Transaction(
function,
blobs.map { it.blobCompressionProof!!.compressedData }.toWeb3JTxBlob(),
gasPriceCaps
)
web3j.informativeEthCall(transaction, smartContractErrors)
}
}
override fun finalizeBlocks(
@@ -162,38 +148,22 @@ class Web3JLineaRollupSmartContractClient internal constructor(
parentL1RollingHashMessageNumber: Long,
gasPriceCaps: GasPriceCaps?
): SafeFuture<String> {
return finalizeBlocksV5(
aggregation,
aggregationLastBlob,
parentShnarf,
parentL1RollingHash,
parentL1RollingHashMessageNumber,
gasPriceCaps
)
}
private fun finalizeBlocksV5(
aggregation: ProofToFinalize,
aggregationLastBlob: BlobRecord,
parentShnarf: ByteArray,
parentL1RollingHash: ByteArray,
parentL1RollingHashMessageNumber: Long,
gasPriceCaps: GasPriceCaps?
): SafeFuture<String> {
val function = buildFinalizeBlobsFunction(
aggregation,
aggregationLastBlob,
parentShnarf,
parentL1RollingHash,
parentL1RollingHashMessageNumber
)
return SafeFuture.of(
helper.sendTransactionAsync(function, BigInteger.ZERO, gasPriceCaps)
).thenApply { result ->
throwExceptionIfJsonRpcErrorReturned("eth_sendRawTransaction", result)
result.transactionHash
}
return getVersion()
.thenCompose { version ->
val function = buildFinalizeBlocksFunction(
version,
aggregation,
aggregationLastBlob,
parentShnarf,
parentL1RollingHash,
parentL1RollingHashMessageNumber
)
helper.sendTransactionAsync(function, BigInteger.ZERO, gasPriceCaps)
.thenApply { result ->
throwExceptionIfJsonRpcErrorReturned("eth_sendRawTransaction", result)
result.transactionHash
}
}
}
override fun finalizeBlocksEthCall(
@@ -203,30 +173,17 @@ class Web3JLineaRollupSmartContractClient internal constructor(
parentL1RollingHash: ByteArray,
parentL1RollingHashMessageNumber: Long
): SafeFuture<String?> {
return finalizeBlocksEthCallV5(
aggregation,
aggregationLastBlob,
parentShnarf,
parentL1RollingHash,
parentL1RollingHashMessageNumber
)
}
private fun finalizeBlocksEthCallV5(
aggregation: ProofToFinalize,
aggregationLastBlob: BlobRecord,
parentShnarf: ByteArray,
parentL1RollingHash: ByteArray,
parentL1RollingHashMessageNumber: Long
): SafeFuture<String?> {
val function = buildFinalizeBlobsFunction(
aggregation,
aggregationLastBlob,
parentShnarf,
parentL1RollingHash,
parentL1RollingHashMessageNumber
)
return helper.executeEthCall(function)
return getVersion()
.thenCompose { version ->
val function = buildFinalizeBlocksFunction(
version,
aggregation,
aggregationLastBlob,
parentShnarf,
parentL1RollingHash,
parentL1RollingHashMessageNumber
)
helper.executeEthCall(function)
}
}
}

View File

@@ -1,5 +1,6 @@
package net.consensys.linea.contract.l1
import build.linea.contract.LineaRollupV6
import net.consensys.encodeHex
import net.consensys.linea.BlockParameter
import net.consensys.linea.async.toSafeFuture
@@ -13,6 +14,8 @@ import org.apache.logging.log4j.Logger
import org.web3j.crypto.Credentials
import org.web3j.protocol.Web3j
import org.web3j.protocol.core.DefaultBlockParameter
import org.web3j.tx.Contract
import org.web3j.tx.exceptions.ContractCallException
import org.web3j.tx.gas.StaticGasProvider
import tech.pegasys.teku.infrastructure.async.SafeFuture
import java.math.BigInteger
@@ -34,41 +37,76 @@ open class Web3JLineaRollupSmartContractClientReadOnly(
) : LineaRollupSmartContractClientReadOnly {
protected fun contractClientAtBlock(blockParameter: BlockParameter): LineaRollup {
return LineaRollup.load(
contractAddress,
web3j,
fakeCredentials,
StaticGasProvider(BigInteger.ZERO, BigInteger.ZERO)
).apply {
this.setDefaultBlockParameter(blockParameter.toWeb3j())
}
return contractClientAtBlock(blockParameter, LineaRollup::class.java)
}
protected fun <T : Contract> contractClientAtBlock(blockParameter: BlockParameter, contract: Class<T>): T {
@Suppress("UNCHECKED_CAST")
return when {
LineaRollupV6::class.java.isAssignableFrom(contract) -> LineaRollupV6.load(
contractAddress,
web3j,
fakeCredentials,
StaticGasProvider(BigInteger.ZERO, BigInteger.ZERO)
).apply {
this.setDefaultBlockParameter(blockParameter.toWeb3j())
}
LineaRollup::class.java.isAssignableFrom(contract) -> LineaRollup.load(
contractAddress,
web3j,
fakeCredentials,
StaticGasProvider(BigInteger.ZERO, BigInteger.ZERO)
).apply {
this.setDefaultBlockParameter(blockParameter.toWeb3j())
}
else -> throw IllegalArgumentException("Unsupported contract type: ${contract::class.java}")
} as T
}
protected val smartContractVersionCache: AtomicReference<LineaContractVersion> =
AtomicReference(fetchSmartContractVersion().get())
private fun getSmartContractVersion(): SafeFuture<LineaContractVersion> {
return if (smartContractVersionCache.get() == LineaContractVersion.V5) {
return if (smartContractVersionCache.get() == LineaContractVersion.V6) {
// once upgraded, it's not downgraded
SafeFuture.completedFuture(LineaContractVersion.V5)
SafeFuture.completedFuture(LineaContractVersion.V6)
} else {
fetchSmartContractVersion().thenPeek { contractLatestVersion ->
if (contractLatestVersion != smartContractVersionCache.get()) {
log.info(
"Smart contract upgraded: prevVersion={} upgradedVersion={}",
smartContractVersionCache.get(),
contractLatestVersion
)
fetchSmartContractVersion()
.thenPeek { contractLatestVersion ->
if (contractLatestVersion != smartContractVersionCache.get()) {
log.info(
"Smart contract upgraded: prevVersion={} upgradedVersion={}",
smartContractVersionCache.get(),
contractLatestVersion
)
}
smartContractVersionCache.set(contractLatestVersion)
}
smartContractVersionCache.set(contractLatestVersion)
}
}
}
private fun fetchSmartContractVersion(): SafeFuture<LineaContractVersion> {
// FIXME: this is a temporary solution to determine the smart contract version.
// It should rely on events
return SafeFuture.completedFuture(LineaContractVersion.V5)
return contractClientAtBlock(BlockParameter.Tag.LATEST, LineaRollupV6::class.java)
.CONTRACT_VERSION()
.sendAsync()
.toSafeFuture()
.thenApply { version ->
when {
version.startsWith("6") -> LineaContractVersion.V6
else -> throw IllegalStateException("Unsupported contract version: $version")
}
}
.exceptionallyCompose { error ->
if (error.cause is ContractCallException) {
// means that contract does not have CONTRACT_VERSION method available yet
// so it is still V5, so defaulting to V5
SafeFuture.completedFuture(LineaContractVersion.V5)
} else {
SafeFuture.failedFuture(error)
}
}
}
override fun getAddress(): String = contractAddress
@@ -94,11 +132,18 @@ open class Web3JLineaRollupSmartContractClientReadOnly(
return contractClientAtBlock(blockParameter).rollingHashes(messageNumber.toBigInteger()).sendAsync().toSafeFuture()
}
override fun findBlobFinalBlockNumberByShnarf(blockParameter: BlockParameter, shnarf: ByteArray): SafeFuture<ULong?> {
return contractClientAtBlock(blockParameter)
.shnarfFinalBlockNumbers(shnarf).sendAsync()
.thenApply { if (it == BigInteger.ZERO) null else it.toULong() }
.toSafeFuture()
override fun isBlobShnarfPresent(blockParameter: BlockParameter, shnarf: ByteArray): SafeFuture<Boolean> {
return getVersion()
.thenCompose { version ->
if (version == LineaContractVersion.V5) {
contractClientAtBlock(blockParameter, LineaRollup::class.java).shnarfFinalBlockNumbers(shnarf)
} else {
contractClientAtBlock(blockParameter, LineaRollupV6::class.java).blobShnarfExists(shnarf)
}
.sendAsync()
.thenApply { it != BigInteger.ZERO }
.toSafeFuture()
}
}
override fun blockStateRootHash(blockParameter: BlockParameter, lineaL2BlockNumber: ULong): SafeFuture<ByteArray> {

View File

@@ -7,7 +7,8 @@ import net.consensys.zkevm.ethereum.gaspricing.GasPriceCaps
import tech.pegasys.teku.infrastructure.async.SafeFuture
enum class LineaContractVersion : Comparable<LineaContractVersion> {
V5 // "EIP4844 multiple blobs per tx support - version in all networks",
V5, // "EIP4844 multiple blobs per tx support - version in all networks"
V6 // more efficient data submission and new events for state recovery
}
interface LineaRollupSmartContractClientReadOnly : ContractVersionProvider<LineaContractVersion> {
@@ -30,12 +31,14 @@ interface LineaRollupSmartContractClientReadOnly : ContractVersionProvider<Linea
): SafeFuture<ByteArray>
/**
* Get the final block number of a shnarf
* Checks if a blob's shnarf is already present in the smart contract
* It meant blob was sent to l1 and accepted by the smart contract.
* Note: snarf in the future may be cleanned up after finalization.
*/
fun findBlobFinalBlockNumberByShnarf(
fun isBlobShnarfPresent(
blockParameter: BlockParameter = BlockParameter.Tag.LATEST,
shnarf: ByteArray
): SafeFuture<ULong?>
): SafeFuture<Boolean>
/**
* Gets Type 2 StateRootHash for Linea Block

View File

@@ -61,12 +61,12 @@ class BlobAndAggregationFinalizationIntTest : CleanDbTestSuiteParallel() {
vertx: Vertx,
smartContractVersion: LineaContractVersion
) {
if (smartContractVersion != LineaContractVersion.V5) {
if (listOf(LineaContractVersion.V5, LineaContractVersion.V6).contains(smartContractVersion).not()) {
// V6 with prover V3 is soon comming, so we will need to update/extend this test setup
throw IllegalArgumentException("Only V5 contract version is supported")
throw IllegalArgumentException("unsupported contract version=$smartContractVersion!")
}
val rollupDeploymentFuture = ContractsManager.get()
.deployLineaRollup(numberOfOperators = 2, contractVersion = LineaContractVersion.V5)
.deployLineaRollup(numberOfOperators = 2, contractVersion = smartContractVersion)
// load files from FS while smc deploy
loadBlobsAndAggregations(
blobsResponsesDir = "$testDataDir/compression/responses",
@@ -90,10 +90,10 @@ class BlobAndAggregationFinalizationIntTest : CleanDbTestSuiteParallel() {
)
aggregationsRepository = AggregationsRepositoryImpl(PostgresAggregationsDao(sqlClient, fakeClock))
val lineaRollupContractForDataSubmissionV4 = rollupDeploymentResult.rollupOperatorClient
val lineaRollupContractForDataSubmissionV5 = rollupDeploymentResult.rollupOperatorClient
@Suppress("DEPRECATION")
val alreadySubmittedBlobFilter = L1ShnarfBasedAlreadySubmittedBlobsFilter(lineaRollupContractForDataSubmissionV4)
val alreadySubmittedBlobFilter = L1ShnarfBasedAlreadySubmittedBlobsFilter(lineaRollupContractForDataSubmissionV5)
blobSubmissionCoordinator = run {
BlobSubmissionCoordinator.create(
@@ -105,7 +105,7 @@ class BlobAndAggregationFinalizationIntTest : CleanDbTestSuiteParallel() {
),
blobsRepository = blobsRepository,
aggregationsRepository = aggregationsRepository,
lineaSmartContractClient = lineaRollupContractForDataSubmissionV4,
lineaSmartContractClient = lineaRollupContractForDataSubmissionV5,
alreadySubmittedBlobsFilter = alreadySubmittedBlobFilter,
gasPriceCapProvider = FakeGasPriceCapProvider(),
vertx = vertx,
@@ -115,9 +115,10 @@ class BlobAndAggregationFinalizationIntTest : CleanDbTestSuiteParallel() {
aggregationFinalizationCoordinator = run {
lineaRollupContractForAggregationSubmission = MakeFileDelegatedContractsManager
.connectToLineaRollupContractV5(
.connectToLineaRollupContract(
rollupDeploymentResult.contractAddress,
rollupDeploymentResult.rollupOperators[1].txManager
)
val aggregationSubmitter = AggregationSubmitterImpl(
@@ -141,15 +142,6 @@ class BlobAndAggregationFinalizationIntTest : CleanDbTestSuiteParallel() {
}
}
@Test
@Timeout(3, timeUnit = TimeUnit.MINUTES)
fun `submission works with contract V5`(
vertx: Vertx,
testContext: VertxTestContext
) {
testSubmission(vertx, testContext, LineaContractVersion.V5)
}
private fun testSubmission(
vertx: Vertx,
testContext: VertxTestContext,
@@ -180,4 +172,22 @@ class BlobAndAggregationFinalizationIntTest : CleanDbTestSuiteParallel() {
testContext.completeNow()
}.whenException(testContext::failNow)
}
@Test
@Timeout(3, timeUnit = TimeUnit.MINUTES)
fun `submission works with contract V5`(
vertx: Vertx,
testContext: VertxTestContext
) {
testSubmission(vertx, testContext, LineaContractVersion.V5)
}
@Test
@Timeout(3, timeUnit = TimeUnit.MINUTES)
fun `submission works with contract V6`(
vertx: Vertx,
testContext: VertxTestContext
) {
testSubmission(vertx, testContext, LineaContractVersion.V6)
}
}

View File

@@ -20,7 +20,15 @@ class L1ShnarfBasedAlreadySubmittedBlobsFilter(
blobRecords: List<BlobRecord>
): SafeFuture<List<BlobRecord>> {
val blockByShnarfQueryFutures = blobRecords.map { blobRecord ->
lineaRollup.findBlobFinalBlockNumberByShnarf(shnarf = blobRecord.expectedShnarf)
lineaRollup
.isBlobShnarfPresent(shnarf = blobRecord.expectedShnarf)
.thenApply { isShnarfPresent ->
if (isShnarfPresent) {
blobRecord.endBlockNumber
} else {
null
}
}
}
return SafeFuture.collectAll(blockByShnarfQueryFutures.stream())

View File

@@ -26,13 +26,13 @@ class L1ShnarfBasedAlreadySubmittedBlobsFilterTest {
val blobs = listOf(blob1, blob2, blob3, blob4, blob5, blob6, blob7)
val l1SmcClient = mock<LineaRollupSmartContractClient>()
whenever(l1SmcClient.findBlobFinalBlockNumberByShnarf(any(), any()))
whenever(l1SmcClient.isBlobShnarfPresent(any(), any()))
.thenAnswer { invocation ->
val shnarfQueried = invocation.getArgument<ByteArray>(1)
val endBlockNumber = when {
shnarfQueried.contentEquals(blob3.expectedShnarf) -> blob3.endBlockNumber
shnarfQueried.contentEquals(blob5.expectedShnarf) -> blob5.endBlockNumber
else -> null
shnarfQueried.contentEquals(blob3.expectedShnarf) -> true
shnarfQueried.contentEquals(blob5.expectedShnarf) -> true
else -> false
}
SafeFuture.completedFuture(endBlockNumber)
}

View File

@@ -8,6 +8,7 @@ import net.consensys.linea.contract.LineaRollup
import net.consensys.linea.contract.LineaRollupAsyncFriendly
import net.consensys.toBigInteger
import net.consensys.toULong
import net.consensys.zkevm.coordinator.clients.smartcontract.LineaContractVersion
import net.consensys.zkevm.ethereum.ContractsManager
import net.consensys.zkevm.ethereum.Web3jClientManager
import org.apache.tuweni.bytes.Bytes32
@@ -35,7 +36,9 @@ class L1EventQuerierIntegrationTest {
@BeforeEach
fun beforeEach() {
val deploymentResult = ContractsManager.get().deployLineaRollup().get()
val deploymentResult = ContractsManager.get()
.deployLineaRollup(contractVersion = LineaContractVersion.V5)
.get()
testLineaRollupContractAddress = deploymentResult.contractAddress
web3Client = Web3jClientManager.l1Client
@Suppress("DEPRECATION")

View File

@@ -10,6 +10,7 @@ import net.consensys.linea.contract.LineaRollup
import net.consensys.linea.contract.LineaRollupAsyncFriendly
import net.consensys.toBigInteger
import net.consensys.toULong
import net.consensys.zkevm.coordinator.clients.smartcontract.LineaContractVersion
import net.consensys.zkevm.coordinator.clients.smartcontract.LineaRollupSmartContractClient
import net.consensys.zkevm.ethereum.ContractsManager
import net.consensys.zkevm.ethereum.Web3jClientManager
@@ -47,7 +48,9 @@ class MessageServiceIntegrationTest {
private lateinit var l2Contract: L2MessageService
private fun deployContracts() {
val l1RollupDeploymentResult = ContractsManager.get().deployLineaRollup().get()
val l1RollupDeploymentResult = ContractsManager.get()
.deployLineaRollup(contractVersion = LineaContractVersion.V5)
.get()
@Suppress("DEPRECATION")
l1ContractLegacyClient = l1RollupDeploymentResult.rollupOperatorClientLegacy
l1ContractClient = l1RollupDeploymentResult.rollupOperatorClient

View File

@@ -14,6 +14,8 @@ dependencies {
implementation("org.web3j:core:${libs.versions.web3j.get()}") {
exclude group: 'org.slf4j', module: 'slf4j-nop'
}
implementation "com.sksamuel.hoplite:hoplite-core:${libs.versions.hoplite.get()}"
implementation "com.sksamuel.hoplite:hoplite-toml:${libs.versions.hoplite.get()}"
implementation "com.fasterxml.jackson.core:jackson-annotations:${libs.versions.jackson.get()}"
implementation "com.fasterxml.jackson.core:jackson-databind:${libs.versions.jackson.get()}"
implementation "com.fasterxml.jackson.module:jackson-module-kotlin:${libs.versions.jackson.get()}"

View File

@@ -1,11 +1,14 @@
package net.consensys.zkevm.ethereum
import com.sksamuel.hoplite.ConfigLoaderBuilder
import com.sksamuel.hoplite.addFileSource
import net.consensys.linea.contract.AsyncFriendlyTransactionManager
import net.consensys.linea.contract.EIP1559GasProvider
import net.consensys.linea.contract.LineaRollupAsyncFriendly
import net.consensys.linea.contract.StaticGasProvider
import net.consensys.linea.contract.l1.Web3JLineaRollupSmartContractClient
import net.consensys.linea.contract.l2.L2MessageServiceGasLimitEstimate
import net.consensys.linea.testing.filesystem.findPathTo
import net.consensys.linea.web3j.SmartContractErrors
import net.consensys.zkevm.coordinator.clients.smartcontract.LineaContractVersion
import net.consensys.zkevm.coordinator.clients.smartcontract.LineaRollupSmartContractClient
@@ -45,17 +48,17 @@ interface ContractsManager {
*/
fun deployLineaRollup(
numberOfOperators: Int = 1,
contractVersion: LineaContractVersion = LineaContractVersion.V5
contractVersion: LineaContractVersion
): SafeFuture<LineaRollupDeploymentResult>
fun deployL2MessageService(): SafeFuture<L2MessageServiceDeploymentResult>
fun deployRollupAndL2MessageService(
dataCompressionAndProofAggregationMigrationBlock: ULong = 1000UL,
numberOfOperators: Int = 1
numberOfOperators: Int = 1,
l1ContractVersion: LineaContractVersion = LineaContractVersion.V5
): SafeFuture<ContactsDeploymentResult>
@Deprecated("Use connectToLineaRollupContractV5 instead")
fun connectToLineaRollupContract(
contractAddress: String,
transactionManager: AsyncFriendlyTransactionManager,
@@ -64,18 +67,8 @@ interface ContractsManager {
maxFeePerGas = 11_000uL,
maxPriorityFeePerGas = 10_000uL,
gasLimit = 1_000_000uL
)
): LineaRollupAsyncFriendly
fun connectToLineaRollupContractV5(
contractAddress: String,
transactionManager: AsyncFriendlyTransactionManager,
gasProvider: ContractEIP1559GasProvider = StaticGasProvider(
L1AccountManager.chainId,
maxFeePerGas = 11_000uL,
maxPriorityFeePerGas = 10_000uL,
gasLimit = 1_000_000uL
)
),
smartContractErrors: SmartContractErrors? = null
): LineaRollupSmartContractClient
fun connectL2MessageService(
@@ -94,14 +87,35 @@ interface ContractsManager {
smartContractErrors: SmartContractErrors = emptyMap()
): L2MessageServiceGasLimitEstimate
@Deprecated("Use connectToLineaRollupContract instead")
fun connectToLineaRollupContractLegacy(
contractAddress: String,
transactionManager: AsyncFriendlyTransactionManager,
gasProvider: ContractEIP1559GasProvider = StaticGasProvider(
L1AccountManager.chainId,
maxFeePerGas = 11_000uL,
maxPriorityFeePerGas = 10_000uL,
gasLimit = 1_000_000uL
)
): LineaRollupAsyncFriendly
companion object {
// TODO: think of better get the Instance
fun get(): ContractsManager = MakeFileDelegatedContractsManager
}
}
object MakeFileDelegatedContractsManager : ContractsManager {
val log = LoggerFactory.getLogger(MakeFileDelegatedContractsManager::class.java)
val lineaRollupContractErrors = findPathTo("config")!!
.resolve("common/smart-contract-errors.toml")
.let { filePath ->
data class ErrorsFile(val smartContractErrors: Map<String, String>)
ConfigLoaderBuilder.default()
.addFileSource(filePath.toAbsolutePath().toString())
.build()
.loadConfigOrThrow<ErrorsFile>()
.smartContractErrors
}
override fun deployLineaRollup(
numberOfOperators: Int,
@@ -133,12 +147,14 @@ object MakeFileDelegatedContractsManager : ContractsManager {
AccountTransactionManager(it, L1AccountManager.getTransactionManager(it))
}
@Suppress("DEPRECATION")
val rollupOperatorClient = connectToLineaRollupContract(
deploymentResult.address,
accountsTxManagers.first().txManager
accountsTxManagers.first().txManager,
smartContractErrors = lineaRollupContractErrors
)
val rollupOperatorClientV4 = connectToLineaRollupContractV5(
@Suppress("DEPRECATION")
val rollupOperatorClientLegacy = connectToLineaRollupContractLegacy(
deploymentResult.address,
accountsTxManagers.first().txManager
)
@@ -147,8 +163,8 @@ object MakeFileDelegatedContractsManager : ContractsManager {
contractDeploymentAccount = contractDeploymentAccount,
contractDeploymentBlockNumber = deploymentResult.blockNumber.toULong(),
rollupOperators = accountsTxManagers,
rollupOperatorClientLegacy = rollupOperatorClient,
rollupOperatorClient = rollupOperatorClientV4
rollupOperatorClientLegacy = rollupOperatorClientLegacy,
rollupOperatorClient = rollupOperatorClient
)
}
return future
@@ -174,9 +190,10 @@ object MakeFileDelegatedContractsManager : ContractsManager {
override fun deployRollupAndL2MessageService(
dataCompressionAndProofAggregationMigrationBlock: ULong,
numberOfOperators: Int
numberOfOperators: Int,
l1ContractVersion: LineaContractVersion
): SafeFuture<ContactsDeploymentResult> {
return deployLineaRollup(numberOfOperators)
return deployLineaRollup(numberOfOperators, l1ContractVersion)
.thenCombine(deployL2MessageService()) { lineaRollupDeploymentResult, l2MessageServiceDeploymentResult ->
ContactsDeploymentResult(
lineaRollup = lineaRollupDeploymentResult,
@@ -185,32 +202,18 @@ object MakeFileDelegatedContractsManager : ContractsManager {
}
}
@Deprecated("Use connectToLineaRollupContractV5 instead")
override fun connectToLineaRollupContract(
contractAddress: String,
transactionManager: AsyncFriendlyTransactionManager,
gasProvider: ContractEIP1559GasProvider
): LineaRollupAsyncFriendly {
return LineaRollupAsyncFriendly.load(
contractAddress,
Web3jClientManager.l1Client,
transactionManager,
gasProvider,
emptyMap()
)
}
override fun connectToLineaRollupContractV5(
contractAddress: String,
transactionManager: AsyncFriendlyTransactionManager,
gasProvider: ContractEIP1559GasProvider
gasProvider: ContractEIP1559GasProvider,
smartContractErrors: SmartContractErrors?
): LineaRollupSmartContractClient {
return Web3JLineaRollupSmartContractClient.load(
contractAddress,
Web3jClientManager.l1Client,
transactionManager,
gasProvider,
emptyMap()
smartContractErrors ?: lineaRollupContractErrors
)
}
@@ -229,4 +232,33 @@ object MakeFileDelegatedContractsManager : ContractsManager {
smartContractErrors
)
}
@Deprecated("Use connectToLineaRollupContract instead")
override fun connectToLineaRollupContractLegacy(
contractAddress: String,
transactionManager: AsyncFriendlyTransactionManager,
gasProvider: ContractEIP1559GasProvider
): LineaRollupAsyncFriendly {
return LineaRollupAsyncFriendly.load(
contractAddress,
Web3jClientManager.l1Client,
transactionManager,
gasProvider,
emptyMap()
)
}
}
fun main() {
data class SmartContractErrors(val smartContractErrors: Map<String, String>)
val lineaRollupContractErrors = findPathTo("config")!!
.resolve("common/smart-contract-errors.toml")
.let { filePath ->
ConfigLoaderBuilder.default()
.addFileSource(filePath.toAbsolutePath().toString())
.build()
.loadConfigOrThrow<SmartContractErrors>()
}
println(lineaRollupContractErrors)
}

View File

@@ -143,10 +143,10 @@ fun makeDeployLineaRollup(
// "HARDHAT_DISABLE_CACHE" to "true"
)
deploymentPrivateKey?.let { env["DEPLOYMENT_PRIVATE_KEY"] = it }
val command = if (contractVersion == LineaContractVersion.V5) {
"make deploy-linea-rollup"
} else {
throw IllegalArgumentException("Unsupported contract version: $contractVersion")
val command = when (contractVersion) {
LineaContractVersion.V5 -> "make deploy-linea-rollup"
LineaContractVersion.V6 -> "make deploy-linea-rollup-v6"
else -> throw IllegalArgumentException("Unsupported contract version: $contractVersion")
}
return deployContract(

View File

@@ -16,8 +16,8 @@ dependencies {
web3jContractWrappers {
def contractAbi = layout.buildDirectory.dir("${rootProject.projectDir}/contracts/abi").get()
.file("LineaRollupV5.0.abi").asFile.absolutePath
.file("LineaRollupV6.0.abi").asFile.absolutePath
contractsPackage = "net.consensys.linea.contract"
contracts = ["$contractAbi": "LineaRollup"]
contractsPackage = "build.linea.contract"
contracts = ["$contractAbi": "LineaRollupV6"]
}