Skip to content

Commit

Permalink
Choose an execution client in tests
Browse files Browse the repository at this point in the history
  • Loading branch information
vsuharnikov committed Nov 14, 2024
1 parent 4b4ae86 commit 1229157
Show file tree
Hide file tree
Showing 8 changed files with 152 additions and 53 deletions.
18 changes: 11 additions & 7 deletions consensus-client-it/src/test/scala/units/BaseDockerTestSuite.scala
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@ import units.BaseDockerTestSuite.generateWavesGenesisConfig
import units.client.HttpChainContractClient
import units.client.contract.HasConsensusLayerDappTxHelpers
import units.client.engine.model.BlockNumber
import units.docker.{EcContainer, Networks, WavesNodeContainer}
import units.docker.*
import units.el.ElBridgeClient
import units.eth.Gwei
import units.test.TestEnvironment.*
import units.test.{CustomMatchers, HasRetry}
import units.test.{CustomMatchers, HasRetry, TestEnvironment}

import java.io.PrintStream
import java.nio.file.{Files, Path}
Expand All @@ -46,11 +46,15 @@ trait BaseDockerTestSuite

private implicit val httpClientBackend: SttpBackend[Identity, Any] = HttpClientSyncBackend()

protected lazy val ec1: EcContainer = new EcContainer(
network = network,
number = 1,
ip = Networks.ipForNode(2) // ipForNode(1) is assigned to Ryuk
)
protected lazy val ec1: EcContainer = {
val constructor = TestEnvironment.ExecutionClient match {
case "besu" => new BesuContainer(_, _, _)
case "geth" => new GethContainer(_, _, _)
case x => throw new RuntimeException(s"Unknown execution client: $x. Only 'geth' or 'besu' supported")
}

constructor(network, 1, Networks.ipForNode(2) /* ipForNode(1) is assigned to Ryuk */ )
}

protected lazy val waves1: WavesNodeContainer = new WavesNodeContainer(
network = network,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import org.web3j.protocol.core.DefaultBlockParameter
import org.web3j.protocol.core.methods.response.{EthSendTransaction, TransactionReceipt}
import org.web3j.tx.gas.DefaultGasProvider
import org.web3j.utils.Convert
import units.docker.EcContainer

import java.math.BigInteger

Expand Down Expand Up @@ -65,11 +66,13 @@ class SyncingTestSuite extends BaseDockerTestSuite {

private def sendTxn(nonce: Long): EthSendTransaction = {
val rawTransaction = RawTransaction.createEtherTransaction(
EcContainer.ChainId,
BigInteger.valueOf(nonce),
DefaultGasProvider.GAS_PRICE,
DefaultGasProvider.GAS_LIMIT,
"0x0000000000000000000000000000000000000000",
amount
amount,
BigInteger.ZERO,
DefaultGasProvider.GAS_PRICE
)
val signedTransaction = EthEncoding.toHexString(TransactionEncoder.signMessage(rawTransaction, elSender))
ec1.web3j.ethSendRawTransaction(signedTransaction).send()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package units.docker

import org.testcontainers.containers.BindMode
import org.testcontainers.containers.Network.NetworkImpl
import org.web3j.protocol.Web3j
import org.web3j.protocol.http.HttpService
import sttp.client3.{Identity, SttpBackend}
import units.client.JsonRpcClient
import units.client.engine.{EngineApiClient, HttpEngineApiClient, LoggedEngineApiClient}
import units.docker.EcContainer.{EnginePort, RpcPort}
import units.http.OkHttpLogger
import units.test.TestEnvironment.ConfigsDir

import scala.concurrent.duration.DurationInt

class BesuContainer(network: NetworkImpl, number: Int, ip: String)(implicit httpClientBackend: SttpBackend[Identity, Any])
extends EcContainer(number) {
protected override val container = new GenericContainer(DockerImages.BesuExecutionClient)
.withNetwork(network)
.withExposedPorts(RpcPort, EnginePort)
.withEnv("LOG4J_CONFIGURATION_FILE", "/config/log4j2.xml")
.withEnv("ROOT_LOG_FILE_LEVEL", "TRACE")
.withFileSystemBind(s"$ConfigsDir/ec-common/genesis.json", "/genesis.json", BindMode.READ_ONLY)
.withFileSystemBind(s"$ConfigsDir/besu", "/config", BindMode.READ_ONLY)
.withFileSystemBind(s"$ConfigsDir/besu/run-besu.sh", "/tmp/run.sh", BindMode.READ_ONLY)
.withFileSystemBind(s"$ConfigsDir/ec-common/p2p-key-$number.hex", "/etc/secrets/p2p-key", BindMode.READ_ONLY)
.withFileSystemBind(s"$logFile", "/opt/besu/logs/besu.log", BindMode.READ_WRITE)
.withCreateContainerCmdModifier { cmd =>
cmd
.withName(s"${network.getName}-$hostName")
.withHostName(hostName)
.withIpv4Address(ip)
.withEntrypoint("/tmp/run.sh")
.withStopTimeout(5)
}

override lazy val engineApi: EngineApiClient = new LoggedEngineApiClient(
new HttpEngineApiClient(
JsonRpcClient.Config(apiUrl = s"http://${container.getHost}:$enginePort", apiRequestRetries = 5, apiRequestRetryWaitTime = 1.second),
httpClientBackend
)
)

override lazy val web3j = Web3j.build(
new HttpService(
s"http://${container.getHost}:$rpcPort",
HttpService.getOkHttpClientBuilder
.addInterceptor(OkHttpLogger)
.build()
)
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import org.testcontainers.utility.DockerImageName.parse
import units.test.TestEnvironment.WavesDockerImage

object DockerImages {
val WavesNode = parse(WavesDockerImage)
val ExecutionClient = parse("hyperledger/besu:latest")
val WavesNode = parse(WavesDockerImage)
val BesuExecutionClient = parse("hyperledger/besu:latest")
val GethExecutionClient = parse("ethereum/client-go:stable")
}
51 changes: 10 additions & 41 deletions consensus-client-it/src/test/scala/units/docker/EcContainer.scala
Original file line number Diff line number Diff line change
@@ -1,63 +1,31 @@
package units.docker

import com.google.common.io.Files
import org.testcontainers.containers.BindMode
import org.testcontainers.containers.Network.NetworkImpl
import org.web3j.protocol.Web3j
import org.web3j.protocol.http.HttpService
import sttp.client3.{Identity, SttpBackend}
import units.client.JsonRpcClient
import units.client.engine.{HttpEngineApiClient, LoggedEngineApiClient}
import units.client.engine.EngineApiClient
import units.docker.EcContainer.{EnginePort, RpcPort}
import units.http.OkHttpLogger
import units.test.TestEnvironment.*

import java.io.File
import scala.concurrent.duration.DurationInt

class EcContainer(network: NetworkImpl, number: Int, ip: String)(implicit httpClientBackend: SttpBackend[Identity, Any])
extends BaseContainer(s"ec-$number") {
private val logFile = new File(s"$DefaultLogsDir/besu-$number.log")
abstract class EcContainer(number: Int) extends BaseContainer(s"ec-$number") {
protected val logFile = new File(s"$DefaultLogsDir/ec-$number.log")
Files.touch(logFile)

protected override val container = new GenericContainer(DockerImages.ExecutionClient)
.withNetwork(network)
.withExposedPorts(RpcPort, EnginePort)
.withEnv("LOG4J_CONFIGURATION_FILE", "/config/log4j2.xml")
.withEnv("ROOT_LOG_FILE_LEVEL", "TRACE")
.withFileSystemBind(s"$ConfigsDir/ec-common/genesis.json", "/genesis.json", BindMode.READ_ONLY)
.withFileSystemBind(s"$ConfigsDir/besu", "/config", BindMode.READ_ONLY)
.withFileSystemBind(s"$ConfigsDir/besu/run-besu.sh", "/tmp/run.sh", BindMode.READ_ONLY)
.withFileSystemBind(s"$ConfigsDir/ec-common/p2p-key-$number.hex", "/etc/secrets/p2p-key", BindMode.READ_ONLY)
.withFileSystemBind(s"$logFile", "/opt/besu/logs/besu.log", BindMode.READ_WRITE)
.withCreateContainerCmdModifier { cmd =>
cmd
.withName(s"${network.getName}-$hostName")
.withHostName(hostName)
.withIpv4Address(ip)
.withEntrypoint("/tmp/run.sh")
.withStopTimeout(5)
}

lazy val rpcPort = container.getMappedPort(RpcPort)
lazy val enginePort = container.getMappedPort(EnginePort)

lazy val engineApiDockerUrl = s"http://$hostName:${EcContainer.EnginePort}"
lazy val engineApi = new LoggedEngineApiClient(
new HttpEngineApiClient(
JsonRpcClient.Config(apiUrl = s"http://${container.getHost}:$enginePort", apiRequestRetries = 5, apiRequestRetryWaitTime = 1.second),
httpClientBackend
)
lazy val engineApiConfig = JsonRpcClient.Config(
apiUrl = s"http://${container.getHost}:$enginePort",
apiRequestRetries = 5,
apiRequestRetryWaitTime = 1.second
)

lazy val web3j = Web3j.build(
new HttpService(
s"http://${container.getHost}:$rpcPort",
HttpService.getOkHttpClientBuilder
.addInterceptor(OkHttpLogger)
.build()
)
)
def engineApi: EngineApiClient
def web3j: Web3j

override def stop(): Unit = {
web3j.shutdown()
Expand All @@ -70,4 +38,5 @@ class EcContainer(network: NetworkImpl, number: Int, ip: String)(implicit httpCl
object EcContainer {
val RpcPort = 8545
val EnginePort = 8551
val ChainId = 1337L // from genesis.json
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package units.docker

import okhttp3.Interceptor
import org.testcontainers.containers.BindMode
import org.testcontainers.containers.Network.NetworkImpl
import org.web3j.protocol.Web3j
import org.web3j.protocol.http.HttpService
import pdi.jwt.{JwtAlgorithm, JwtClaim, JwtJson}
import sttp.client3.{Identity, SttpBackend}
import units.client.JwtAuthenticationBackend
import units.client.engine.{EngineApiClient, HttpEngineApiClient, LoggedEngineApiClient}
import units.docker.EcContainer.{EnginePort, RpcPort}
import units.http.OkHttpLogger
import units.test.TestEnvironment.ConfigsDir

import java.time.Clock
import scala.io.Source

class GethContainer(network: NetworkImpl, number: Int, ip: String)(implicit httpClientBackend: SttpBackend[Identity, Any])
extends EcContainer(number) {
protected override val container = new GenericContainer(DockerImages.GethExecutionClient)
.withNetwork(network)
.withExposedPorts(RpcPort, EnginePort)
.withFileSystemBind(s"$ConfigsDir/ec-common/genesis.json", "/tmp/genesis.json", BindMode.READ_ONLY)
.withFileSystemBind(s"$ConfigsDir/geth/run-geth.sh", "/tmp/run.sh", BindMode.READ_ONLY)
.withFileSystemBind(s"$ConfigsDir/ec-common/p2p-key-$number.hex", "/etc/secrets/p2p-key", BindMode.READ_ONLY)
.withFileSystemBind(s"$ConfigsDir/ec-common/jwt-secret-$number.hex", "/etc/secrets/jwtsecret", BindMode.READ_ONLY)
.withFileSystemBind(s"$logFile", "/root/logs/log", BindMode.READ_WRITE)
.withCreateContainerCmdModifier { cmd =>
cmd
.withName(s"${network.getName}-$hostName")
.withHostName(hostName)
.withIpv4Address(ip)
.withEntrypoint("/tmp/run.sh")
.withStopTimeout(5)
}

lazy val jwtSecretKey = {
val src = Source.fromFile(s"$ConfigsDir/ec-common/jwt-secret-$number.hex")
try src.getLines().next()
finally src.close()
}

override lazy val engineApi: EngineApiClient = new LoggedEngineApiClient(
new HttpEngineApiClient(
engineApiConfig,
new JwtAuthenticationBackend(jwtSecretKey, httpClientBackend)
)
)

override lazy val web3j = Web3j.build(
new HttpService(
s"http://${container.getHost}:$rpcPort",
HttpService.getOkHttpClientBuilder
.addInterceptor { (chain: Interceptor.Chain) =>
val orig = chain.request()
val jwtToken = JwtJson.encode(JwtClaim().issuedNow(Clock.systemUTC), jwtSecretKey, JwtAlgorithm.HS256)
val request = orig
.newBuilder()
.header("Authorization", s"Bearer $jwtToken")
.build()

chain.proceed(request)
}
.addInterceptor(OkHttpLogger)
.build()
)
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,6 @@ object OkHttpLogger extends Interceptor with ScorexLogging {
val source = body.source()
source.request(Long.MaxValue) // Buffer the entire body.
val buffer = source.getBuffer.clone()
buffer.readUtf8()
buffer.readUtf8().trim
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@ object TestEnvironment {
Files.createDirectories(DefaultLogsDir)

val WavesDockerImage: String = System.getProperty("cc.it.docker.image")
val ExecutionClient: String = System.getProperty("cc.it.ec", "besu") // | geth
}

0 comments on commit 1229157

Please sign in to comment.