Skip to content

Commit

Permalink
Merge branch 'version-1.5.x' into node-2631-java-11
Browse files Browse the repository at this point in the history
  • Loading branch information
xrtm000 authored Nov 27, 2023
2 parents 0ef8edd + aa2cbf6 commit 9d8c70d
Show file tree
Hide file tree
Showing 124 changed files with 1,810 additions and 1,917 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ object StateSyntheticBenchmark {

val textScript = "sigVerify(tx.bodyBytes,tx.proofs[0],tx.senderPublicKey)"
val untypedScript = Parser.parseExpr(textScript).get.value
val typedScript = ExpressionCompiler(compilerContext(V1, Expression, isAssetScript = false), untypedScript).explicitGet()._1
val typedScript = ExpressionCompiler(compilerContext(V1, Expression, isAssetScript = false), V1, untypedScript).explicitGet()._1

val setScriptBlock = nextBlock(
Seq(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package com.wavesplatform.api.grpc.test
import com.google.protobuf.ByteString
import com.wavesplatform.account.KeyPair
import com.wavesplatform.api.grpc.{AssetInfoResponse, AssetsApiGrpcImpl, NFTRequest, NFTResponse}
import com.wavesplatform.block.Block.ProtoBlockVersion
import com.wavesplatform.db.WithDomain
import com.wavesplatform.db.WithState.AddrWithBalance
import com.wavesplatform.features.BlockchainFeatures
Expand Down Expand Up @@ -55,6 +56,49 @@ class AssetsApiGrpcSpec extends FreeSpec with BeforeAndAfterAll with DiffMatcher
}
}

"NODE-999. GetNftList limit should work properly" in withDomain(
RideV6.addFeatures(BlockchainFeatures.ReduceNFTFee),
AddrWithBalance.enoughBalances(sender)
) { d =>
val nftIssues = (1 to 5).map(idx => TxHelpers.issue(sender, 1, name = s"nft$idx", reissuable = false))
val limit = 2
val afterId = 1 // second element

d.appendBlock()
val mb1 = d.appendMicroBlock(nftIssues.take(afterId + 1)*)
d.appendMicroBlock(nftIssues.drop(afterId + 1)*)

// full liquid
d.rocksDBWriter.containsTransaction(nftIssues(afterId)) shouldBe false
d.rocksDBWriter.containsTransaction(nftIssues(afterId + 1)) shouldBe false
check()

// liquid afterId
d.appendBlock(d.createBlock(ProtoBlockVersion, nftIssues.drop(afterId + 1), Some(mb1)))
d.rocksDBWriter.containsTransaction(nftIssues(afterId)) shouldBe true
d.rocksDBWriter.containsTransaction(nftIssues(afterId + 1)) shouldBe false
check()

// full solid
d.appendBlock()
d.rocksDBWriter.containsTransaction(nftIssues(afterId)) shouldBe true
d.rocksDBWriter.containsTransaction(nftIssues(afterId + 1)) shouldBe true
check()

def check() = {
val (observer, result) = createObserver[NFTResponse]
val request = NFTRequest.of(
ByteString.copyFrom(sender.toAddress.bytes),
limit,
afterAssetId = ByteString.copyFrom(nftIssues(afterId).asset.id.arr)
)
getGrpcApi(d).getNFTList(request, observer)
val response = result.runSyncUnsafe()
response.size shouldBe limit
response.map(_.assetInfo.get.name) shouldBe nftIssues.slice(afterId + 1, afterId + limit + 1).map(_.name.toStringUtf8)
}
}

private def getGrpcApi(d: Domain) =
new AssetsApiGrpcImpl(d.assetsApi, d.accountsApi)
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package com.wavesplatform.api.grpc.test

import scala.concurrent.{Await, Future}
import scala.concurrent.duration.Duration
import scala.concurrent.duration.*
import com.wavesplatform.account.Address
import com.wavesplatform.common.state.ByteStr
import com.wavesplatform.test.{FlatSpec, TestTime}
Expand Down Expand Up @@ -91,7 +91,7 @@ class GRPCBroadcastSpec extends FlatSpec with BeforeAndAfterAll with PathMockFac

@throws[StatusException]("on failed broadcast")
def assertBroadcast(tx: Transaction): Unit = {
Await.result(grpcTxApi.broadcast(PBTransactions.protobuf(tx)), Duration.Inf)
Await.result(grpcTxApi.broadcast(PBTransactions.protobuf(tx)), 10.seconds)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -420,7 +420,7 @@ class BlockchainUpdatesSpec extends FreeSpec with WithBUDomain with ScalaFutures
(1 to blocksCount + 1).foreach(_ => d.appendBlock())

val result = Await
.result(r.getBlockUpdatesRange(GetBlockUpdatesRangeRequest(1, blocksCount)), Duration.Inf)
.result(r.getBlockUpdatesRange(GetBlockUpdatesRangeRequest(1, blocksCount)), 1.minute)
.updates
.map(_.update.append.map(_.getBlock.vrf.toByteStr).filterNot(_.isEmpty))

Expand Down Expand Up @@ -1215,7 +1215,7 @@ class BlockchainUpdatesSpec extends FreeSpec with WithBUDomain with ScalaFutures
Await
.result(
repo.getBlockUpdate(GetBlockUpdateRequest(height)),
Duration.Inf
1.minute
)
.getUpdate
.update
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
package com.wavesplatform.lang.v1.compiler

import java.nio.charset.StandardCharsets

import cats.Show
import com.wavesplatform.lang.v1.ContractLimits
import com.wavesplatform.lang.v1.compiler.Types.*
import com.wavesplatform.lang.v1.evaluator.ctx.FunctionTypeSignature
import com.wavesplatform.lang.v1.parser.Expressions
import com.wavesplatform.lang.v1.parser.Expressions.{Declaration, PART}

import java.nio.charset.StandardCharsets

sealed trait CompilationError {
def start: Int
def end: Int
Expand Down Expand Up @@ -52,18 +52,11 @@ object CompilationError {
s"but ${names.map(n => s"`$n`").mkString(", ")} found"
}

final case class UnusedCaseVariables(start: Int, end: Int, names: List[String]) extends CompilationError {
val message = s"Unused case variable(s) ${names.map(n => s"`$n`").mkString(", ")}"
}

final case class AlreadyDefined(start: Int, end: Int, name: String, isFunction: Boolean) extends CompilationError {
val message =
if (isFunction) s"Value '$name' can't be defined because function with this name is already defined"
else s"Value '$name' already defined in the scope"
}
final case class NonExistingType(start: Int, end: Int, name: String, existing: List[String]) extends CompilationError {
val message = s"Value '$name' declared as non-existing type, while all possible types are $existing"
}

final case class BadFunctionSignatureSameArgNames(start: Int, end: Int, name: String) extends CompilationError {
val message = s"Function '$name' declared with duplicating argument names"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.wavesplatform.lang.v1.compiler

import com.wavesplatform.lang.v1.compiler.Types.FINAL
import com.wavesplatform.lang.v1.parser.Expressions

case class CompilationStepResultDec(
ctx: CompilerContext,
dec: Terms.DECLARATION,
t: FINAL,
parseNodeExpr: Expressions.Declaration,
errors: Iterable[CompilationError] = Iterable.empty
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.wavesplatform.lang.v1.compiler

import com.wavesplatform.lang.v1.compiler.Types.FINAL
import com.wavesplatform.lang.v1.parser.Expressions

case class CompilationStepResultExpr(
ctx: CompilerContext,
expr: Terms.EXPR,
t: FINAL,
parseNodeExpr: Expressions.EXPR,
errors: Iterable[CompilationError] = Iterable.empty
)
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import com.wavesplatform.lang.contract.meta.{MetaMapper, V1 as MetaV1, V2 as Met
import com.wavesplatform.lang.directives.values.{StdLibVersion, V3, V6}
import com.wavesplatform.lang.v1.compiler.CompilationError.{AlreadyDefined, Generic, UnionNotAllowedForCallableArgs, WrongArgumentType}
import com.wavesplatform.lang.v1.compiler.CompilerContext.{VariableInfo, vars}
import com.wavesplatform.lang.v1.compiler.ExpressionCompiler.*
import com.wavesplatform.lang.v1.compiler.ContractCompiler.*
import com.wavesplatform.lang.v1.compiler.ScriptResultSource.FreeCall
import com.wavesplatform.lang.v1.compiler.Terms.EXPR
import com.wavesplatform.lang.v1.compiler.Types.{BOOLEAN, BYTESTR, LONG, STRING}
Expand All @@ -25,16 +25,13 @@ import com.wavesplatform.lang.v1.parser.Expressions.{FUNC, PART, Type}
import com.wavesplatform.lang.v1.parser.Parser.LibrariesOffset
import com.wavesplatform.lang.v1.parser.{Expressions, Parser}
import com.wavesplatform.lang.v1.task.imports.*
import com.wavesplatform.lang.v1.{ContractLimits, FunctionHeader, compiler}
import com.wavesplatform.lang.v1.{ContractLimits, FunctionHeader}

import scala.annotation.tailrec

object ContractCompiler {
val FreeCallInvocationArg = "i"

class ContractCompiler(version: StdLibVersion) extends ExpressionCompiler(version) {
private def compileAnnotatedFunc(
af: Expressions.ANNOTATEDFUNC,
version: StdLibVersion,
saveExprContext: Boolean,
allowIllFormedStrings: Boolean,
source: ScriptResultSource
Expand Down Expand Up @@ -88,10 +85,10 @@ object ContractCompiler {
_.flatMap(_.dic(version).toList).map(nameAndType => (nameAndType._1, VariableInfo(AnyPos, nameAndType._2)))
)
.getOrElse(List.empty)
unionInCallableErrs <- checkCallableUnions(af, annotationsWithErr._1.toList.flatten, version)
unionInCallableErrs <- checkCallableUnions(af, annotationsWithErr._1.toList.flatten)
compiledBody <- local {
modify[Id, CompilerContext, CompilationError](vars.modify(_)(_ ++ annotationBindings)).flatMap(_ =>
compiler.ExpressionCompiler.compileFunc(af.f.position, af.f, saveExprContext, annotationBindings.map(_._1), allowIllFormedStrings)
compileFunc(af.f.position, af.f, saveExprContext, annotationBindings.map(_._1), allowIllFormedStrings)
)
}
annotatedFuncWithErr <- getCompiledAnnotatedFunc(annotationsWithErr, compiledBody._1).handleError()
Expand Down Expand Up @@ -132,7 +129,6 @@ object ContractCompiler {

private def compileContract(
parsedDapp: Expressions.DAPP,
version: StdLibVersion,
needCompaction: Boolean,
removeUnusedCode: Boolean,
source: ScriptResultSource,
Expand All @@ -149,7 +145,7 @@ object ContractCompiler {
annFuncArgTypesErr <- validateAnnotatedFuncsArgTypes(parsedDapp).handleError()
compiledAnnFuncsWithErr <- parsedDapp.fs
.traverse[CompileM, (Option[AnnotatedFunction], List[(String, Types.FINAL)], Expressions.ANNOTATEDFUNC, Iterable[CompilationError])](af =>
local(compileAnnotatedFunc(af, version, saveExprContext, allowIllFormedStrings, source))
local(compileAnnotatedFunc(af, saveExprContext, allowIllFormedStrings, source))
)
annotatedFuncs = compiledAnnFuncsWithErr.filter(_._1.nonEmpty).map(_._1.get)
parsedNodeAFuncs = compiledAnnFuncsWithErr.map(_._3)
Expand Down Expand Up @@ -236,7 +232,7 @@ object ContractCompiler {
} yield result
}

def handleValid[T](part: PART[T]): CompileM[PART.VALID[T]] = part match {
private def handleValid[T](part: PART[T]): CompileM[PART.VALID[T]] = part match {
case x: PART.VALID[T] => x.pure[CompileM]
case PART.INVALID(p, message) => raiseError(Generic(p.start, p.end, message))
}
Expand Down Expand Up @@ -305,13 +301,7 @@ object ContractCompiler {
}
}

val primitiveCallableTypes: Set[String] =
Set(LONG, BYTESTR, BOOLEAN, STRING).map(_.name)

val allowedCallableTypesV4: Set[String] =
primitiveCallableTypes + "List[]"

private def validateDuplicateVarsInContract(contract: Expressions.DAPP): CompileM[Any] = {
private def validateDuplicateVarsInContract(contract: Expressions.DAPP): CompileM[Any] =
for {
ctx <- get[Id, CompilerContext, CompilationError]
annotationVars = contract.fs.flatMap(_.anns.flatMap(_.args)).traverse[CompileM, PART.VALID[String]](handleValid)
Expand Down Expand Up @@ -339,7 +329,52 @@ object ContractCompiler {
}
}
} yield ()

private def checkCallableUnions(
func: Expressions.ANNOTATEDFUNC,
annotations: List[Annotation],
): CompileM[Seq[UnionNotAllowedForCallableArgs]] = {
@tailrec
def containsUnion(tpe: Type): Boolean =
tpe match {
case Expressions.Union(types) if types.size > 1 => true
case Expressions.Single(PART.VALID(_, Type.ListTypeName), Some(PART.VALID(_, Expressions.Union(types)))) if types.size > 1 => true
case Expressions.Single(
PART.VALID(_, Type.ListTypeName),
Some(PART.VALID(_, inner @ Expressions.Single(PART.VALID(_, Type.ListTypeName), _)))
) =>
containsUnion(inner)
case _ => false
}

val isCallable = annotations.exists {
case CallableAnnotation(_) => true
case _ => false
}

if (version < V6 || !isCallable) {
Seq.empty[UnionNotAllowedForCallableArgs].pure[CompileM]
} else {
func.f.args
.filter { case (_, tpe) =>
containsUnion(tpe)
}
.map { case (argName, _) =>
UnionNotAllowedForCallableArgs(argName.position.start, argName.position.end)
}
.pure[CompileM]
}
}
}

object ContractCompiler {
val FreeCallInvocationArg = "i"

val primitiveCallableTypes: Set[String] =
Set(LONG, BYTESTR, BOOLEAN, STRING).map(_.name)

val allowedCallableTypesV4: Set[String] =
primitiveCallableTypes + "List[]"

def apply(
c: CompilerContext,
Expand All @@ -350,7 +385,8 @@ object ContractCompiler {
removeUnusedCode: Boolean = false,
allowIllFormedStrings: Boolean = false
): Either[String, DApp] = {
compileContract(contract, version, needCompaction, removeUnusedCode, source, allowIllFormedStrings = allowIllFormedStrings)
new ContractCompiler(version)
.compileContract(contract, needCompaction, removeUnusedCode, source, allowIllFormedStrings = allowIllFormedStrings)
.run(c)
.map(
_._2
Expand All @@ -375,7 +411,7 @@ object ContractCompiler {
val parser = new Parser(version)(offset)
parser.parseContract(input) match {
case fastparse.Parsed.Success(xs, _) =>
ContractCompiler(ctx, xs, version, source, needCompaction, removeUnusedCode, allowIllFormedStrings) match {
apply(ctx, xs, version, source, needCompaction, removeUnusedCode, allowIllFormedStrings) match {
case Left(err) => Left(err)
case Right(c) => Right(c)
}
Expand All @@ -396,7 +432,8 @@ object ContractCompiler {
new Parser(version)(offset)
.parseDAPPWithErrorRecovery(input)
.flatMap { case (parseResult, removedCharPosOpt) =>
compileContract(parseResult, version, needCompaction, removeUnusedCode, ScriptResultSource.CallableFunction, saveExprContext)
new ContractCompiler(version)
.compileContract(parseResult, needCompaction, removeUnusedCode, ScriptResultSource.CallableFunction, saveExprContext)
.run(ctx)
.map(
_._2
Expand Down Expand Up @@ -437,41 +474,4 @@ object ContractCompiler {
Left(parser.toString(input, f))
}
}

private def checkCallableUnions(
func: Expressions.ANNOTATEDFUNC,
annotations: List[Annotation],
version: StdLibVersion
): CompileM[Seq[UnionNotAllowedForCallableArgs]] = {
@tailrec
def containsUnion(tpe: Type): Boolean =
tpe match {
case Expressions.Union(types) if types.size > 1 => true
case Expressions.Single(PART.VALID(_, Type.ListTypeName), Some(PART.VALID(_, Expressions.Union(types)))) if types.size > 1 => true
case Expressions.Single(
PART.VALID(_, Type.ListTypeName),
Some(PART.VALID(_, inner @ Expressions.Single(PART.VALID(_, Type.ListTypeName), _)))
) =>
containsUnion(inner)
case _ => false
}

val isCallable = annotations.exists {
case CallableAnnotation(_) => true
case _ => false
}

if (version < V6 || !isCallable) {
Seq.empty[UnionNotAllowedForCallableArgs].pure[CompileM]
} else {
func.f.args
.filter { case (_, tpe) =>
containsUnion(tpe)
}
.map { case (argName, _) =>
UnionNotAllowedForCallableArgs(argName.position.start, argName.position.end)
}
.pure[CompileM]
}
}
}
Loading

0 comments on commit 9d8c70d

Please sign in to comment.