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 849d2a0777..bf14f6b9b1 100644 --- a/benchmark/src/test/scala/com/wavesplatform/lang/v1/EnvironmentFunctionsBenchmark.scala +++ b/benchmark/src/test/scala/com/wavesplatform/lang/v1/EnvironmentFunctionsBenchmark.scala @@ -132,7 +132,7 @@ object EnvironmentFunctionsBenchmark { override def accountScript(addressOrAlias: Recipient): Option[Script] = ??? - override def calculateDelay(hitSource: ByteStr, baseTarget: Long, generator: ByteStr, balance: Long): Long = ??? + override def calculateDelay(generator: ByteStr, balance: Long): Long = ??? def callScript( dApp: Address, diff --git a/benchmark/src/test/scala/com/wavesplatform/state/CalculateDelayBenchmark.scala b/benchmark/src/test/scala/com/wavesplatform/state/CalculateDelayBenchmark.scala index 950a124a95..00c84d1797 100644 --- a/benchmark/src/test/scala/com/wavesplatform/state/CalculateDelayBenchmark.scala +++ b/benchmark/src/test/scala/com/wavesplatform/state/CalculateDelayBenchmark.scala @@ -25,24 +25,24 @@ class CalculateDelayBenchmark { @Benchmark def calculateDelay1(bh: Blackhole, st: St): Unit = - bh.consume(st.environment.calculateDelay(ByteStr.empty, 0, ByteStr.empty, 0)) + bh.consume(st.environment.calculateDelay(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) + st.environment.calculateDelay(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) + st.environment.calculateDelay(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) + st.environment.calculateDelay(ByteStr.fill(26)(32), 100_000_000) ) } diff --git a/lang/doc/v8/funcs/blockchain-functions.hjson b/lang/doc/v8/funcs/blockchain-functions.hjson index ed60aad8d4..b8500b8be5 100644 --- a/lang/doc/v8/funcs/blockchain-functions.hjson +++ b/lang/doc/v8/funcs/blockchain-functions.hjson @@ -72,9 +72,9 @@ } { name: "calculateDelay" - params: [ "ByteVector", "Int", "Address", "Int" ] + params: [ "Address", "Int" ] doc: "Calculates mining delay using Fair PoS calculator." - paramsDoc: [ "hit source", "base target", "generator address", "generator balance" ] + paramsDoc: [ "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 c65012ac24..23200066f5 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,7 +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 calculateDelay(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/ctx/impl/waves/Functions.scala b/lang/shared/src/main/scala/com/wavesplatform/lang/v1/evaluator/ctx/impl/waves/Functions.scala index c12a726ef3..d748f02c83 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 @@ -1002,8 +1002,6 @@ object Functions { val calculateDelay: NativeFunction[Environment] = { val args = Seq( - ("hit source", BYTESTR), - ("base target", LONG), ("generator", addressType), ("balance", LONG) ) @@ -1014,24 +1012,23 @@ object Functions { 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 => + case 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") + } else if (balance <= 0) { + val error = CommonError(s"Unexpected non-positive balance = $balance") (error: ExecutionError).asLeft[EVALUATED].pure[F] } else { - val delay = env.calculateDelay(hitSource, baseTarget, addressBytes, balance) + val delay = env.calculateDelay(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) + notImplemented[Id, EVALUATED]("calculateDelay(generator: Address, balance: Long)", xs) } } } 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 ac61d73b63..315a118499 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,5 +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 + def calculateDelay(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 730c910446..ed520803c2 100644 --- a/lang/testkit/src/main/scala/com/wavesplatform/lang/Common.scala +++ b/lang/testkit/src/main/scala/com/wavesplatform/lang/Common.scala @@ -9,10 +9,10 @@ import com.wavesplatform.lang.v1.CTX import com.wavesplatform.lang.v1.compiler.Terms.* import com.wavesplatform.lang.v1.compiler.Types.* import com.wavesplatform.lang.v1.evaluator.Contextful.NoContext -import com.wavesplatform.lang.v1.evaluator.{EvaluatorV1, Log} import com.wavesplatform.lang.v1.evaluator.EvaluatorV1.* import com.wavesplatform.lang.v1.evaluator.ctx.* -import com.wavesplatform.lang.v1.evaluator.ctx.impl.{EnvironmentFunctions, PureContext, *} +import com.wavesplatform.lang.v1.evaluator.ctx.impl.* +import com.wavesplatform.lang.v1.evaluator.{EvaluatorV1, Log} 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} @@ -96,7 +96,7 @@ object Common { 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 calculateDelay(gt: ByteStr, b: Long): Long = ??? def callScript( dApp: Address, func: String, diff --git a/lang/tests/src/test/scala/com/wavesplatform/lang/compiler/DecompilerTest.scala b/lang/tests/src/test/scala/com/wavesplatform/lang/compiler/DecompilerTest.scala index d78e73802a..f8f31be7e6 100644 --- a/lang/tests/src/test/scala/com/wavesplatform/lang/compiler/DecompilerTest.scala +++ b/lang/tests/src/test/scala/com/wavesplatform/lang/compiler/DecompilerTest.scala @@ -1118,7 +1118,7 @@ class DecompilerTest extends PropSpec { } property("calculateDelay()") { - val script = "calculateDelay(base58'aaa', 123, Address(base58'bbb'), 456)" + val script = "calculateDelay(Address(base58'bbb'), 456)" assertDecompile(script, script, V8) } 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 f8bbd054bf..f4eb97e1a6 100644 --- a/node/src/main/scala/com/wavesplatform/transaction/smart/WavesEnvironment.scala +++ b/node/src/main/scala/com/wavesplatform/transaction/smart/WavesEnvironment.scala @@ -1,7 +1,7 @@ package com.wavesplatform.transaction.smart -import cats.implicits.catsSyntaxSemigroup import cats.Id +import cats.implicits.catsSyntaxSemigroup import cats.syntax.either.* import com.wavesplatform.account import com.wavesplatform.account.{AddressOrAlias, PublicKey} @@ -26,7 +26,6 @@ import com.wavesplatform.state.* import com.wavesplatform.state.BlockRewardCalculator.CurrentBlockRewardPart import com.wavesplatform.state.diffs.invoke.InvokeScriptDiff.validateIntermediateBalances import com.wavesplatform.state.diffs.invoke.{InvokeScript, InvokeScriptDiff, InvokeScriptTransactionLike} -import com.wavesplatform.state.SnapshotBlockchain import com.wavesplatform.transaction.Asset.* import com.wavesplatform.transaction.TxValidationError.{FailedTransactionError, GenericError} import com.wavesplatform.transaction.assets.exchange.Order @@ -268,9 +267,15 @@ class WavesEnvironment( reentrant: Boolean ): Coeval[(Either[ValidationError, (EVALUATED, Log[Id])], Int)] = ??? - override def calculateDelay(hitSource: ByteStr, baseTarget: Long, generator: ByteStr, balance: Long): Long = { + override def calculateDelay(generator: ByteStr, balance: Long): Long = { + val baseTarget = blockchain.lastBlockHeader.map(_.header.baseTarget).getOrElse(0L) + val hitSource = + blockchain + .vrf(blockchain.height) + .orElse(blockchain.lastBlockHeader.map(_.header.generationSignature)) + .getOrElse(ByteStr.empty) val hit = Global.blake2b256(hitSource.arr ++ generator.arr).take(PoSCalculator.HitSize) - FairPoSCalculator.V2.calculateDelay(BigInt(1, hit), baseTarget, balance) + FairPoSCalculator(0, 0).calculateDelay(BigInt(1, hit), baseTarget, balance) } private def getRewards(generator: PublicKey, height: Int): Seq[(Address, Long)] = { 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 af47ac69af..150a11ab3b 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 @@ -4,7 +4,9 @@ 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.Terms.CONST_LONG import com.wavesplatform.lang.v1.compiler.TestCompiler +import com.wavesplatform.state.IntegerDataEntry import com.wavesplatform.test.* import com.wavesplatform.transaction.TxHelpers.* @@ -20,25 +22,34 @@ class CalculateDelayTest extends PropSpec with WithDomain { | 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) + | let lowest = calculateDelay(address1, 10 * 1000 * 1000) + | let medium = calculateDelay(address2, 30 * 1000 * 1000) + | let largest = calculateDelay(address3, 90 * 1000 * 1000) | [ | IntegerEntry("lowest", lowest), | IntegerEntry("medium", medium), | IntegerEntry("largest", largest) | ] | } + | + | @Callable(i) + | func results() = + | [ + | IntegerEntry("1", calculateDelay(Address(base58''), 1)), + | IntegerEntry("2", calculateDelay(Address(base58'${ByteStr.fill(26)(1)}'), ${Int.MaxValue})), + | IntegerEntry("3", calculateDelay(Address(base58'${ByteStr.fill(26)(1)}'), ${100_000L * Int.MaxValue})), + | IntegerEntry("4", calculateDelay(Address(base58'${ByteStr.fill(26)(1)}'), ${200_000L * Int.MaxValue})) + | ] | | @Callable(i) | func error1() = { - | strict r = calculateDelay(base58'${ByteStr.fill(97)(1)}', 0, i.caller, 0) + | strict r = calculateDelay(Address(base58'${ByteStr.fill(27)(1)}'), 1) | [] | } | | @Callable(i) - | func error2() = { - | strict r = calculateDelay(lastBlock.generationSignature, 0, Address(base58'${ByteStr.fill(27)(1)}'), 0) + | func error2(balance: Int) = { + | strict r = calculateDelay(Address(base58''), balance) | [] | } """.stripMargin @@ -61,11 +72,25 @@ class CalculateDelayTest extends PropSpec with WithDomain { } } + property("results") { + withDomain(TransactionStateSnapshot, AddrWithBalance.enoughBalances(secondSigner)) { d => + d.appendBlock(setScript(secondSigner, contract)) + d.appendBlock(invoke(func = Some("results"))) + d.liquidSnapshot.accountData.head._2.values.toSeq shouldBe Seq( + IntegerDataEntry("1", 1418883), + IntegerDataEntry("2", 70064), + IntegerDataEntry("3", 1), + IntegerDataEntry("4", 0) + ) + } + } + 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") + d.appendBlockE(invoke(func = Some("error1"))) should produce("Address bytes length = 27 exceeds limit = 26") + d.appendBlockE(invoke(func = Some("error2"), args = Seq(CONST_LONG(-1)))) should produce("Unexpected non-positive balance = -1") + d.appendBlockE(invoke(func = Some("error2"), args = Seq(CONST_LONG(0)))) should produce("Unexpected non-positive balance = 0") } } } 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 42d24757ad..6b9ea189fb 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 @@ -34,7 +34,7 @@ case class ErrorMessageEnvironment[F[_]](message: String) extends Environment[F] 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 calculateDelay(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 7b519bdaac..fda0c55de0 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 @@ -147,7 +147,7 @@ private[repl] case class WebEnvironment(settings: NodeConnectionSettings, client override def accountScript(addressOrAlias: Recipient): Future[Option[Script]] = ??? - override def calculateDelay(hitSource: ByteStr, baseTarget: Long, generator: ByteStr, balance: Long): Long = ??? + override def calculateDelay(generator: ByteStr, balance: Long): Long = ??? override def callScript( dApp: Address, diff --git a/ride-runner/src/main/scala/com/wavesplatform/ride/runner/environments/TrackedDAppEnvironment.scala b/ride-runner/src/main/scala/com/wavesplatform/ride/runner/environments/TrackedDAppEnvironment.scala index 9e6607b193..750b6b76d2 100644 --- a/ride-runner/src/main/scala/com/wavesplatform/ride/runner/environments/TrackedDAppEnvironment.scala +++ b/ride-runner/src/main/scala/com/wavesplatform/ride/runner/environments/TrackedDAppEnvironment.scala @@ -30,8 +30,8 @@ class TrackedDAppEnvironment(underlying: DAppEnvironment, tracker: DAppEnvironme override def invocationRoot: DAppEnvironment.InvocationTreeTracker = underlying.invocationRoot - override def calculateDelay(hitSource: ByteStr, baseTarget: Long, generator: ByteStr, balance: Long): Long = - underlying.calculateDelay(hitSource, baseTarget, generator, balance) + override def calculateDelay(generator: ByteStr, balance: Long): Long = + underlying.calculateDelay(generator, balance) // Functions those need Blockchain override def height: Id[Long] = {