Skip to content

Commit

Permalink
fixed ride-runner tests
Browse files Browse the repository at this point in the history
  • Loading branch information
phearnot committed Jan 31, 2025
1 parent a70f1a8 commit ad34161
Show file tree
Hide file tree
Showing 30 changed files with 186 additions and 149 deletions.
24 changes: 11 additions & 13 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,7 @@ lazy val `node-tests` = project
lazy val `grpc-server` =
project.dependsOn(node % "compile;runtime->provided", `node-testkit`, `node-tests` % "test->test")

// TODO: [scala3] enable
// lazy val `ride-runner` = project.dependsOn(node, `grpc-server`, `node-tests` % "test->test")
lazy val `ride-runner` = project.dependsOn(node, `grpc-server`, `node-tests` % "test->test")
lazy val `node-it` = project.dependsOn(`repl-jvm`, `grpc-server`, `lang-testkit` % "test->test", `node-testkit`)

lazy val `node-generator` = project.dependsOn(node, `node-testkit`, `node-testkit`)
Expand Down Expand Up @@ -144,7 +143,7 @@ lazy val `waves-node` = (project in file("."))
`node-tests`,
`node-generator`,
benchmark,
// `ride-runner` // TODO: [scala3] enable
`ride-runner`
)

inScope(Global)(
Expand Down Expand Up @@ -199,7 +198,7 @@ inScope(Global)(
lazy val packageAll = taskKey[Unit]("Package all artifacts")
packageAll := {
(node / assembly).value
// (`ride-runner` / assembly).value // TODO: [scala3] enable
(`ride-runner` / assembly).value
buildDebPackages.value
buildTarballsForDocker.value
}
Expand All @@ -216,14 +215,13 @@ buildTarballsForDocker := {
)
}

// TODO: [scala3] enable
// lazy val buildRIDERunnerForDocker = taskKey[Unit]("Package RIDE Runner tarball and copy it to docker/target")
// buildRIDERunnerForDocker := {
// IO.copyFile(
// (`ride-runner` / Universal / packageZipTarball).value,
// (`ride-runner` / baseDirectory).value / "docker" / "target" / s"${(`ride-runner` / name).value}.tgz"
// )
// }
lazy val buildRIDERunnerForDocker = taskKey[Unit]("Package RIDE Runner tarball and copy it to docker/target")
buildRIDERunnerForDocker := {
IO.copyFile(
(`ride-runner` / Universal / packageZipTarball).value,
(`ride-runner` / baseDirectory).value / "docker" / "target" / s"${(`ride-runner` / name).value}.tgz"
)
}

lazy val checkPRRaw = taskKey[Unit]("Build a project and run unit tests")
checkPRRaw := Def
Expand All @@ -240,7 +238,7 @@ checkPRRaw := Def
(`node-it` / Test / compile).value
(benchmark / Test / compile).value
(`node-generator` / Compile / compile).value
// (`ride-runner` / Test / compile).value // TODO: [scala3] enable
(`ride-runner` / Test / test).value
}
)
.value
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import com.wavesplatform.lang.v1.traits.Environment
import com.wavesplatform.lang.*
import monix.eval.Coeval

import java.io.{PrintWriter, StringWriter}
import scala.annotation.tailrec
import scala.collection.mutable.ListBuffer

Expand Down Expand Up @@ -128,7 +129,9 @@ class EvaluatorV2(
case null => e.toString
case msg => msg
}
Coeval(Left((CommonError(s"""An error during run ${function.ev}: ${e.getClass} $error"""), 0)))
val sw = new StringWriter()
e.printStackTrace(new PrintWriter(sw))
Coeval(Left((CommonError(s"""An error during run ${function.ev}: ${e.getClass} $error ${sw.toString}"""), 0)))
}
)
_ <- update(result)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -336,7 +336,7 @@ object BlockchainSettings {
def fromRootConfig(config: Config): BlockchainSettings =
ConfigSource.fromConfig(config).at("waves.blockchain").loadOrThrow[BlockchainSettings]

implicit val configReader: ConfigReader[BlockchainSettings] = ConfigReader.fromCursor(cur =>
given ConfigReader[BlockchainSettings] = ConfigReader.fromCursor(cur =>
for {
objCur <- cur.asObjectCursor
blockchainTypeString <- objCur.atKey("type").flatMap(_.asString).map(_.toUpperCase)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import com.wavesplatform.api.RideMulticastHttpApi.{AskResult, AskServerResponse,
import com.wavesplatform.utils.ScorexLogging
import monix.eval.Task
import play.api.libs.json.{JsObject, Json}
import pureconfig.ConfigReader
import sttp.client3.*

import scala.concurrent.duration.{Duration, DurationLong, FiniteDuration}
Expand Down Expand Up @@ -38,7 +39,7 @@ class RideMulticastHttpApi(settings: Settings, httpBackend: SttpBackend[Identity
}

object RideMulticastHttpApi {
case class Settings(rideRunnerApiBaseUri: String, nodeApiBaseUri: String)
case class Settings(rideRunnerApiBaseUri: String, nodeApiBaseUri: String) derives ConfigReader

case class AskResult(rideRunner: AskServerResponse, node: AskServerResponse) {
def timeDiff: FiniteDuration = (node.time - rideRunner.time).toCoarsest
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,12 +87,7 @@ class ImmutableBlockchain(override val settings: BlockchainSettings, input: Ride

// Ride: blockInfoByHeight, lastBlock
override def blockHeader(height: Int): Option[SignedBlockHeader] =
// Dirty, but we have a clear error instead of "None.get"
blockHeaders
.get(height)
.tap { r =>
if (r.isEmpty) throw new RuntimeException(s"blockHeader($height): can't find a block header, please specify or check your script")
}
blockHeaders.get(height)

// Ride: blockInfoByHeight
override def hitSource(height: Int): Option[ByteStr] = input.blocks.get(height).flatMap(_.VRF)
Expand Down Expand Up @@ -197,7 +192,7 @@ class ImmutableBlockchain(override val settings: BlockchainSettings, input: Ride

override def wavesBalances(addresses: Seq[Address]): Map[Address, Long] = ???

override def effectiveBalanceBanHeights(address: Address): Seq[Int] = ???
override def effectiveBalanceBanHeights(address: Address): Seq[Int] = Seq.empty

override def lastStateHash(refId: Option[BlockId]): BlockId = ???

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -281,19 +281,19 @@ class LazyBlockchain[TagT] private (
affected
}

private def updateCacheIfExists[CacheKeyT <: MemCacheKey](key: CacheKeyT)(v: RemoteData[CacheKeyT#ValueT]): AffectedTags[TagT] = {
private def updateCacheIfExists[V, K <: MemCacheKey[V]](key: K)(v: RemoteData[V]): AffectedTags[TagT] = {
getAffectedTags(key).tap { tags =>
if (tags.isEmpty) memCache.updateIfExists(key, v) // Not yet removed from memCache, but already removed from tags
else memCache.set(key, v)
}
}

private def removeCache[CacheKeyT <: MemCacheKey](key: CacheKeyT): AffectedTags[TagT] = {
private def removeCache[K <: MemCacheKey[?]](key: K): AffectedTags[TagT] = {
memCache.remove(key)
getAffectedTags(key)
}

private def getAffectedTags(key: MemCacheKey): AffectedTags[TagT] = allTags.get(key).getOrElse(AffectedTags.empty)
private def getAffectedTags(key: MemCacheKey[?]): AffectedTags[TagT] = allTags.get(key).getOrElse(AffectedTags.empty)

private def append(atHeight: Height, evt: BlockchainUpdated.Append)(implicit ctx: ReadWrite): AffectedTags[TagT] = {
val (initialAffectedTags, txs, timer) = evt.body match {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,20 +12,20 @@ class CacheKeyTags[TagT] {
// not exist - we don't known this key
// exist, but empty - we known this key, but doesn't remember why
// exist and non-empty - we know, why do we need this key (but there are probably more tags)
private val allTags = new ConcurrentHashMap[MemCacheKey, Tags]()
private val allTags = new ConcurrentHashMap[MemCacheKey[?], Tags]()

def get(key: MemCacheKey): Option[Tags] = Option(allTags.get(key))
def get(key: MemCacheKey[?]): Option[Tags] = Option(allTags.get(key))

def addDependent(key: MemCacheKey, tag: TagT): Unit = allTags.compute(key, (_, origTags) => Option(origTags).getOrElse(Set.empty) + tag)
def addDependent(key: MemCacheKey[?], tag: TagT): Unit = allTags.compute(key, (_, origTags) => Option(origTags).getOrElse(Set.empty) + tag)

def removeTags(xs: collection.Set[TagT]): Unit = {
allTags.replaceAll { (_: MemCacheKey, orig: Tags) =>
allTags.replaceAll { (_: MemCacheKey[?], orig: Tags) =>
if (orig.size >= xs.size) orig -- xs
else orig.diff(xs)
}

// Use removeIf to remove empty keys in JRE 17
val emptyKeys = allTags.reduceEntries[Seq[MemCacheKey]](
val emptyKeys = allTags.reduceEntries[Seq[MemCacheKey[?]]](
4, // parallelismThreshold
entry => if (entry.getValue.isEmpty) Seq(entry.getKey) else Seq.empty,
_ ++ _
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,36 +5,35 @@ import com.typesafe.config.ConfigMemorySize
import com.wavesplatform.ride.runner.caches.RemoteData
import com.wavesplatform.ride.runner.caches.mem.MemBlockchainDataCache.Settings
import com.wavesplatform.ride.runner.stats.KamonCaffeineStats
import org.github.jamm.MemoryMeter
import pureconfig.ConfigReader

class MemBlockchainDataCache(settings: Settings) {
private val mmeter = MemoryMeter.builder().build()
private val backend = Caffeine
.newBuilder()
.softValues()
.maximumWeight(settings.size.toBytes)
.recordStats(() => new KamonCaffeineStats("Common"))
.weigher { (key: MemCacheKey, value: RemoteData[Any]) =>
val v = value.mayBeValue.map(_.asInstanceOf[key.ValueT])
key.keyWeight + v.fold(0) { v =>
MemCacheWeights.OfCachedRemoteDataOverhead + key.valueWeight(v)
}
.weigher { (key: MemCacheKey[?], value: RemoteData[Any]) =>
(mmeter.measure(key) + mmeter.measure(value)).toInt
}
.build[MemCacheKey, RemoteData[Any]]()
.build[MemCacheKey[?], RemoteData[Any]]()

def get[T <: MemCacheKey](key: T): RemoteData[T#ValueT] =
Option(backend.getIfPresent(key)).getOrElse(RemoteData.Unknown).asInstanceOf[RemoteData[T#ValueT]]
def get[V, K <: MemCacheKey[V]](key: K): RemoteData[V] =
Option(backend.getIfPresent(key)).getOrElse(RemoteData.Unknown).asInstanceOf[RemoteData[V]]

def getOrLoad[T <: MemCacheKey](key: T)(load: T => RemoteData[T#ValueT]): RemoteData[T#ValueT] =
backend.get(key, _ => load(key)).asInstanceOf[RemoteData[T#ValueT]]
def getOrLoad[V, K <: MemCacheKey[V]](key: K)(load: K => RemoteData[V]): RemoteData[V] =
backend.get(key, _ => load(key)).asInstanceOf[RemoteData[V]]

def set[T <: MemCacheKey, V](key: T, value: RemoteData[V])(implicit ev: V =:= T#ValueT): Unit = backend.put(key, value)
def set[V, K <: MemCacheKey[V]](key: K, value: RemoteData[V]): Unit = backend.put(key, value)

def updateIfExists[T <: MemCacheKey, V](key: T, newValue: RemoteData[V])(implicit ev: V =:= T#ValueT): Unit =
def updateIfExists[V, K <: MemCacheKey[V]](key: K, newValue: RemoteData[V]): Unit =
Option(backend.policy().getEntryIfPresentQuietly(key)).foreach { _ =>
backend.put(key, newValue)
}

def remove[T <: MemCacheKey](key: T): Unit = backend.invalidate(key)
def remove[K <: MemCacheKey[?]](key: K): Unit = backend.invalidate(key)
}

object MemBlockchainDataCache {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,77 +4,36 @@ import com.google.protobuf.ByteString
import com.wavesplatform.account.{Address, Alias}
import com.wavesplatform.common.state.ByteStr
import com.wavesplatform.common.utils.EitherExt2
import com.wavesplatform.common.utils.EitherExt2.explicitGet
import com.wavesplatform.events.protobuf.StateUpdate
import com.wavesplatform.protobuf.{ByteStringExt, transaction as pb}
import com.wavesplatform.protobuf.transaction.PBAmounts.toAssetAndAmount
import com.wavesplatform.protobuf.transaction.PBTransactions.{toVanillaDataEntry, toVanillaScript}
import com.wavesplatform.protobuf.transaction.{CreateAliasTransactionData, Transaction}
import com.wavesplatform.protobuf.{ByteStringExt, transaction as pb}
import com.wavesplatform.ride.runner.caches.{WeighedAccountScriptInfo, WeighedAssetDescription}
import com.wavesplatform.state.{AssetDescription, AssetScriptInfo, DataEntry, Height, LeaseBalance, TransactionId}
import com.wavesplatform.transaction.Asset.IssuedAsset
import com.wavesplatform.utils.StringBytes
import com.wavesplatform.{account, state, transaction}
import com.wavesplatform.common.utils.EitherExt2.explicitGet

sealed trait MemCacheKey extends Product with Serializable {
type ValueT
def keyWeight: Int
def valueWeight(value: ValueT): Int
}
sealed trait MemCacheKey[ValueT]

object MemCacheKey {
case class AccountData(address: Address, dataKey: String) extends MemCacheKey {
override type ValueT = DataEntry[?]
// 24 = 12 (header) + 4 (ref) + 4 (ref) + 4 (align)
override def keyWeight: Int = 24 + MemCacheWeights.OfAddress + MemCacheWeights.ofAsciiString(dataKey)
override def valueWeight(value: DataEntry[?]): Int = MemCacheWeights.ofDataEntry(value)
}
case class AccountData(address: Address, dataKey: String) extends MemCacheKey[DataEntry[?]]

case class Transaction(id: TransactionId) extends MemCacheKey {
override type ValueT = state.Height
override def keyWeight: Int = 16 + MemCacheWeights.OfTransactionId // 16 = 12 (header) + 4 (ref) + id
override def valueWeight(value: Height): Int = 16 // 12 (header) + 4 (int value)
}
case class Transaction(id: TransactionId) extends MemCacheKey[state.Height]

case object Height extends MemCacheKey {
override type ValueT = state.Height
override def keyWeight: Int = 0
override def valueWeight(value: Height): Int = 16 // 12 (header) + 4 (int value)
}
case object Height extends MemCacheKey[state.Height]

case class Alias(alias: account.Alias) extends MemCacheKey {
override type ValueT = Address
override def keyWeight: Int = 16 + MemCacheWeights.ofAlias(alias) // 16 = 12 (header) + 4 (ref) + alias
override def valueWeight(value: Address): Int = MemCacheWeights.OfAddress
}
case class Alias(alias: account.Alias) extends MemCacheKey[Address]

case class Asset(asset: IssuedAsset) extends MemCacheKey {
override type ValueT = WeighedAssetDescription
override def keyWeight: Int = MemCacheWeights.OfIssuedAsset
override def valueWeight(value: WeighedAssetDescription): Int = MemCacheWeights.ofWeighedAssetDescription(value)
}
case class Asset(asset: IssuedAsset) extends MemCacheKey[WeighedAssetDescription]

case class AccountBalance(address: Address, asset: transaction.Asset) extends MemCacheKey {
override type ValueT = Long
// 24 = 12 (header) + 4*2 (ref: address, asset) + 4 (align)
override def keyWeight: Int = 24 + MemCacheWeights.OfAddress + MemCacheWeights.ofAsset(asset)
override def valueWeight(value: Long): Int = 8
}
case class AccountBalance(address: Address, asset: transaction.Asset) extends MemCacheKey[Long]

case class AccountLeaseBalance(address: Address) extends MemCacheKey {
override type ValueT = LeaseBalance
// 16 = 12 (header) + 4 (ref)
override def keyWeight: Int = 16 + MemCacheWeights.OfAddress
override def valueWeight(value: LeaseBalance): Int = MemCacheWeights.OfLeaseBalance
}
case class AccountLeaseBalance(address: Address) extends MemCacheKey[LeaseBalance]

case class AccountScript(address: Address) extends MemCacheKey {
override type ValueT = WeighedAccountScriptInfo
// 16 = 12 (header) + 4 (ref)
override def keyWeight: Int = 16 + MemCacheWeights.OfAddress
// 24 = 12 (header) + 4 (size) + 4 (ref: scriptInfo) + 4 (align)
override def valueWeight(value: WeighedAccountScriptInfo): Int = 24 + value.scriptInfoWeight
}
case class AccountScript(address: Address) extends MemCacheKey[WeighedAccountScriptInfo]
}

class GrpcCacheKeyConverters(chainId: Byte) {
Expand All @@ -83,10 +42,10 @@ class GrpcCacheKeyConverters(chainId: Byte) {
MemCacheKey.AccountData(update.address.toAddress(chainId), dataKey)
}

def accountDataValueBefore(update: StateUpdate.DataEntryUpdate): Option[MemCacheKey.AccountData#ValueT] =
def accountDataValueBefore(update: StateUpdate.DataEntryUpdate): Option[DataEntry[?]] =
update.dataEntryBefore.map(accountDataValue)
def accountDataValueAfter(update: StateUpdate.DataEntryUpdate): Option[MemCacheKey.AccountData#ValueT] = update.dataEntry.map(accountDataValue)
def accountDataValue(dataEntry: pb.DataEntry): MemCacheKey.AccountData#ValueT = toVanillaDataEntry(dataEntry)
def accountDataValueAfter(update: StateUpdate.DataEntryUpdate): Option[DataEntry[?]] = update.dataEntry.map(accountDataValue)
def accountDataValue(dataEntry: pb.DataEntry): DataEntry[?] = toVanillaDataEntry(dataEntry)

def transactionIdKey(id: ByteString): MemCacheKey.Transaction = MemCacheKey.Transaction(TransactionId(ByteStr(id.toByteArray)))

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,10 @@ trait ReadOnly {
}

def getRemoteDataOpt[T](key: Key[Option[T]]): RemoteData[T] = RemoteData(getOpt(key))


def readFromDb[K, V](k: K, kvHistoryPair: KvHistoryPair[K, V], maxHeight: Height)(implicit @unused ev: V =:!= Option[?]): RemoteData[V] =
readFromDbRaw(k, kvHistoryPair, maxHeight).fold(RemoteData.unknown[V])(RemoteData.Cached(_))

def readFromDb[K, V](k: K, kvHistoryPair: KvHistoryPair[K, Option[V]], maxHeight: Height): RemoteData[V] =
readFromDbRaw(k, kvHistoryPair, maxHeight).fold(RemoteData.unknown[V])(RemoteData.loaded)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ trait ReadWrite extends ReadOnly {
k: K,
kvHistoryPair: KvHistoryPair[K, V],
fromHeight: Height
): RemoteData[V] =
)(implicit @unused ev: V =:!= Option[?]): RemoteData[V] =
RemoteData.cachedOrUnknown(removeFromAndGetLatestExistedBase(k, kvHistoryPair, fromHeight))

def removeFromAndGetLatestExisted[K, V](k: K, kvHistoryPair: KvHistoryPair[K, Option[V]], fromHeight: Height): RemoteData[V] =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,19 @@ import org.rocksdb.*
import scala.util.Using

trait RideDbAccess {
def batchedReadOnly[T](f: ReadOnly => T): T
def batchedReadWrite[T](f: ReadWrite => T): T
def batchedReadOnly[T](f: ReadOnly => T)(implicit ev: T <:!< Task[?]): T
def batchedReadWrite[T](f: ReadWrite => T)(implicit ev: T <:!< Task[?]): T
def directReadOnly[T](f: ReadOnly => T): T
def directReadWrite[T](f: ReadWrite => T): T
}

object RideDbAccess {
def fromRocksDb(db: RocksDB): RideDbAccess = new RideDbAccess with ScorexLogging {
override def batchedReadOnly[T](f: ReadOnly => T): T = withReadOptions { ro =>
override def batchedReadOnly[T](f: ReadOnly => T)(implicit ev: T <:!< Task[?]): T = withReadOptions { ro =>
f(new BatchedReadOnly(db, ro))
}

override def batchedReadWrite[T](f: ReadWrite => T): T = withReadOptions { ro =>
override def batchedReadWrite[T](f: ReadWrite => T)(implicit ev: T <:!< Task[?]): T = withReadOptions { ro =>
Using.resource(mkWriteOptions()) { wo =>
Using.resource(SynchronizedWriteBatch()) { wb =>
val r = f(new BatchedReadWrite(db, ro, wb))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,13 @@ package com.wavesplatform.ride.runner

import com.wavesplatform.state.Height

import scala.annotation.targetName
import scala.util.NotGiven

package object db {
type Heights = Vector[Height]
val EmptyHeights: Heights = Vector.empty

type =:!=[A, B] = NotGiven[A =:= B]
type <:!<[A, B] = NotGiven[A <:< B]
}
Loading

0 comments on commit ad34161

Please sign in to comment.