Skip to content

Commit

Permalink
Blob Decompressor and Some Helpers (#230)
Browse files Browse the repository at this point in the history
* adds Java/Kotlin blob decompressor and some common libs
  • Loading branch information
jpnovais authored Oct 23, 2024
1 parent ce964fc commit ecfe183
Show file tree
Hide file tree
Showing 25 changed files with 405 additions and 16 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package build.linea

import java.net.URI

fun URI.getPortWithSchemeDefaults(): Int {
return if (port != -1) {
port
} else {
when (scheme.lowercase()) {
"http" -> 80
"https" -> 443
// Focous on HTTP as it is what we need for now
else -> throw IllegalArgumentException("Unsupported scheme: $scheme")
}
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package net.consensys.jvm
package build.linea.jvm

import java.io.File
import java.nio.file.Files
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package build.linea

import org.assertj.core.api.Assertions.assertThat
import org.assertj.core.api.Assertions.assertThatThrownBy
import org.junit.jupiter.api.Test
import java.net.URI

class URIExtensionsTest {
@Test
fun `getPortWithSchemaDefaults`() {
assertThat(URI.create("http://example.com").getPortWithSchemeDefaults()).isEqualTo(80)
assertThat(URI.create("https://example.com").getPortWithSchemeDefaults()).isEqualTo(443)
assertThat(URI.create("http://example.com:8080").getPortWithSchemeDefaults()).isEqualTo(8080)
assertThat(URI.create("https://example.com:8080").getPortWithSchemeDefaults()).isEqualTo(8080)
assertThat(URI.create("myschema://example.com:8080").getPortWithSchemeDefaults()).isEqualTo(8080)
assertThatThrownBy { (URI.create("mySchema://example.com").getPortWithSchemeDefaults()) }
.isInstanceOf(IllegalArgumentException::class.java)
.hasMessage("Unsupported scheme: mySchema")
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package net.consensys.jvm
package build.linea.jvm

import net.consensys.jvm.ResourcesUtil.copyResourceToTmpDir
import build.linea.jvm.ResourcesUtil.copyResourceToTmpDir
import org.assertj.core.api.AssertionsForClassTypes.assertThat
import org.junit.jupiter.api.Test
import java.nio.file.Files
Expand Down
9 changes: 9 additions & 0 deletions jvm-libs/generic/extensions/tuweni/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
plugins {
id 'net.consensys.zkevm.kotlin-library-conventions'
}

dependencies {
api "io.tmio:tuweni-bytes:${libs.versions.tuweni.get()}"
implementation(project(':jvm-libs:generic:extensions:kotlin'))
testImplementation "io.tmio:tuweni-units:${libs.versions.tuweni.get()}"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package build.linea.tuweni

import net.consensys.toULong
import org.apache.tuweni.bytes.Bytes32
import java.math.BigInteger

fun ByteArray.toBytes32(): Bytes32 = Bytes32.wrap(this)
fun ByteArray.sliceAsBytes32(sliceIndex: Int): Bytes32 = Bytes32.wrap(this, /*offset*/sliceIndex * 32)
fun Bytes32.toULong(): ULong = BigInteger(this.toArray()).toULong()
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package build.linea.tuweni

import net.consensys.toBigInteger
import org.apache.tuweni.bytes.Bytes32
import org.apache.tuweni.units.bigints.UInt256
import org.assertj.core.api.Assertions.assertThat
import org.assertj.core.api.Assertions.assertThatThrownBy
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import kotlin.random.Random

class Bytes32Test {
@BeforeEach
fun setUp() {
// workaround: need this to load the functions otherwise JUNit gets stuck ¯\_(ツ)_/¯
Random.Default.nextBytes(32).sliceAsBytes32(0)
UInt256.ZERO.toBytes().toULong()
}

@Test
fun testSliceAsBytes32() {
val bytes = Random.Default.nextBytes(3 * 32 - 1)
assertThat(bytes.sliceAsBytes32(0)).isEqualTo(Bytes32.wrap(bytes, 0))
assertThat(bytes.sliceAsBytes32(1)).isEqualTo(Bytes32.wrap(bytes, 32))
assertThatThrownBy { bytes.sliceAsBytes32(2) }
.isInstanceOf(IllegalArgumentException::class.java)
}

@Test
fun testToULong() {
UInt256.ZERO.toBytes()
.also { bytes -> assertThat(bytes.toULong()).isEqualTo(0uL) }
UInt256.valueOf(Long.MAX_VALUE)
.also { bytes -> assertThat(bytes.toULong()).isEqualTo(Long.MAX_VALUE.toULong()) }
UInt256.valueOf(Long.MAX_VALUE).add(UInt256.ONE)
.also { bytes -> assertThat(bytes.toULong()).isEqualTo(Long.MAX_VALUE.toULong() + 1UL) }
UInt256.valueOf(ULong.MAX_VALUE.toBigInteger())
.also { bytes -> assertThat(bytes.toULong()).isEqualTo(ULong.MAX_VALUE) }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,6 @@ class VertxHttpJsonRpcClientFactory(
}

fun createV2(
vertx: Vertx,
endpoints: Set<URL>,
maxInflightRequestsPerClient: UInt? = null,
retryConfig: RequestRetryConfig,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,6 @@ class JsonRpcV2ClientImplTest {
)

private fun createClientAndSetupWireMockServer(
vertx: Vertx,
responseObjectMapper: ObjectMapper = defaultObjectMapper,
requestObjectMapper: ObjectMapper = defaultObjectMapper,
retryConfig: RequestRetryConfig = defaultRetryConfig,
Expand All @@ -89,7 +88,6 @@ class JsonRpcV2ClientImplTest {
endpoint = URI(wiremock.baseUrl() + path).toURL()

return factory.createV2(
vertx = vertx,
endpoints = setOf(endpoint),
retryConfig = retryConfig,
requestObjectMapper = requestObjectMapper,
Expand All @@ -103,7 +101,7 @@ class JsonRpcV2ClientImplTest {
this.vertx = vertx
this.meterRegistry = SimpleMeterRegistry()
this.factory = VertxHttpJsonRpcClientFactory(vertx, meterRegistry)
this.client = createClientAndSetupWireMockServer(vertx)
this.client = createClientAndSetupWireMockServer()
}

@AfterEach
Expand Down Expand Up @@ -192,7 +190,7 @@ class JsonRpcV2ClientImplTest {
fun `request params shall use defined objectMapper and not affect json-rpc envelope`() {
val obj = User(name = "John", email = "email@example.com", address = "0x01ffbb".decodeHex(), value = 987UL)

createClientAndSetupWireMockServer(vertx, requestObjectMapper = defaultObjectMapper).also { client ->
createClientAndSetupWireMockServer(requestObjectMapper = defaultObjectMapper).also { client ->
replyRequestWith(200, jsonRpcResultOk)
client.makeRequest(
method = "someMethod",
Expand Down Expand Up @@ -223,7 +221,7 @@ class JsonRpcV2ClientImplTest {
}
)

createClientAndSetupWireMockServer(vertx, requestObjectMapper = objMapperWithNumbersAsHex).also { client ->
createClientAndSetupWireMockServer(requestObjectMapper = objMapperWithNumbersAsHex).also { client ->
replyRequestWith(200, jsonRpcResultOk)
client.makeRequest(
method = "someMethod",
Expand Down Expand Up @@ -456,7 +454,6 @@ class JsonRpcV2ClientImplTest {
@Test
fun `when it gets an error propagates to shallRetryRequestPredicate and retries while is true`() {
createClientAndSetupWireMockServer(
vertx,
retryConfig = retryConfig(maxRetries = 10u)
).also { client ->
val responses = listOf(
Expand Down Expand Up @@ -507,7 +504,6 @@ class JsonRpcV2ClientImplTest {
@Test
fun `when it has connection error propagates to shallRetryRequestPredicate and retries while is true`() {
createClientAndSetupWireMockServer(
vertx,
retryConfig = retryConfig(maxRetries = 10u)
).also { client ->
// stop the server to simulate connection error
Expand Down Expand Up @@ -543,7 +539,6 @@ class JsonRpcV2ClientImplTest {
@Test
fun `when it has connection error propagates to shallRetryRequestPredicate and retries until retry config elapses`() {
createClientAndSetupWireMockServer(
vertx,
retryConfig = retryConfig(maxRetries = 2u, timeout = 8.seconds, backoffDelay = 5.milliseconds)
).also { client ->
// stop the server to simulate connection error
Expand Down Expand Up @@ -580,7 +575,6 @@ class JsonRpcV2ClientImplTest {
(it.value as String).startsWith("retry_a")
}
createClientAndSetupWireMockServer(
vertx,
retryConfig = RequestRetryConfig(
maxRetries = 10u,
timeout = 5.minutes,
Expand Down
1 change: 1 addition & 0 deletions jvm-libs/generic/vertx-helper/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ plugins {
}

dependencies {
implementation project(':jvm-libs:generic:extensions:kotlin')
implementation project(':jvm-libs:generic:extensions:futures')
implementation "io.vertx:vertx-core"
implementation "io.vertx:vertx-web"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package net.consensys.linea.vertx

import build.linea.getPortWithSchemeDefaults
import io.vertx.core.http.HttpClientOptions
import java.net.URI

fun <T : HttpClientOptions> T.setDefaultsFrom(uri: URI): T {
isSsl = uri.scheme.lowercase() == "https"
defaultHost = uri.host
defaultPort = uri.getPortWithSchemeDefaults()

return this
}
2 changes: 1 addition & 1 deletion jvm-libs/linea/blob-compressor/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ apply from: rootProject.file("gradle/publishing.gradle")

dependencies {
implementation "net.java.dev.jna:jna:${libs.versions.jna.get()}"
testImplementation project(":jvm-libs:generic:extensions:kotlin")
implementation project(":jvm-libs:generic:extensions:kotlin")
testImplementation project(":jvm-libs:linea:blob-shnarf-calculator")
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package net.consensys.linea.blob

import build.linea.jvm.ResourcesUtil.copyResourceToTmpDir
import com.sun.jna.Library
import com.sun.jna.Native
import net.consensys.jvm.ResourcesUtil.copyResourceToTmpDir

interface GoNativeBlobCompressor {

Expand Down
Binary file not shown.
59 changes: 59 additions & 0 deletions jvm-libs/linea/blob-decompressor/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
plugins {
id 'net.consensys.zkevm.kotlin-library-conventions'
id 'net.consensys.zkevm.linea-native-libs-helper'
alias(libs.plugins.jreleaser)
id 'java-test-fixtures'
}

description = 'Java JNA wrapper for Linea Blob Decompressor Library implemented in GO Lang'
apply from: rootProject.file("gradle/publishing.gradle")

dependencies {
implementation "net.java.dev.jna:jna:${libs.versions.jna.get()}"
implementation project(":jvm-libs:generic:extensions:kotlin")

testImplementation project(":jvm-libs:linea:blob-compressor")
testImplementation(testFixtures(project(":jvm-libs:linea:blob-compressor")))
testImplementation(project(":jvm-libs:linea:testing:file-system"))
testImplementation("io.tmio:tuweni-bytes:${libs.versions.tuweni.get()}")
testImplementation("org.hyperledger.besu:besu-datatypes:${libs.versions.besu.get()}")
testImplementation "org.hyperledger.besu:evm:${libs.versions.besu.get()}"
testImplementation("org.hyperledger.besu.internal:core:${libs.versions.besu.get()}")
testImplementation("org.hyperledger.besu:plugin-api:${libs.versions.besu.get()}")
testImplementation("org.hyperledger.besu.internal:rlp:${libs.versions.besu.get()}")
}

jar {
dependsOn configurations.runtimeClasspath
}

test {
// we cannot have more 1 compressor per JVM, hence we disable parallel execution
// because multiple threads would cause issues with the native library
systemProperties["junit.jupiter.execution.parallel.enabled"] = false
maxParallelForks = 1
}

def libsZipDownloadOutputDir = project.parent.layout.buildDirectory.asFile.get().absolutePath

task downloadNativeLibs {
doLast {
fetchLibFromZip("https://github.com/Consensys/linea-monorepo/releases/download/blob-libs-v1.1.0-test8/linea-blob-libs-v1.1.0-test8.zip", "blob_decompressor", libsZipDownloadOutputDir)
}
}

compileKotlin {
dependsOn tasks.downloadNativeLibs
}

task cleanResources(type: Delete) {
fileTree(project.layout.projectDirectory.dir('src/main/resources'))
.filter {
it.name.endsWith(".so") || it.name.endsWith(".dll") || it.name.endsWith(".dylib")
}.each {
println("Deleting: ${it}")
delete it
}
}

clean.dependsOn cleanResources
Loading

0 comments on commit ecfe183

Please sign in to comment.