From 82e9a3fbfc882e4b7ec812773b094dadb5ca936b Mon Sep 17 00:00:00 2001 From: Artyom Sayadyan Date: Wed, 20 Sep 2023 23:27:34 +0300 Subject: [PATCH 1/5] NODE-2613 RIDE calculateDelay() --- .../v1/EnvironmentFunctionsBenchmark.scala | 2 + .../state/CalculateDelayBenchmark.scala | 43 ++++++++++++ lang/doc/v8/funcs/blockchain-functions.hjson | 7 ++ .../wavesplatform/lang/utils/package.scala | 1 + .../lang/v1/evaluator/FunctionIds.scala | 3 +- .../evaluator/ctx/impl/waves/Functions.scala | 43 +++++++++++- .../ctx/impl/waves/WavesContext.scala | 13 ++-- .../lang/v1/traits/Environment.scala | 1 + .../scala/com/wavesplatform/lang/Common.scala | 47 +++++++------ .../consensus/PoSCalculator.scala | 4 +- .../transaction/smart/WavesEnvironment.scala | 8 ++- .../smart/predef/CalculateDelayTest.scala | 70 +++++++++++++++++++ 12 files changed, 207 insertions(+), 35 deletions(-) create mode 100644 benchmark/src/test/scala/com/wavesplatform/state/CalculateDelayBenchmark.scala create mode 100644 node/src/test/scala/com/wavesplatform/state/diffs/smart/predef/CalculateDelayTest.scala diff --git a/benchmark/src/test/scala/com/wavesplatform/lang/v1/EnvironmentFunctionsBenchmark.scala b/benchmark/src/test/scala/com/wavesplatform/lang/v1/EnvironmentFunctionsBenchmark.scala index 12f86e74549..4857c4d4c81 100644 --- a/benchmark/src/test/scala/com/wavesplatform/lang/v1/EnvironmentFunctionsBenchmark.scala +++ b/benchmark/src/test/scala/com/wavesplatform/lang/v1/EnvironmentFunctionsBenchmark.scala @@ -132,6 +132,8 @@ object EnvironmentFunctionsBenchmark { override def accountScript(addressOrAlias: Recipient): Option[Script] = ??? + override def calculateDelay(hitSource: ByteStr, baseTarget: Long, generator: ByteStr, balance: Long): Long = ??? + def callScript( dApp: Address, func: String, diff --git a/benchmark/src/test/scala/com/wavesplatform/state/CalculateDelayBenchmark.scala b/benchmark/src/test/scala/com/wavesplatform/state/CalculateDelayBenchmark.scala new file mode 100644 index 00000000000..d0cafd61119 --- /dev/null +++ b/benchmark/src/test/scala/com/wavesplatform/state/CalculateDelayBenchmark.scala @@ -0,0 +1,43 @@ +package com.wavesplatform.state + +import com.wavesplatform.common.state.ByteStr +import org.openjdk.jmh.annotations.* +import org.openjdk.jmh.infra.Blackhole + +import java.util.concurrent.TimeUnit + +@OutputTimeUnit(TimeUnit.MILLISECONDS) +@BenchmarkMode(Array(Mode.AverageTime)) +@Threads(1) +@Fork(1) +@Warmup(iterations = 5, time = 1) +@Measurement(iterations = 10, time = 1) +class CalculateDelayBenchmark { + import CalculateDelayBenchmark.* + + @Benchmark + def calculateDelay1(bh: Blackhole, st: St): Unit = + bh.consume(st.environment.calculateDelay(ByteStr.empty, 0, ByteStr.empty, 0)) + + @Benchmark + def calculateDelay2(bh: Blackhole, st: St): Unit = + bh.consume( + st.environment.calculateDelay(ByteStr.fill(96)(127), Long.MaxValue, ByteStr.fill(26)(127), Long.MaxValue) + ) + + @Benchmark + def calculateDelay3(bh: Blackhole, st: St): Unit = + bh.consume( + st.environment.calculateDelay(ByteStr.fill(96)(-128), Long.MinValue, ByteStr.fill(26)(-128), Long.MinValue) + ) + + @Benchmark + def calculateDelay4(bh: Blackhole, st: St): Unit = + bh.consume( + st.environment.calculateDelay(ByteStr.fill(32)(32), 123456, ByteStr.fill(26)(32), 100_000_000) + ) +} + +object CalculateDelayBenchmark { + class St extends DBState {} +} diff --git a/lang/doc/v8/funcs/blockchain-functions.hjson b/lang/doc/v8/funcs/blockchain-functions.hjson index 701ed298503..ed60aad8d47 100644 --- a/lang/doc/v8/funcs/blockchain-functions.hjson +++ b/lang/doc/v8/funcs/blockchain-functions.hjson @@ -70,5 +70,12 @@ paramsDoc: [ "dApp", "function name", "arguments", "Attached payments" ] complexity: 75 } + { + name: "calculateDelay" + params: [ "ByteVector", "Int", "Address", "Int" ] + doc: "Calculates mining delay using Fair PoS calculator." + paramsDoc: [ "hit source", "base target", "generator address", "generator balance" ] + complexity: 1 + } ] } diff --git a/lang/shared/src/main/scala/com/wavesplatform/lang/utils/package.scala b/lang/shared/src/main/scala/com/wavesplatform/lang/utils/package.scala index 9bde12bd5ec..c65012ac246 100644 --- a/lang/shared/src/main/scala/com/wavesplatform/lang/utils/package.scala +++ b/lang/shared/src/main/scala/com/wavesplatform/lang/utils/package.scala @@ -53,6 +53,7 @@ package object utils { override def addressFromString(address: String): Either[String, Recipient.Address] = ??? override def addressFromPublicKey(publicKey: ByteStr): Either[String, Address] = ??? override def accountScript(addressOrAlias: Recipient): Option[Script] = ??? + override def calculateDelay(hs: ByteStr, bt: Long, gt: ByteStr, b: Long): Long = ??? override def callScript( dApp: Address, func: String, diff --git a/lang/shared/src/main/scala/com/wavesplatform/lang/v1/evaluator/FunctionIds.scala b/lang/shared/src/main/scala/com/wavesplatform/lang/v1/evaluator/FunctionIds.scala index da973f82308..c021f529598 100644 --- a/lang/shared/src/main/scala/com/wavesplatform/lang/v1/evaluator/FunctionIds.scala +++ b/lang/shared/src/main/scala/com/wavesplatform/lang/v1/evaluator/FunctionIds.scala @@ -117,7 +117,8 @@ object FunctionIds { val BLS12_GROTH16_VERIFY: Short = 800 val BN256_GROTH16_VERIFY: Short = 801 - val ECRECOVER: Short = 900 + val ECRECOVER: Short = 900 + val CALCULATE_DELAY: Short = 901 val BLS12_GROTH16_VERIFY_LIM: Short = 2400 // Reserved n id for generated limited functions val BN256_GROTH16_VERIFY_LIM: Short = 2450 // Reserved n id for generated limited functions diff --git a/lang/shared/src/main/scala/com/wavesplatform/lang/v1/evaluator/ctx/impl/waves/Functions.scala b/lang/shared/src/main/scala/com/wavesplatform/lang/v1/evaluator/ctx/impl/waves/Functions.scala index fe40b3f515d..19c79872853 100644 --- a/lang/shared/src/main/scala/com/wavesplatform/lang/v1/evaluator/ctx/impl/waves/Functions.scala +++ b/lang/shared/src/main/scala/com/wavesplatform/lang/v1/evaluator/ctx/impl/waves/Functions.scala @@ -11,10 +11,11 @@ import com.wavesplatform.lang.v1.FunctionHeader.{Native, User} import com.wavesplatform.lang.v1.compiler.Terms.* import com.wavesplatform.lang.v1.compiler.Types.* import com.wavesplatform.lang.v1.evaluator.FunctionIds.* +import com.wavesplatform.lang.v1.evaluator.ctx.impl.EnvironmentFunctions.AddressLength import com.wavesplatform.lang.v1.evaluator.ctx.impl.converters.* import com.wavesplatform.lang.v1.evaluator.ctx.impl.waves.Bindings.{scriptTransfer as _, *} import com.wavesplatform.lang.v1.evaluator.ctx.impl.waves.Types.* -import com.wavesplatform.lang.v1.evaluator.ctx.impl.{EnvironmentFunctions, GlobalValNames, PureContext, notImplemented, unit} +import com.wavesplatform.lang.v1.evaluator.ctx.impl.* import com.wavesplatform.lang.v1.evaluator.ctx.{BaseFunction, NativeFunction, UserFunction} import com.wavesplatform.lang.v1.evaluator.{ContextfulNativeFunction, ContextfulUserFunction, FunctionIds, Log} import com.wavesplatform.lang.v1.traits.domain.{Issue, Lease, Recipient} @@ -304,7 +305,7 @@ object Functions { PureContext.eq, List( FUNCTION_CALL(PureContext.sizeBytes, List(REF("@afs_addrBytes"))), - CONST_LONG(EnvironmentFunctions.AddressLength) + CONST_LONG(AddressLength) ) ), IF( @@ -880,7 +881,6 @@ object Functions { BYTESTR, ("lease", leaseActionType) ) { - val AddressLength = 26 val MaxAliasLength = 30 new ContextfulNativeFunction.Simple[Environment]("calculateLeaseId", BYTESTR, Seq(("lease", leaseActionType))) { override def evaluate[F[_]: Monad](env: Environment[F], args: List[EVALUATED]): F[Either[ExecutionError, EVALUATED]] = @@ -943,4 +943,41 @@ object Functions { } } + val calculateDelay: NativeFunction[Environment] = { + val args = + Seq( + ("hit source", BYTESTR), + ("base target", LONG), + ("generator", addressType), + ("balance", LONG) + ) + NativeFunction.withEnvironment[Environment]( + "calculateDelay", + 1, + CALCULATE_DELAY, + LONG, + args* + ) { + val MaxHitSourceLength = 96 + new ContextfulNativeFunction.Simple[Environment]("calculateDelay", LONG, args) { + override def evaluate[F[_]: Monad](env: Environment[F], args: List[EVALUATED]): F[Either[ExecutionError, EVALUATED]] = + args match { + case CONST_BYTESTR(hitSource) :: CONST_LONG(baseTarget) :: CaseObj(`addressType`, fields) :: CONST_LONG(balance) :: Nil => + val addressBytes = fields("bytes").asInstanceOf[CONST_BYTESTR].bs + if (addressBytes.size > AddressLength) { + val error = CommonError(s"Address bytes length = ${addressBytes.size} exceeds limit = $AddressLength") + (error: ExecutionError).asLeft[EVALUATED].pure[F] + } else if (hitSource.size > MaxHitSourceLength) { + val error = CommonError(s"Hit source bytes length = ${hitSource.size} exceeds limit = $MaxHitSourceLength") + (error: ExecutionError).asLeft[EVALUATED].pure[F] + } else { + val delay = env.calculateDelay(hitSource, baseTarget, addressBytes, balance) + (CONST_LONG(delay): EVALUATED).asRight[ExecutionError].pure[F] + } + case xs => + notImplemented[Id, EVALUATED]("calculateDelay(hitSource: ByteVector, baseTarget: ByteVector, generator: Address, balance: Long)", xs) + } + } + } + } } diff --git a/lang/shared/src/main/scala/com/wavesplatform/lang/v1/evaluator/ctx/impl/waves/WavesContext.scala b/lang/shared/src/main/scala/com/wavesplatform/lang/v1/evaluator/ctx/impl/waves/WavesContext.scala index 8fd56abb0fb..ce8829ea19a 100644 --- a/lang/shared/src/main/scala/com/wavesplatform/lang/v1/evaluator/ctx/impl/waves/WavesContext.scala +++ b/lang/shared/src/main/scala/com/wavesplatform/lang/v1/evaluator/ctx/impl/waves/WavesContext.scala @@ -93,6 +93,9 @@ object WavesContext { fromV4Funcs(proofsEnabled, ds.stdLibVersion, typeDefs) ++ v5Funcs ++ dAppFuncs ++ accountFuncs } + private def fromV8Funcs(proofsEnabled: Boolean, ds: DirectiveSet, typeDefs: Map[String, FINAL]) = + fromV5Funcs(proofsEnabled, ds, typeDefs) :+ calculateDelay + private def selfCallFunctions(v: StdLibVersion) = Array( getIntegerFromStateSelfF, @@ -119,11 +122,11 @@ object WavesContext { val versionSpecificFuncs = version match { - case V1 | V2 => Array(txByIdF(proofsEnabled, version)) ++ balanceV123Functions - case V3 => fromV3Funcs(proofsEnabled, version, typeDefs) ++ balanceV123Functions - case V4 => fromV4Funcs(proofsEnabled, version, typeDefs) - case V5 => fromV5Funcs(proofsEnabled, ds, typeDefs) - case _ => fromV5Funcs(proofsEnabled, ds, typeDefs) + case V1 | V2 => Array(txByIdF(proofsEnabled, version)) ++ balanceV123Functions + case V3 => fromV3Funcs(proofsEnabled, version, typeDefs) ++ balanceV123Functions + case V4 => fromV4Funcs(proofsEnabled, version, typeDefs) + case V5 | V6 | V7 => fromV5Funcs(proofsEnabled, ds, typeDefs) + case _ => fromV8Funcs(proofsEnabled, ds, typeDefs) } commonFuncs ++ versionSpecificFuncs } diff --git a/lang/shared/src/main/scala/com/wavesplatform/lang/v1/traits/Environment.scala b/lang/shared/src/main/scala/com/wavesplatform/lang/v1/traits/Environment.scala index e4d86ed6ae5..ac61d73b636 100644 --- a/lang/shared/src/main/scala/com/wavesplatform/lang/v1/traits/Environment.scala +++ b/lang/shared/src/main/scala/com/wavesplatform/lang/v1/traits/Environment.scala @@ -50,4 +50,5 @@ trait Environment[F[_]] { availableComplexity: Int, reentrant: Boolean ): Coeval[F[(Either[ValidationError, (EVALUATED, Log[F])], Int)]] + def calculateDelay(hitSource: ByteStr, baseTarget: Long, generator: ByteStr, balance: Long): Long } diff --git a/lang/testkit/src/main/scala/com/wavesplatform/lang/Common.scala b/lang/testkit/src/main/scala/com/wavesplatform/lang/Common.scala index 60cdb6b3a6d..730c9104468 100644 --- a/lang/testkit/src/main/scala/com/wavesplatform/lang/Common.scala +++ b/lang/testkit/src/main/scala/com/wavesplatform/lang/Common.scala @@ -74,29 +74,30 @@ object Common { def emptyBlockchainEnvironment(h: Int = 1, in: Coeval[Environment.InputEntity] = Coeval(???), nByte: Byte = 'T'): Environment[Id] = new Environment[Id] { - override def height: Long = h - override def chainId: Byte = nByte - override def inputEntity = in() - - override def transactionById(id: Array[Byte]): Option[Tx] = ??? - override def transferTransactionById(id: Array[Byte]): Option[Tx.Transfer] = ??? - override def transactionHeightById(id: Array[Byte]): Option[Long] = ??? - override def assetInfoById(id: Array[Byte]): Option[ScriptAssetInfo] = ??? - override def lastBlockOpt(): Option[BlockInfo] = ??? - override def blockInfoByHeight(height: Int): Option[BlockInfo] = ??? - override def data(recipient: Recipient, key: String, dataType: DataType): Option[Any] = None - override def hasData(recipient: Recipient): Boolean = false - override def resolveAlias(name: String): Either[String, Recipient.Address] = ??? - override def accountBalanceOf(addressOrAlias: Recipient, assetId: Option[Array[Byte]]): Either[String, Long] = ??? - override def accountWavesBalanceOf(addressOrAlias: Recipient): Either[String, Environment.BalanceDetails] = ??? - override def tthis: Environment.Tthis = Coproduct(Address(ByteStr.empty)) - override def multiPaymentAllowed: Boolean = true - override def txId: ByteStr = ??? - override def transferTransactionFromProto(b: Array[Byte]): Option[Tx.Transfer] = ??? - override def addressFromString(address: String): Either[String, Recipient.Address] = ??? - override def addressFromPublicKey(publicKey: ByteStr): Either[String, Address] = ??? - def accountScript(addressOrAlias: Recipient): Option[Script] = ??? - override def callScript( + def height: Long = h + def chainId: Byte = nByte + def inputEntity = in() + + def transactionById(id: Array[Byte]): Option[Tx] = ??? + def transferTransactionById(id: Array[Byte]): Option[Tx.Transfer] = ??? + def transactionHeightById(id: Array[Byte]): Option[Long] = ??? + def assetInfoById(id: Array[Byte]): Option[ScriptAssetInfo] = ??? + def lastBlockOpt(): Option[BlockInfo] = ??? + def blockInfoByHeight(height: Int): Option[BlockInfo] = ??? + def data(recipient: Recipient, key: String, dataType: DataType): Option[Any] = None + def hasData(recipient: Recipient): Boolean = false + def resolveAlias(name: String): Either[String, Recipient.Address] = ??? + def accountBalanceOf(a: Recipient, b: Option[Array[Byte]]): Either[String, Long] = ??? + def accountWavesBalanceOf(a: Recipient): Either[String, Environment.BalanceDetails] = ??? + def tthis: Environment.Tthis = Coproduct(Address(ByteStr.empty)) + def multiPaymentAllowed: Boolean = true + def txId: ByteStr = ??? + def transferTransactionFromProto(b: Array[Byte]): Option[Tx.Transfer] = ??? + def addressFromString(address: String): Either[String, Recipient.Address] = ??? + def addressFromPublicKey(publicKey: ByteStr): Either[String, Address] = ??? + def accountScript(addressOrAlias: Recipient): Option[Script] = ??? + def calculateDelay(hs: ByteStr, bt: Long, gt: ByteStr, b: Long): Long = ??? + def callScript( dApp: Address, func: String, args: List[EVALUATED], diff --git a/node/src/main/scala/com/wavesplatform/consensus/PoSCalculator.scala b/node/src/main/scala/com/wavesplatform/consensus/PoSCalculator.scala index d0327c76531..6ab4be34d00 100644 --- a/node/src/main/scala/com/wavesplatform/consensus/PoSCalculator.scala +++ b/node/src/main/scala/com/wavesplatform/consensus/PoSCalculator.scala @@ -20,8 +20,8 @@ sealed trait PoSCalculator { } object PoSCalculator { - private[consensus] val HitSize: Int = 8 - val MinBaseTarget: Long = 9 + val HitSize: Int = 8 + val MinBaseTarget: Long = 9 def generationSignature(signature: ByteStr, publicKey: PublicKey): Array[Byte] = { val s = new Array[Byte](crypto.DigestLength * 2) diff --git a/node/src/main/scala/com/wavesplatform/transaction/smart/WavesEnvironment.scala b/node/src/main/scala/com/wavesplatform/transaction/smart/WavesEnvironment.scala index 1cf5c2fbf62..1aa4c7159b2 100644 --- a/node/src/main/scala/com/wavesplatform/transaction/smart/WavesEnvironment.scala +++ b/node/src/main/scala/com/wavesplatform/transaction/smart/WavesEnvironment.scala @@ -7,9 +7,10 @@ import com.wavesplatform.account.{AddressOrAlias, PublicKey} import com.wavesplatform.block.BlockHeader import com.wavesplatform.common.state.ByteStr import com.wavesplatform.common.utils.EitherExt2 +import com.wavesplatform.consensus.{FairPoSCalculator, PoSCalculator} import com.wavesplatform.features.BlockchainFeatures import com.wavesplatform.features.MultiPaymentPolicyProvider.* -import com.wavesplatform.lang.ValidationError +import com.wavesplatform.lang.{Global, ValidationError} import com.wavesplatform.lang.directives.DirectiveSet import com.wavesplatform.lang.directives.values.StdLibVersion import com.wavesplatform.lang.script.Script @@ -250,6 +251,11 @@ class WavesEnvironment( reentrant: Boolean ): Coeval[(Either[ValidationError, (EVALUATED, Log[Id])], Int)] = ??? + override def calculateDelay(hitSource: ByteStr, baseTarget: Long, generator: ByteStr, balance: Long): Long = { + val hit = Global.blake2b256(hitSource.arr ++ generator.arr).take(PoSCalculator.HitSize) + FairPoSCalculator.V2.calculateDelay(BigInt(1, hit), baseTarget, balance) + } + private def getRewards(generator: PublicKey, height: Int): Seq[(Address, Long)] = { if (blockchain.isFeatureActivated(BlockchainFeatures.CappedReward)) { val rewardShares = BlockRewardCalculator.getSortedBlockRewardShares(height, generator.toAddress, blockchain) diff --git a/node/src/test/scala/com/wavesplatform/state/diffs/smart/predef/CalculateDelayTest.scala b/node/src/test/scala/com/wavesplatform/state/diffs/smart/predef/CalculateDelayTest.scala new file mode 100644 index 00000000000..0dcdaa4c70a --- /dev/null +++ b/node/src/test/scala/com/wavesplatform/state/diffs/smart/predef/CalculateDelayTest.scala @@ -0,0 +1,70 @@ +package com.wavesplatform.state.diffs.smart.predef + +import com.wavesplatform.common.state.ByteStr +import com.wavesplatform.db.WithDomain +import com.wavesplatform.db.WithState.AddrWithBalance +import com.wavesplatform.lang.directives.values.V8 +import com.wavesplatform.lang.v1.compiler.TestCompiler +import com.wavesplatform.test.* +import com.wavesplatform.transaction.TxHelpers.* + +class CalculateDelayTest extends PropSpec with WithDomain { + import DomainPresets.* + + private val contract = + TestCompiler(V8).compileContract( + s""" + | @Callable(i) + | func default() = { + | let address1 = i.caller + | let address2 = Address(base58'${signer(2).toAddress}') + | let address3 = Address(base58'${signer(3).toAddress}') + | let lowest = calculateDelay(lastBlock.generationSignature, lastBlock.baseTarget, address1, 10 * 1000 * 1000) + | let medium = calculateDelay(lastBlock.generationSignature, lastBlock.baseTarget, address2, 30 * 1000 * 1000) + | let largest = calculateDelay(lastBlock.generationSignature, lastBlock.baseTarget, address3, 90 * 1000 * 1000) + | [ + | IntegerEntry("lowest", lowest), + | IntegerEntry("medium", medium), + | IntegerEntry("largest", largest) + | ] + | } + | + | @Callable(i) + | func error1() = { + | strict r = calculateDelay(base58'${ByteStr.fill(97)(1)}', 0, i.caller, 0) + | [] + | } + | + | @Callable(i) + | func error2() = { + | strict r = calculateDelay(lastBlock.generationSignature, 0, Address(base58'${ByteStr.fill(27)(1)}'), 0) + | [] + | } + """.stripMargin + ) + + property("distribution of calculateDelay()") { + withDomain(TransactionStateSnapshot, AddrWithBalance.enoughBalances(secondSigner)) { d => + d.appendBlock(setScript(secondSigner, contract)) + val minDelays = + (1 to 200).map { _ => + d.appendBlock(invoke()) + d.liquidDiff.accountData(secondAddress).values.minBy(_.value.asInstanceOf[Long]).key + } + val lowestIsMiner = minDelays.count(_ == "lowest") + val mediumIsMiner = minDelays.count(_ == "medium") + val largestIsMiner = minDelays.count(_ == "largest") + lowestIsMiner should be > 0 + mediumIsMiner should be > lowestIsMiner + largestIsMiner should be > mediumIsMiner + } + } + + property("errors of calculateDelay()") { + withDomain(TransactionStateSnapshot, AddrWithBalance.enoughBalances(secondSigner)) { d => + d.appendBlock(setScript(secondSigner, contract)) + d.appendBlockE(invoke(func = Some("error1"))) should produce("Hit source bytes length = 97 exceeds limit = 96") + d.appendBlockE(invoke(func = Some("error2"))) should produce("Address bytes length = 27 exceeds limit = 26") + } + } +} From bd4e021e76e056fa708fb08175a883e9c14c1c74 Mon Sep 17 00:00:00 2001 From: Artyom Sayadyan Date: Wed, 20 Sep 2023 23:46:50 +0300 Subject: [PATCH 2/5] Adapted REPL package --- .../repl/node/ErrorMessageEnvironment.scala | 47 ++++++++++--------- .../v1/repl/node/http/WebEnvironment.scala | 3 ++ 2 files changed, 27 insertions(+), 23 deletions(-) diff --git a/repl/shared/src/main/scala/com/wavesplatform/lang/v1/repl/node/ErrorMessageEnvironment.scala b/repl/shared/src/main/scala/com/wavesplatform/lang/v1/repl/node/ErrorMessageEnvironment.scala index 1ff8f0a0789..42d24757adb 100644 --- a/repl/shared/src/main/scala/com/wavesplatform/lang/v1/repl/node/ErrorMessageEnvironment.scala +++ b/repl/shared/src/main/scala/com/wavesplatform/lang/v1/repl/node/ErrorMessageEnvironment.scala @@ -5,35 +5,36 @@ import com.wavesplatform.lang.ValidationError import com.wavesplatform.lang.script.Script import com.wavesplatform.lang.v1.compiler.Terms.EVALUATED import com.wavesplatform.lang.v1.evaluator.Log -import com.wavesplatform.lang.v1.traits.Environment.InputEntity +import com.wavesplatform.lang.v1.traits.Environment.{BalanceDetails, InputEntity} import com.wavesplatform.lang.v1.traits.domain.Recipient.Address import com.wavesplatform.lang.v1.traits.domain.{BlockInfo, Recipient, ScriptAssetInfo, Tx} import com.wavesplatform.lang.v1.traits.{DataType, Environment} import monix.eval.Coeval case class ErrorMessageEnvironment[F[_]](message: String) extends Environment[F] { - lazy val unavailable = throw BlockchainUnavailableException(message) - override def chainId: Byte = 0 - override def height: F[Long] = unavailable - override def inputEntity: InputEntity = unavailable - override def tthis: Environment.Tthis = unavailable - override def transactionById(id: Array[Byte]): F[Option[Tx]] = unavailable - override def transferTransactionById(id: Array[Byte]): F[Option[Tx.Transfer]] = unavailable - override def transactionHeightById(id: Array[Byte]): F[Option[Long]] = unavailable - override def assetInfoById(d: Array[Byte]): F[Option[ScriptAssetInfo]] = unavailable - override def lastBlockOpt(): F[Option[BlockInfo]] = unavailable - override def blockInfoByHeight(height: Int): F[Option[BlockInfo]] = unavailable - override def data(addressOrAlias: Recipient, key: String, dataType: DataType): F[Option[Any]] = unavailable - override def hasData(addressOrAlias: Recipient): F[Boolean] = unavailable - override def resolveAlias(name: String): F[Either[String, Recipient.Address]] = unavailable - override def accountBalanceOf(addressOrAlias: Recipient, assetId: Option[Array[Byte]]): F[Either[String, Long]] = unavailable - override def accountWavesBalanceOf(addressOrAlias: Recipient): F[Either[String, Environment.BalanceDetails]] = unavailable - override def multiPaymentAllowed: Boolean = unavailable - override def txId: ByteStr = unavailable - override def transferTransactionFromProto(b: Array[Byte]): F[Option[Tx.Transfer]] = unavailable - override def addressFromString(address: String): Either[String, Recipient.Address] = unavailable - override def addressFromPublicKey(publicKey: ByteStr): Either[String, Address] = unavailable - override def accountScript(addressOrAlias: Recipient): F[Option[Script]] = unavailable + lazy val unavailable = throw BlockchainUnavailableException(message) + override def chainId: Byte = 0 + override def height: F[Long] = unavailable + override def inputEntity: InputEntity = unavailable + override def tthis: Environment.Tthis = unavailable + override def transactionById(id: Array[Byte]): F[Option[Tx]] = unavailable + override def transferTransactionById(id: Array[Byte]): F[Option[Tx.Transfer]] = unavailable + override def transactionHeightById(id: Array[Byte]): F[Option[Long]] = unavailable + override def assetInfoById(d: Array[Byte]): F[Option[ScriptAssetInfo]] = unavailable + override def lastBlockOpt(): F[Option[BlockInfo]] = unavailable + override def blockInfoByHeight(height: Int): F[Option[BlockInfo]] = unavailable + override def data(addressOrAlias: Recipient, key: String, dataType: DataType): F[Option[Any]] = unavailable + override def hasData(addressOrAlias: Recipient): F[Boolean] = unavailable + override def resolveAlias(name: String): F[Either[String, Recipient.Address]] = unavailable + override def accountBalanceOf(r: Recipient, assetId: Option[Array[Byte]]): F[Either[String, Long]] = unavailable + override def accountWavesBalanceOf(addressOrAlias: Recipient): F[Either[String, BalanceDetails]] = unavailable + override def multiPaymentAllowed: Boolean = unavailable + override def txId: ByteStr = unavailable + override def transferTransactionFromProto(b: Array[Byte]): F[Option[Tx.Transfer]] = unavailable + override def addressFromString(address: String): Either[String, Recipient.Address] = unavailable + override def addressFromPublicKey(publicKey: ByteStr): Either[String, Address] = unavailable + override def accountScript(addressOrAlias: Recipient): F[Option[Script]] = unavailable + override def calculateDelay(hitSource: ByteStr, bt: Long, generator: ByteStr, balance: Long): Long = unavailable override def callScript( dApp: Address, func: String, diff --git a/repl/shared/src/main/scala/com/wavesplatform/lang/v1/repl/node/http/WebEnvironment.scala b/repl/shared/src/main/scala/com/wavesplatform/lang/v1/repl/node/http/WebEnvironment.scala index 702c7a1c596..7b519bdaacd 100644 --- a/repl/shared/src/main/scala/com/wavesplatform/lang/v1/repl/node/http/WebEnvironment.scala +++ b/repl/shared/src/main/scala/com/wavesplatform/lang/v1/repl/node/http/WebEnvironment.scala @@ -146,6 +146,9 @@ private[repl] case class WebEnvironment(settings: NodeConnectionSettings, client client.get[F, A](url).map(_.map(ev)) override def accountScript(addressOrAlias: Recipient): Future[Option[Script]] = ??? + + override def calculateDelay(hitSource: ByteStr, baseTarget: Long, generator: ByteStr, balance: Long): Long = ??? + override def callScript( dApp: Address, func: String, From 38785656f2388673677f3c01a7c26e67b1394456 Mon Sep 17 00:00:00 2001 From: Artyom Sayadyan Date: Thu, 21 Sep 2023 17:07:27 +0300 Subject: [PATCH 3/5] Corrected CalculateDelayBenchmark --- .../wavesplatform/state/CalculateDelayBenchmark.scala | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/benchmark/src/test/scala/com/wavesplatform/state/CalculateDelayBenchmark.scala b/benchmark/src/test/scala/com/wavesplatform/state/CalculateDelayBenchmark.scala index d0cafd61119..950a124a951 100644 --- a/benchmark/src/test/scala/com/wavesplatform/state/CalculateDelayBenchmark.scala +++ b/benchmark/src/test/scala/com/wavesplatform/state/CalculateDelayBenchmark.scala @@ -6,7 +6,15 @@ import org.openjdk.jmh.infra.Blackhole import java.util.concurrent.TimeUnit -@OutputTimeUnit(TimeUnit.MILLISECONDS) +/* +[info] Benchmark (configFile) Mode Cnt Score Error Units +[info] CalculateDelayBenchmark.calculateDelay1 waves.conf avgt 10 1,616 ± 0,244 us/op +[info] CalculateDelayBenchmark.calculateDelay2 waves.conf avgt 10 1,671 ± 0,073 us/op +[info] CalculateDelayBenchmark.calculateDelay3 waves.conf avgt 10 1,688 ± 0,228 us/op +[info] CalculateDelayBenchmark.calculateDelay4 waves.conf avgt 10 1,656 ± 0,020 us/op + */ + +@OutputTimeUnit(TimeUnit.MICROSECONDS) @BenchmarkMode(Array(Mode.AverageTime)) @Threads(1) @Fork(1) From 04b080863c197f60beec70668a838d2c7bcc466a Mon Sep 17 00:00:00 2001 From: Artyom Sayadyan Date: Fri, 22 Sep 2023 10:26:24 +0300 Subject: [PATCH 4/5] Corrected vrf in RIDE and modified test --- .../scala/com/wavesplatform/history/Domain.scala | 5 +++-- .../diffs/smart/predef/CalculateDelayTest.scala | 13 +++++++------ 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/node/src/test/scala/com/wavesplatform/history/Domain.scala b/node/src/test/scala/com/wavesplatform/history/Domain.scala index d4d60769928..1b9c86a6513 100644 --- a/node/src/test/scala/com/wavesplatform/history/Domain.scala +++ b/node/src/test/scala/com/wavesplatform/history/Domain.scala @@ -23,10 +23,10 @@ import com.wavesplatform.lang.script.Script import com.wavesplatform.mining.{BlockChallenger, BlockChallengerImpl} import com.wavesplatform.settings.WavesSettings import com.wavesplatform.state.* -import com.wavesplatform.state.appender.BlockAppender import com.wavesplatform.state.BlockchainUpdaterImpl.BlockApplyResult import com.wavesplatform.state.BlockchainUpdaterImpl.BlockApplyResult.{Applied, Ignored} import com.wavesplatform.state.TxStateSnapshotHashBuilder.InitStateHash +import com.wavesplatform.state.appender.BlockAppender import com.wavesplatform.state.diffs.{BlockDiffer, TransactionDiffer} import com.wavesplatform.state.reader.SnapshotBlockchain import com.wavesplatform.test.TestTime @@ -444,7 +444,8 @@ case class Domain(rdb: RDB, blockchainUpdater: BlockchainUpdaterImpl, rocksDBWri ) resultStateHash <- stateHash.map(Right(_)).getOrElse { if (blockchain.isFeatureActivated(TransactionStateSnapshot, blockchain.height + 1)) { - val blockchain = SnapshotBlockchain(this.blockchain, StateSnapshot.empty, blockWithoutStateHash, ByteStr.empty, 0, None) + val hitSource = posSelector.validateGenerationSignature(blockWithoutStateHash).explicitGet() + val blockchain = SnapshotBlockchain(this.blockchain, StateSnapshot.empty, blockWithoutStateHash, hitSource, 0, None) val prevStateHash = this.blockchain.lastBlockHeader.flatMap(_.header.stateHash).getOrElse(InitStateHash) BlockDiffer diff --git a/node/src/test/scala/com/wavesplatform/state/diffs/smart/predef/CalculateDelayTest.scala b/node/src/test/scala/com/wavesplatform/state/diffs/smart/predef/CalculateDelayTest.scala index 0dcdaa4c70a..c9df847c920 100644 --- a/node/src/test/scala/com/wavesplatform/state/diffs/smart/predef/CalculateDelayTest.scala +++ b/node/src/test/scala/com/wavesplatform/state/diffs/smart/predef/CalculateDelayTest.scala @@ -16,12 +16,13 @@ class CalculateDelayTest extends PropSpec with WithDomain { s""" | @Callable(i) | func default() = { - | let address1 = i.caller - | let address2 = Address(base58'${signer(2).toAddress}') - | let address3 = Address(base58'${signer(3).toAddress}') - | let lowest = calculateDelay(lastBlock.generationSignature, lastBlock.baseTarget, address1, 10 * 1000 * 1000) - | let medium = calculateDelay(lastBlock.generationSignature, lastBlock.baseTarget, address2, 30 * 1000 * 1000) - | let largest = calculateDelay(lastBlock.generationSignature, lastBlock.baseTarget, address3, 90 * 1000 * 1000) + | let hitSource = if (height % 2 == 0) then lastBlock.generationSignature else lastBlock.vrf.value() + | let address1 = i.caller + | let address2 = Address(base58'${signer(2).toAddress}') + | let address3 = Address(base58'${signer(3).toAddress}') + | let lowest = calculateDelay(hitSource, lastBlock.baseTarget, address1, 10 * 1000 * 1000) + | let medium = calculateDelay(hitSource, lastBlock.baseTarget, address2, 30 * 1000 * 1000) + | let largest = calculateDelay(hitSource, lastBlock.baseTarget, address3, 90 * 1000 * 1000) | [ | IntegerEntry("lowest", lowest), | IntegerEntry("medium", medium), From 945754ec827a3e7384d33c98672cd225a6199231 Mon Sep 17 00:00:00 2001 From: Artyom Sayadyan Date: Fri, 22 Sep 2023 10:33:25 +0300 Subject: [PATCH 5/5] Adapted Domain --- node/src/test/scala/com/wavesplatform/history/Domain.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/node/src/test/scala/com/wavesplatform/history/Domain.scala b/node/src/test/scala/com/wavesplatform/history/Domain.scala index 1b9c86a6513..7f32c0d5816 100644 --- a/node/src/test/scala/com/wavesplatform/history/Domain.scala +++ b/node/src/test/scala/com/wavesplatform/history/Domain.scala @@ -444,8 +444,8 @@ case class Domain(rdb: RDB, blockchainUpdater: BlockchainUpdaterImpl, rocksDBWri ) resultStateHash <- stateHash.map(Right(_)).getOrElse { if (blockchain.isFeatureActivated(TransactionStateSnapshot, blockchain.height + 1)) { - val hitSource = posSelector.validateGenerationSignature(blockWithoutStateHash).explicitGet() - val blockchain = SnapshotBlockchain(this.blockchain, StateSnapshot.empty, blockWithoutStateHash, hitSource, 0, None) + val hitSource = posSelector.validateGenerationSignature(blockWithoutStateHash).getOrElse(blockWithoutStateHash.header.generationSignature) + val blockchain = SnapshotBlockchain(this.blockchain, StateSnapshot.empty, blockWithoutStateHash, hitSource, 0, None) val prevStateHash = this.blockchain.lastBlockHeader.flatMap(_.header.stateHash).getOrElse(InitStateHash) BlockDiffer