From 1fea41b066b486b6ee89ed98808c955d1f79f808 Mon Sep 17 00:00:00 2001 From: Fluent Crafter <205769460+fluentcrafter@users.noreply.github.com> Date: Tue, 17 Jun 2025 09:19:44 +0100 Subject: [PATCH] coordinator: adds FakeLineaRollupSmartContractClient (#1161) * coordinator: adds FakeLineaRollupSmartContractClient * coordinator: change @get:Synchronized notation * coordinator: move contractVersion to constructor * jvm-libs: fix publish job --- .github/workflows/maven-release-all.yml | 4 +- .../l1/FakeLineaRollupSmartContractClient.kt | 105 ++++++++++++++++++ 2 files changed, 107 insertions(+), 2 deletions(-) create mode 100644 jvm-libs/linea/clients/linea-contract-clients/src/testFixtures/kotlin/linea/contract/l1/FakeLineaRollupSmartContractClient.kt diff --git a/.github/workflows/maven-release-all.yml b/.github/workflows/maven-release-all.yml index 2c4a0d63..791f4c8c 100644 --- a/.github/workflows/maven-release-all.yml +++ b/.github/workflows/maven-release-all.yml @@ -5,7 +5,7 @@ on: version: required: false type: string - description: 'Release version: e.g "1.0.0". Defaults to 0.0. if not provided' + description: 'Release version: e.g "1.0.0". Defaults to 0.0.1-v if not provided' jobs: release: @@ -17,7 +17,7 @@ jobs: TIMESTAMP=`date -u +'%Y%m%d%H%M%S'` INPUT_VERSION=${{ github.event.inputs.version }} if [ -z "$INPUT_VERSION" ]; then - VERSION="0.0.$TIMESTAMP" + VERSION="0.0.1-v$TIMESTAMP" else VERSION=$INPUT_VERSION fi diff --git a/jvm-libs/linea/clients/linea-contract-clients/src/testFixtures/kotlin/linea/contract/l1/FakeLineaRollupSmartContractClient.kt b/jvm-libs/linea/clients/linea-contract-clients/src/testFixtures/kotlin/linea/contract/l1/FakeLineaRollupSmartContractClient.kt new file mode 100644 index 00000000..29fb4928 --- /dev/null +++ b/jvm-libs/linea/clients/linea-contract-clients/src/testFixtures/kotlin/linea/contract/l1/FakeLineaRollupSmartContractClient.kt @@ -0,0 +1,105 @@ +package linea.contract.l1 + +import kotlinx.datetime.Clock +import kotlinx.datetime.Instant +import linea.domain.BlockParameter +import linea.kotlin.encodeHex +import tech.pegasys.teku.infrastructure.async.SafeFuture +import java.util.concurrent.ConcurrentHashMap +import kotlin.random.Random + +data class FinalizedBlock( + val number: ULong, + val timestamp: Instant, + val stateRootHash: ByteArray, +) { + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as FinalizedBlock + + if (number != other.number) return false + if (timestamp != other.timestamp) return false + if (!stateRootHash.contentEquals(other.stateRootHash)) return false + + return true + } + + override fun hashCode(): Int { + var result = number.hashCode() + result = 31 * result + timestamp.hashCode() + result = 31 * result + stateRootHash.contentHashCode() + return result + } + + override fun toString(): String { + return "FinalizedBlock(number=$number, timestamp=$timestamp, stateRootHash=${stateRootHash.encodeHex()})" + } +} + +class FakeLineaRollupSmartContractClient( + val contractAddress: String = Random.nextBytes(20).encodeHex(), + @get:Synchronized @set:Synchronized + var contractVersion: LineaContractVersion = LineaContractVersion.V6, + _finalizedBlocks: List = listOf(FinalizedBlock(0uL, Clock.System.now(), Random.nextBytes(32))), + _messageRollingHashes: Map = emptyMap(), +) : LineaRollupSmartContractClientReadOnly { + val messageRollingHashes: MutableMap = ConcurrentHashMap(_messageRollingHashes) + val finalizedBlocks: MutableMap = ConcurrentHashMap() + + init { + require(_finalizedBlocks.size > 0) { "At least one finalized block is required" } + _finalizedBlocks.forEach { block -> finalizedBlocks.put(block.number, block) } + require(finalizedBlocks[0UL] != null) { + "Finalized block with number 0 must be present" + } + } + + private fun lastFinalizedBlock(): FinalizedBlock = + finalizedBlocks.values.maxByOrNull { it.number } + ?: throw IllegalStateException("No finalized blocks available") + + @Synchronized + fun setFinalizedBlock( + number: ULong, + timestamp: Instant = Clock.System.now(), + stateRootHash: ByteArray = Random.nextBytes(32), + ) { + val lastFinalizedBlock = lastFinalizedBlock().number + + require(lastFinalizedBlock <= number) { + "next finalized blockNumber=$number must be greater than lastFinalizedBlock=$lastFinalizedBlock" + } + + finalizedBlocks[number] = FinalizedBlock(number, timestamp, stateRootHash) + } + + override fun getAddress(): String = contractAddress + + override fun getVersion(): SafeFuture = SafeFuture.completedFuture(contractVersion) + + override fun finalizedL2BlockNumber(blockParameter: BlockParameter): SafeFuture = + SafeFuture.completedFuture(lastFinalizedBlock().number) + + override fun finalizedL2BlockTimestamp(blockParameter: BlockParameter): SafeFuture = + SafeFuture.completedFuture(lastFinalizedBlock().timestamp.epochSeconds.toULong()) + + override fun getMessageRollingHash( + blockParameter: BlockParameter, + messageNumber: Long, + ): SafeFuture = SafeFuture.completedFuture(messageRollingHashes[messageNumber.toULong()] ?: ByteArray(32)) + + override fun isBlobShnarfPresent( + blockParameter: BlockParameter, + shnarf: ByteArray, + ): SafeFuture = SafeFuture.completedFuture(false) + + override fun blockStateRootHash( + blockParameter: BlockParameter, + lineaL2BlockNumber: ULong, + ): SafeFuture { + val stateRootHash = finalizedBlocks[lineaL2BlockNumber]?.stateRootHash ?: ByteArray(32) + return SafeFuture.completedFuture(stateRootHash) + } +}