From dd62bd7475f3a4f4d1399bdca8e9dd2361e36255 Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Tue, 11 Jun 2024 17:15:07 +0300 Subject: [PATCH 1/9] failing tests --- .../utxo/BasicOpsSpecification.scala | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala index 79701d6e07..87a3697462 100644 --- a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala +++ b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala @@ -3,6 +3,7 @@ package sigmastate.utxo import org.ergoplatform.ErgoBox.{AdditionalRegisters, R6, R8} import org.ergoplatform._ import sigma.Extensions.ArrayOps +import sigma.VersionContext import sigma.ast.SCollection.SByteArray import sigma.ast.SType.AnyOps import sigma.data.{AvlTreeData, CAnyValue, CSigmaDslBuilder} @@ -157,6 +158,47 @@ class BasicOpsSpecification extends CompilerTestingCommons ) } + property("Lazy evaluation of default in Option.getOrElse") { + val customExt = Map ( + 1.toByte -> IntConstant(5) + ).toSeq + def optTest() = test("getOrElse", env, customExt, + """{ + | getVar[Int](1).getOrElse(getVar[Int](44).get) > 0 + |} + | + |""".stripMargin, + null + ) + + if(VersionContext.current.isV6SoftForkActivated) { + optTest() + } else { + an[Exception] shouldBe thrownBy(optTest()) + } + } + + property("Lazy evaluation of default in Coll.getOrElse") { + val customExt = Map ( + 1.toByte -> IntConstant(5) + ).toSeq + def optTest() = test("getOrElse", env, customExt, + """{ + | val c = Coll[Int](1) + | c.getOrElse(0, getVar[Int](44).get) > 0 + |} + | + |""".stripMargin, + null + ) + + if(VersionContext.current.isV6SoftForkActivated) { + optTest() + } else { + an[Exception] shouldBe thrownBy(optTest()) + } + } + property("Relation operations") { test("R1", env, ext, "{ allOf(Coll(getVar[Boolean](trueVar).get, true, true)) }", From aaef77e76f8b4be4c97520a56cc6b1492bb70791 Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Tue, 11 Jun 2024 17:46:20 +0300 Subject: [PATCH 2/9] close #906: lazy evaluation of default in Option.getOrElse and Coll.getOrElse --- .../main/scala/sigma/ast/transformers.scala | 43 ++++++++++++++----- .../utxo/BasicOpsSpecification.scala | 10 ++--- 2 files changed, 36 insertions(+), 17 deletions(-) diff --git a/data/shared/src/main/scala/sigma/ast/transformers.scala b/data/shared/src/main/scala/sigma/ast/transformers.scala index 939da79d98..8d7e689a18 100644 --- a/data/shared/src/main/scala/sigma/ast/transformers.scala +++ b/data/shared/src/main/scala/sigma/ast/transformers.scala @@ -10,7 +10,7 @@ import sigma.eval.ErgoTreeEvaluator.DataEnv import sigma.serialization.CoreByteWriter.ArgInfo import sigma.serialization.OpCodes import sigma.serialization.ValueCodes.OpCode -import sigma.{Box, Coll, Evaluation} +import sigma.{Box, Coll, Evaluation, VersionContext} // TODO refactor: remove this trait as it doesn't have semantic meaning @@ -258,10 +258,22 @@ case class ByIndex[V <: SType](input: Value[SCollection[V]], val indexV = index.evalTo[Int](env) default match { case Some(d) => - val dV = d.evalTo[V#WrappedType](env) - Value.checkType(d, dV) // necessary because cast to V#WrappedType is erased - addCost(ByIndex.costKind) - inputV.getOrElse(indexV, dV) + if (VersionContext.current.isV6SoftForkActivated) { + // lazy evaluation of default in 6.0 + addCost(ByIndex.costKind) + if (inputV.isDefinedAt(indexV)) { + inputV.apply(indexV) + } else { + val dV = d.evalTo[V#WrappedType](env) + Value.checkType(d, dV) // necessary because cast to V#WrappedType is erased + inputV.getOrElse(indexV, dV) + } + } else { + val dV = d.evalTo[V#WrappedType](env) + Value.checkType(d, dV) // necessary because cast to V#WrappedType is erased + addCost(ByIndex.costKind) + inputV.getOrElse(indexV, dV) + } case _ => addCost(ByIndex.costKind) inputV.apply(indexV) @@ -613,11 +625,22 @@ case class OptionGetOrElse[V <: SType](input: Value[SOption[V]], default: Value[ override val opType = SFunc(IndexedSeq(input.tpe, tpe), tpe) override def tpe: V = input.tpe.elemType protected final override def eval(env: DataEnv)(implicit E: ErgoTreeEvaluator): Any = { - val inputV = input.evalTo[Option[V#WrappedType]](env) - val dV = default.evalTo[V#WrappedType](env) // TODO v6.0: execute lazily (see https://github.com/ScorexFoundation/sigmastate-interpreter/issues/906) - Value.checkType(default, dV) // necessary because cast to V#WrappedType is erased - addCost(OptionGetOrElse.costKind) - inputV.getOrElse(dV) + if(VersionContext.current.isV6SoftForkActivated) { + // lazy evaluation of default in 6.0 + val inputV = input.evalTo[Option[V#WrappedType]](env) + addCost(OptionGetOrElse.costKind) + inputV.getOrElse { + val dV = default.evalTo[V#WrappedType](env) + Value.checkType(default, dV) // necessary because cast to V#WrappedType is erased + dV + } + } else { + val inputV = input.evalTo[Option[V#WrappedType]](env) + val dV = default.evalTo[V#WrappedType](env) + Value.checkType(default, dV) // necessary because cast to V#WrappedType is erased + addCost(OptionGetOrElse.costKind) + inputV.getOrElse(dV) + } } } object OptionGetOrElse extends ValueCompanion with FixedCostValueCompanion { diff --git a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala index 87a3697462..c1489355e6 100644 --- a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala +++ b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala @@ -166,7 +166,6 @@ class BasicOpsSpecification extends CompilerTestingCommons """{ | getVar[Int](1).getOrElse(getVar[Int](44).get) > 0 |} - | |""".stripMargin, null ) @@ -179,15 +178,12 @@ class BasicOpsSpecification extends CompilerTestingCommons } property("Lazy evaluation of default in Coll.getOrElse") { - val customExt = Map ( - 1.toByte -> IntConstant(5) - ).toSeq - def optTest() = test("getOrElse", env, customExt, + def optTest() = test("getOrElse", env, ext, """{ | val c = Coll[Int](1) - | c.getOrElse(0, getVar[Int](44).get) > 0 + | c.getOrElse(0, getVar[Int](44).get) > 0 && + | c.getOrElse(1, c.getOrElse(0, getVar[Int](44).get)) > 0 |} - | |""".stripMargin, null ) From f7f31e3614cbce8e8694d12773f2e17b2b391cf3 Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Thu, 13 Jun 2024 13:01:57 +0300 Subject: [PATCH 3/9] fix w/out tests (only manual tests are done) --- .../scala/sigma/data/CollsOverArrays.scala | 19 ++++++++++++++++--- .../utxo/BasicOpsSpecification.scala | 7 +++++++ 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/core/shared/src/main/scala/sigma/data/CollsOverArrays.scala b/core/shared/src/main/scala/sigma/data/CollsOverArrays.scala index 2413f7f427..01cad08471 100644 --- a/core/shared/src/main/scala/sigma/data/CollsOverArrays.scala +++ b/core/shared/src/main/scala/sigma/data/CollsOverArrays.scala @@ -135,7 +135,13 @@ class CollOverArray[@specialized A](val toArray: Array[A], val builder: CollBuil override def equals(obj: scala.Any): Boolean = (this eq obj.asInstanceOf[AnyRef]) || (obj match { case obj: CollOverArray[_] if obj.tItem == this.tItem => - java.util.Objects.deepEquals(obj.toArray, toArray) + java.util.Objects.deepEquals(obj.toArray, this.toArray) + case obj: PairColl[_, _] if obj.tItem == this.tItem => + if(VersionContext.current.isV6SoftForkActivated) { + java.util.Objects.deepEquals(obj.toArray, this.toArray) + } else { + false + } case _ => false }) @@ -237,8 +243,15 @@ private[sigma] class CollOverArrayBuilder extends CollBuilder { builder => class PairOfCols[@specialized L, @specialized R](val ls: Coll[L], val rs: Coll[R]) extends PairColl[L,R] { - override def equals(that: scala.Any) = (this eq that.asInstanceOf[AnyRef]) || (that match { - case that: PairColl[_,_] if that.tItem == this.tItem => ls == that.ls && rs == that.rs + override def equals(that: scala.Any): Boolean = (this eq that.asInstanceOf[AnyRef]) || (that match { + case that: PairColl[_,_] if that.tItem == this.tItem => + ls == that.ls && rs == that.rs + case that: CollOverArray[_] if that.tItem == this.tItem => + if (VersionContext.current.isV6SoftForkActivated) { + java.util.Objects.deepEquals(that.toArray, this.toArray) + } else { + false + } case _ => false }) diff --git a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala index 79701d6e07..705d83b56a 100644 --- a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala +++ b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala @@ -157,6 +157,13 @@ class BasicOpsSpecification extends CompilerTestingCommons ) } + property("coll equality") { + test("R1", env, ext, + "{ SELF.tokens == Coll[(Coll[Byte], Long)]() }", + null + ) + } + property("Relation operations") { test("R1", env, ext, "{ allOf(Coll(getVar[Boolean](trueVar).get, true, true)) }", From 4c63a60e981743fd10c29a4b87b8e996ed5b749d Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Tue, 30 Jul 2024 19:30:54 +0300 Subject: [PATCH 4/9] LSV5 & LSV6 tests --- .../scala/sigma/LanguageSpecificationV5.scala | 146 +++++++++--------- .../scala/sigma/LanguageSpecificationV6.scala | 60 ++++++- 2 files changed, 134 insertions(+), 72 deletions(-) diff --git a/sc/shared/src/test/scala/sigma/LanguageSpecificationV5.scala b/sc/shared/src/test/scala/sigma/LanguageSpecificationV5.scala index 700b48fd13..347a7b90f4 100644 --- a/sc/shared/src/test/scala/sigma/LanguageSpecificationV5.scala +++ b/sc/shared/src/test/scala/sigma/LanguageSpecificationV5.scala @@ -7957,77 +7957,81 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => ) ) ) - verifyCases( - // (coll, (index, default)) - { - def success[T](v: T) = Expected(Success(v), 1773, costDetails, 1773) - Seq( - ((Coll[Int](), (0, default)), success(default)), - ((Coll[Int](), (-1, default)), success(default)), - ((Coll[Int](1), (0, default)), success(1)), - ((Coll[Int](1), (1, default)), success(default)), - ((Coll[Int](1), (-1, default)), success(default)), - ((Coll[Int](1, 2), (0, default)), success(1)), - ((Coll[Int](1, 2), (1, default)), success(2)), - ((Coll[Int](1, 2), (2, default)), success(default)), - ((Coll[Int](1, 2), (-1, default)), success(default)) - ) - }, - existingFeature((x: (Coll[Int], (Int, Int))) => x._1.getOrElse(x._2._1, x._2._2), - "{ (x: (Coll[Int], (Int, Int))) => x._1.getOrElse(x._2._1, x._2._2) }", - if (lowerMethodCallsInTests) - FuncValue( - Vector((1, SPair(SCollectionType(SInt), SPair(SInt, SInt)))), - BlockValue( - Vector( - ValDef( - 3, - List(), - SelectField.typed[Value[STuple]]( - ValUse(1, SPair(SCollectionType(SInt), SPair(SInt, SInt))), - 2.toByte + + if(!VersionContext.current.isV6SoftForkActivated) { + verifyCases( + // (coll, (index, default)) + { + def success[T](v: T) = Expected(Success(v), 1773, costDetails, 1773) + + Seq( + ((Coll[Int](), (0, default)), success(default)), + ((Coll[Int](), (-1, default)), success(default)), + ((Coll[Int](1), (0, default)), success(1)), + ((Coll[Int](1), (1, default)), success(default)), + ((Coll[Int](1), (-1, default)), success(default)), + ((Coll[Int](1, 2), (0, default)), success(1)), + ((Coll[Int](1, 2), (1, default)), success(2)), + ((Coll[Int](1, 2), (2, default)), success(default)), + ((Coll[Int](1, 2), (-1, default)), success(default)) + ) + }, + existingFeature((x: (Coll[Int], (Int, Int))) => x._1.getOrElse(x._2._1, x._2._2), + "{ (x: (Coll[Int], (Int, Int))) => x._1.getOrElse(x._2._1, x._2._2) }", + if (lowerMethodCallsInTests) + FuncValue( + Vector((1, SPair(SCollectionType(SInt), SPair(SInt, SInt)))), + BlockValue( + Vector( + ValDef( + 3, + List(), + SelectField.typed[Value[STuple]]( + ValUse(1, SPair(SCollectionType(SInt), SPair(SInt, SInt))), + 2.toByte + ) ) - ) - ), - ByIndex( - SelectField.typed[Value[SCollection[SInt.type]]]( - ValUse(1, SPair(SCollectionType(SInt), SPair(SInt, SInt))), - 1.toByte ), - SelectField.typed[Value[SInt.type]](ValUse(3, SPair(SInt, SInt)), 1.toByte), - Some(SelectField.typed[Value[SInt.type]](ValUse(3, SPair(SInt, SInt)), 2.toByte)) + ByIndex( + SelectField.typed[Value[SCollection[SInt.type]]]( + ValUse(1, SPair(SCollectionType(SInt), SPair(SInt, SInt))), + 1.toByte + ), + SelectField.typed[Value[SInt.type]](ValUse(3, SPair(SInt, SInt)), 1.toByte), + Some(SelectField.typed[Value[SInt.type]](ValUse(3, SPair(SInt, SInt)), 2.toByte)) + ) ) ) - ) - else - FuncValue( - Array((1, SPair(SCollectionType(SInt), SPair(SInt, SInt)))), - BlockValue( - Array( - ValDef( - 3, - List(), - SelectField.typed[Value[STuple]]( - ValUse(1, SPair(SCollectionType(SInt), SPair(SInt, SInt))), - 2.toByte + else + FuncValue( + Array((1, SPair(SCollectionType(SInt), SPair(SInt, SInt)))), + BlockValue( + Array( + ValDef( + 3, + List(), + SelectField.typed[Value[STuple]]( + ValUse(1, SPair(SCollectionType(SInt), SPair(SInt, SInt))), + 2.toByte + ) ) - ) - ), - MethodCall.typed[Value[SInt.type]]( - SelectField.typed[Value[SCollection[SInt.type]]]( - ValUse(1, SPair(SCollectionType(SInt), SPair(SInt, SInt))), - 1.toByte ), - SCollectionMethods.getMethodByName("getOrElse").withConcreteTypes(Map(STypeVar("IV") -> SInt)), - Vector( - SelectField.typed[Value[SInt.type]](ValUse(3, SPair(SInt, SInt)), 1.toByte), - SelectField.typed[Value[SInt.type]](ValUse(3, SPair(SInt, SInt)), 2.toByte) - ), - Map() + MethodCall.typed[Value[SInt.type]]( + SelectField.typed[Value[SCollection[SInt.type]]]( + ValUse(1, SPair(SCollectionType(SInt), SPair(SInt, SInt))), + 1.toByte + ), + SCollectionMethods.getMethodByName("getOrElse").withConcreteTypes(Map(STypeVar("IV") -> SInt)), + Vector( + SelectField.typed[Value[SInt.type]](ValUse(3, SPair(SInt, SInt)), 1.toByte), + SelectField.typed[Value[SInt.type]](ValUse(3, SPair(SInt, SInt)), 2.toByte) + ), + Map() + ) ) ) - ) - )) + )) + } } property("Tuple size method equivalence") { @@ -8591,13 +8595,15 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => "{ (x: Option[Long]) => x.isDefined }", FuncValue(Vector((1, SOption(SLong))), OptionIsDefined(ValUse(1, SOption(SLong)))))) - verifyCases( - Seq( - (None -> Expected(Success(1L), 1766, costDetails3, 1766)), - (Some(10L) -> Expected(Success(10L), 1766, costDetails3, 1766))), - existingFeature({ (x: Option[Long]) => x.getOrElse(1L) }, - "{ (x: Option[Long]) => x.getOrElse(1L) }", - FuncValue(Vector((1, SOption(SLong))), OptionGetOrElse(ValUse(1, SOption(SLong)), LongConstant(1L))))) + if (!VersionContext.current.isV6SoftForkActivated) { + verifyCases( + Seq( + (None -> Expected(Success(1L), 1766, costDetails3, 1766)), + (Some(10L) -> Expected(Success(10L), 1766, costDetails3, 1766))), + existingFeature({ (x: Option[Long]) => x.getOrElse(1L) }, + "{ (x: Option[Long]) => x.getOrElse(1L) }", + FuncValue(Vector((1, SOption(SLong))), OptionGetOrElse(ValUse(1, SOption(SLong)), LongConstant(1L))))) + } verifyCases( Seq( diff --git a/sc/shared/src/test/scala/sigma/LanguageSpecificationV6.scala b/sc/shared/src/test/scala/sigma/LanguageSpecificationV6.scala index 3b3de407b5..612f0e33c3 100644 --- a/sc/shared/src/test/scala/sigma/LanguageSpecificationV6.scala +++ b/sc/shared/src/test/scala/sigma/LanguageSpecificationV6.scala @@ -1,8 +1,9 @@ package sigma -import sigma.ast.{Apply, Downcast, FixedCost, FixedCostItem, FuncValue, GetVar, JitCost, OptionGet, SBigInt, SByte, SInt, SLong, SShort, ValUse} +import sigma.ast.{Apply, ArithOp, BlockValue, ByIndex, CompanionDesc, Constant, Downcast, FixedCost, FixedCostItem, FuncValue, GetVar, IntConstant, JitCost, LongConstant, MethodCall, OptionGet, OptionGetOrElse, PerItemCost, SBigInt, SByte, SCollection, SCollectionMethods, SCollectionType, SInt, SLong, SOption, SPair, SShort, STuple, STypeVar, SelectField, ValDef, ValUse, Value} import sigma.data.{CBigInt, ExactNumeric} -import sigma.eval.SigmaDsl +import sigma.eval.{SigmaDsl, TracedCost} +import sigma.serialization.ValueCodes.OpCode import sigma.util.Extensions.{BooleanOps, ByteOps, IntOps, LongOps} import sigmastate.exceptions.MethodNotFound @@ -168,7 +169,62 @@ class LanguageSpecificationV6 extends LanguageSpecificationBase { suite => Seq(compareTo, bitOr, bitAnd).foreach(_.checkEquality(x)) } } + } + + property("Option.getOrElse with lazy default") { + def getOrElse = newFeature( + { (x: Option[Long]) => x.getOrElse(1 / 0L) }, + "{ (x: Option[Long]) => x.getOrElse(1 / 0L) }", + FuncValue( + Array((1, SOption(SLong))), + OptionGetOrElse( + ValUse(1, SOption(SLong)), + ArithOp(LongConstant(1L), LongConstant(0L), OpCode @@ (-99.toByte)) + ) + ) + ) + if (VersionContext.current.isV6SoftForkActivated) { + forAll { x: Option[Long] => + Seq(getOrElse).map(_.checkEquality(x)) + } + } else { + forAll { x: Option[Long] => + if (x.isEmpty) { + Seq(getOrElse).map(_.checkEquality(x)) + } + } + } + } + + property("Coll getOrElse with lazy default") { + def getOrElse = newFeature( + (x: (Coll[Int], Int)) => x._1.toArray.unapply(x._2).getOrElse(1 / 0), + "{ (x: (Coll[Int], Int)) => x._1.getOrElse(x._2, 1 / 0) }", + FuncValue( + Array((1, SPair(SCollectionType(SInt), SInt))), + ByIndex( + SelectField.typed[Value[SCollection[SInt.type]]]( + ValUse(1, SPair(SCollectionType(SInt), SInt)), + 1.toByte + ), + SelectField.typed[Value[SInt.type]](ValUse(1, SPair(SCollectionType(SInt), SInt)), 2.toByte), + Some(ArithOp(IntConstant(1), IntConstant(0), OpCode @@ (-99.toByte))) + ) + ) + ) + + if (VersionContext.current.isV6SoftForkActivated) { + forAll { x: (Coll[Int], Int) => + Seq(getOrElse).map(_.checkEquality(x)) + } + } else { + forAll { x: (Coll[Int], Int) => + if (x._1.isEmpty) { + Seq(getOrElse).map(_.checkEquality(x)) + } + } + } } property("BigInt methods equivalence (new features)") { From 61f90cd339b9a79ce20154f45f3db2980be9dc4c Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Wed, 31 Jul 2024 14:04:30 +0300 Subject: [PATCH 5/9] assertEXceptionThrown --- sc/shared/src/test/scala/sigma/LanguageSpecificationV6.scala | 2 +- .../test/scala/sigmastate/utxo/BasicOpsSpecification.scala | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/sc/shared/src/test/scala/sigma/LanguageSpecificationV6.scala b/sc/shared/src/test/scala/sigma/LanguageSpecificationV6.scala index 612f0e33c3..b4fb5b12fb 100644 --- a/sc/shared/src/test/scala/sigma/LanguageSpecificationV6.scala +++ b/sc/shared/src/test/scala/sigma/LanguageSpecificationV6.scala @@ -199,7 +199,7 @@ class LanguageSpecificationV6 extends LanguageSpecificationBase { suite => property("Coll getOrElse with lazy default") { def getOrElse = newFeature( - (x: (Coll[Int], Int)) => x._1.toArray.unapply(x._2).getOrElse(1 / 0), + (x: (Coll[Int], Int)) => x._1.toArray.toIndexedSeq.unapply(x._2).getOrElse(1 / 0), "{ (x: (Coll[Int], Int)) => x._1.getOrElse(x._2, 1 / 0) }", FuncValue( Array((1, SPair(SCollectionType(SInt), SInt))), diff --git a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala index c1489355e6..3d25326660 100644 --- a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala +++ b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala @@ -170,10 +170,10 @@ class BasicOpsSpecification extends CompilerTestingCommons null ) - if(VersionContext.current.isV6SoftForkActivated) { + if (VersionContext.current.isV6SoftForkActivated) { optTest() } else { - an[Exception] shouldBe thrownBy(optTest()) + assertExceptionThrown(optTest(), _.isInstanceOf[NoSuchElementException]) } } From 26809c94f0ed8aca3d56fabb10995fb30e2889e0 Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Fri, 2 Aug 2024 13:58:07 +0300 Subject: [PATCH 6/9] passing but improper changedFeature test --- .gitignore | 1 + .../scala/sigma/LanguageSpecificationV6.scala | 48 +++++++++---------- 2 files changed, 25 insertions(+), 24 deletions(-) diff --git a/.gitignore b/.gitignore index df18ce8ab1..d328645cde 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,7 @@ *.fdb_latexmk *.gz +yarn.lock *.log docs/spec/out/ test-out/ diff --git a/sc/shared/src/test/scala/sigma/LanguageSpecificationV6.scala b/sc/shared/src/test/scala/sigma/LanguageSpecificationV6.scala index b4fb5b12fb..9e9827df1f 100644 --- a/sc/shared/src/test/scala/sigma/LanguageSpecificationV6.scala +++ b/sc/shared/src/test/scala/sigma/LanguageSpecificationV6.scala @@ -1,14 +1,14 @@ package sigma -import sigma.ast.{Apply, ArithOp, BlockValue, ByIndex, CompanionDesc, Constant, Downcast, FixedCost, FixedCostItem, FuncValue, GetVar, IntConstant, JitCost, LongConstant, MethodCall, OptionGet, OptionGetOrElse, PerItemCost, SBigInt, SByte, SCollection, SCollectionMethods, SCollectionType, SInt, SLong, SOption, SPair, SShort, STuple, STypeVar, SelectField, ValDef, ValUse, Value} +import sigma.ast.{Apply, ByIndex, Downcast, FixedCost, FixedCostItem, FuncValue, GetVar, IntConstant, JitCost, LongConstant, MethodCall, OptionGet, OptionGetOrElse, PerItemCost, SBigInt, SByte, SCollection, SCollectionMethods, SCollectionType, SInt, SLong, SOption, SPair, SShort, STuple, STypeVar, SelectField, ValDef, ValUse, Value} import sigma.data.{CBigInt, ExactNumeric} -import sigma.eval.{SigmaDsl, TracedCost} +import sigma.eval.{CostDetails, SigmaDsl, TracedCost} import sigma.serialization.ValueCodes.OpCode import sigma.util.Extensions.{BooleanOps, ByteOps, IntOps, LongOps} import sigmastate.exceptions.MethodNotFound import java.math.BigInteger -import scala.util.Success +import scala.util.{Failure, Success} /** This suite tests all operations for v6.0 version of the language. * The base classes establish the infrastructure for the tests. @@ -172,29 +172,29 @@ class LanguageSpecificationV6 extends LanguageSpecificationBase { suite => } property("Option.getOrElse with lazy default") { - def getOrElse = newFeature( - { (x: Option[Long]) => x.getOrElse(1 / 0L) }, - "{ (x: Option[Long]) => x.getOrElse(1 / 0L) }", - FuncValue( - Array((1, SOption(SLong))), - OptionGetOrElse( - ValUse(1, SOption(SLong)), - ArithOp(LongConstant(1L), LongConstant(0L), OpCode @@ (-99.toByte)) - ) + verifyCases( + Seq( + Some(0L) -> Expected(Failure(new java.lang.ArithmeticException("/ by zero")), 6, CostDetails.ZeroCost, 1793, + newVersionedResults = { + Seq(0 -> (ExpectedResult(Success(6L), Some(1793)) -> None)) + } ), + None -> Expected(Failure(new java.lang.ArithmeticException("/ by zero")), 6) + ), + changedFeature( + { (x: Option[Long]) => val default = 1 / 0L; x.getOrElse(default) }, + { (x: Option[Long]) => if (VersionContext.current.isV6SoftForkActivated) {x.getOrElse(1 / 0L)} else {val default = 1 / 0L; x.getOrElse(default)} }, + "{ (x: Option[Long]) => x.getOrElse(1 / 0L) }", + FuncValue( + Array((1, SOption(SLong))), + OptionGetOrElse( + ValUse(1, SOption(SLong)), + ArithOp(LongConstant(1L), LongConstant(0L), OpCode @@ (-99.toByte)) + ) + ), + allowNewToSucceed = true, + changedIn = VersionContext.V6SoftForkVersion ) ) - - if (VersionContext.current.isV6SoftForkActivated) { - forAll { x: Option[Long] => - Seq(getOrElse).map(_.checkEquality(x)) - } - } else { - forAll { x: Option[Long] => - if (x.isEmpty) { - Seq(getOrElse).map(_.checkEquality(x)) - } - } - } } property("Coll getOrElse with lazy default") { From 8da35750e295b0fa95e440c21316d147c45b1f1d Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Fri, 9 Aug 2024 17:33:12 +0300 Subject: [PATCH 7/9] fixed tests in LSV6 --- .../scala/sigma/LanguageSpecificationV6.scala | 79 ++++++++++++------- .../test/scala/sigma/SigmaDslTesting.scala | 13 ++- 2 files changed, 60 insertions(+), 32 deletions(-) diff --git a/sc/shared/src/test/scala/sigma/LanguageSpecificationV6.scala b/sc/shared/src/test/scala/sigma/LanguageSpecificationV6.scala index 4e6641984b..d63d6aae65 100644 --- a/sc/shared/src/test/scala/sigma/LanguageSpecificationV6.scala +++ b/sc/shared/src/test/scala/sigma/LanguageSpecificationV6.scala @@ -467,7 +467,7 @@ class LanguageSpecificationV6 extends LanguageSpecificationBase { suite => property("Option.getOrElse with lazy default") { - val someTrace = TracedCost( + val trace = TracedCost( Array( FixedCostItem(Apply), FixedCostItem(FuncValue), @@ -481,11 +481,11 @@ class LanguageSpecificationV6 extends LanguageSpecificationBase { suite => verifyCases( Seq( - Some(2L) -> Expected(Failure(new java.lang.ArithmeticException("/ by zero")), 6, someTrace, 1793, + Some(2L) -> Expected(Failure(new java.lang.ArithmeticException("/ by zero")), 6, trace, 1793, newVersionedResults = { - expectedSuccessForAllTreeVersions(2L, 2015, someTrace) + expectedSuccessForAllTreeVersions(2L, 2015, trace) } ), - // None -> Expected(Failure(new java.lang.ArithmeticException("/ by zero")), 6) + None -> Expected(Failure(new java.lang.ArithmeticException("/ by zero")), 6, trace, 1793) ), changedFeature( changedInVersion = VersionContext.V6SoftForkVersion, @@ -503,35 +503,56 @@ class LanguageSpecificationV6 extends LanguageSpecificationBase { suite => ) ) } -/* + property("Coll getOrElse with lazy default") { - def getOrElse = newFeature( - (x: (Coll[Int], Int)) => x._1.toArray.toIndexedSeq.unapply(x._2).getOrElse(1 / 0), - "{ (x: (Coll[Int], Int)) => x._1.getOrElse(x._2, 1 / 0) }", - FuncValue( - Array((1, SPair(SCollectionType(SInt), SInt))), - ByIndex( - SelectField.typed[Value[SCollection[SInt.type]]]( - ValUse(1, SPair(SCollectionType(SInt), SInt)), - 1.toByte - ), - SelectField.typed[Value[SInt.type]](ValUse(1, SPair(SCollectionType(SInt), SInt)), 2.toByte), - Some(ArithOp(IntConstant(1), IntConstant(0), OpCode @@ (-99.toByte))) - ) + + val trace = TracedCost( + Array( + FixedCostItem(Apply), + FixedCostItem(FuncValue), + FixedCostItem(GetVar), + FixedCostItem(OptionGet), + FixedCostItem(FuncValue.AddToEnvironmentDesc, FixedCost(JitCost(5))), + FixedCostItem(ValUse), + FixedCostItem(Constant), + FixedCostItem(ByIndex) ) ) - if (VersionContext.current.isV6SoftForkActivated) { - forAll { x: (Coll[Int], Int) => - Seq(getOrElse).map(_.checkEquality(x)) - } - } else { - forAll { x: (Coll[Int], Int) => - if (x._1.isEmpty) { - Seq(getOrElse).map(_.checkEquality(x)) - } - } + def scalaFuncNew(x: Coll[Int]) = { + if (VersionContext.current.isV6SoftForkActivated) { + x.toArray.toIndexedSeq.headOption.getOrElse(1 / 0) + } else scalaFuncOld(x) + } + + def scalaFuncOld(x: Coll[Int]) = { + x.getOrElse(0, 1 / 0) } + + verifyCases( + Seq( + Coll(1) -> Expected(Failure(new java.lang.ArithmeticException("/ by zero")), 6, trace, 1793, + newVersionedResults = { + expectedSuccessForAllTreeVersions(1, 2029, trace) + } ), + Coll[Int]() -> Expected(Failure(new java.lang.ArithmeticException("/ by zero")), 6, trace, 1793) + ), + changedFeature( + changedInVersion = VersionContext.V6SoftForkVersion, + scalaFuncOld, + scalaFuncNew, + "{ (x: Coll[Int]) => x.getOrElse(0, 1 / 0) }", + FuncValue( + Array((1, SCollectionType(SInt))), + ByIndex( + ValUse(1, SCollectionType(SInt)), + IntConstant(0), + Some(ArithOp(IntConstant(1), IntConstant(0), OpCode @@ (-99.toByte))) + ) + ), + allowNewToSucceed = true + ) + ) } - */ + } diff --git a/sc/shared/src/test/scala/sigma/SigmaDslTesting.scala b/sc/shared/src/test/scala/sigma/SigmaDslTesting.scala index 58873449b4..cf2fd98ebf 100644 --- a/sc/shared/src/test/scala/sigma/SigmaDslTesting.scala +++ b/sc/shared/src/test/scala/sigma/SigmaDslTesting.scala @@ -261,6 +261,7 @@ class SigmaDslTesting extends AnyPropSpec s"""Should succeed with the same value or fail with the same exception, but was: |First result: $b1 |Second result: $b2 + |Input: $x |Root cause: $cause |""".stripMargin) } @@ -715,11 +716,17 @@ class SigmaDslTesting extends AnyPropSpec override def checkEquality(input: A, logInputOutput: Boolean = false): Try[(B, CostDetails)] = { // check the old implementation against Scala semantic function var oldRes: Try[(B, CostDetails)] = null - if (ergoTreeVersionInTests < VersionContext.JitActivationVersion) oldRes = VersionContext.withVersions(activatedVersionInTests, ergoTreeVersionInTests) { try checkEq(scalaFunc)(oldF)(input) catch { - case e: TestFailedException => throw e + case e: TestFailedException => + if(activatedVersionInTests < changedInVersion) { + throw e + } else { + // old ergoscript may succeed in new version while old scalafunc may fail, + // see e.g. "Option.getOrElse with lazy default" test + Failure(e) + } case t: Throwable => Failure(t) } @@ -764,7 +771,7 @@ class SigmaDslTesting extends AnyPropSpec override def checkExpected(input: A, expected: Expected[B]): Unit = { // check the new implementation with Scala semantic function val newRes = VersionContext.withVersions(activatedVersionInTests, ergoTreeVersionInTests) { - checkEq(scalaFuncNew)(newF)(input) + checkEq(scalaFuncNew)(newF)(input) } if (VersionContext.current.activatedVersion < changedInVersion) { From edc91baa371048578d5fdeb08b5c15cf33526b32 Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Mon, 30 Sep 2024 16:55:58 +0300 Subject: [PATCH 8/9] tests --- .../ErgoLikeTransactionSpec.scala | 32 ++++++++++++------- .../utxo/BasicOpsSpecification.scala | 7 ---- 2 files changed, 21 insertions(+), 18 deletions(-) diff --git a/sc/shared/src/test/scala/org/ergoplatform/ErgoLikeTransactionSpec.scala b/sc/shared/src/test/scala/org/ergoplatform/ErgoLikeTransactionSpec.scala index 6a7ef5a512..3fc9c7fd3d 100644 --- a/sc/shared/src/test/scala/org/ergoplatform/ErgoLikeTransactionSpec.scala +++ b/sc/shared/src/test/scala/org/ergoplatform/ErgoLikeTransactionSpec.scala @@ -7,8 +7,7 @@ import org.ergoplatform.settings.ErgoAlgos import scorex.util.encode.Base16 import scorex.util.{ModifierId, Random} import sigma.Extensions._ -import sigma.SigmaDslTesting -import sigma.ast.SCollection.SByteArray +import sigma.{SigmaDslTesting, VersionContext} import sigma.ast.SType._ import sigma.ast.syntax.{ErgoBoxCandidateRType, TrueSigmaProp} import sigma.ast._ @@ -20,9 +19,11 @@ import sigmastate.helpers.TestingHelpers.copyTransaction import sigmastate.utils.Helpers import sigma.SigmaDslTesting import sigma.Extensions._ +import sigma.ast.SCollection.SByteArray +import sigmastate.CrossVersionProps import sigmastate.utils.Helpers.EitherOps // required for Scala 2.11 -class ErgoLikeTransactionSpec extends SigmaDslTesting with JsonCodecs { +class ErgoLikeTransactionSpec extends SigmaDslTesting with CrossVersionProps with JsonCodecs { property("ErgoBox test vectors") { val token1 = "6e789ab7b2fffff12280a6cd01557f6fb22b7f80ff7aff8e1f7f15973d7f0001" @@ -99,14 +100,24 @@ class ErgoLikeTransactionSpec extends SigmaDslTesting with JsonCodecs { { // test case for R2 val res = b1.get(ErgoBox.R2).get - val exp = Coll( - (Digest32Coll @@ ErgoAlgos.decodeUnsafe(token1).toColl) -> 10000000L, - (Digest32Coll @@ ErgoAlgos.decodeUnsafe(token2).toColl) -> 500L - ).map(identity).toConstant - // TODO v6.0 (16h): fix collections equality and remove map(identity) - // (PairOfColl should be equal CollOverArray but now it is not) + + // We have versioned check here due to fixed collections equality in 6.0.0 + // (PairOfColl equal CollOverArray now) // see (https://github.com/ScorexFoundation/sigmastate-interpreter/issues/909) - res shouldBe exp + if(VersionContext.current.isV6SoftForkActivated) { + val exp = Coll( + (Digest32Coll @@ ErgoAlgos.decodeUnsafe(token1).toColl) -> 10000000L, + (Digest32Coll @@ ErgoAlgos.decodeUnsafe(token2).toColl) -> 500L + ).toConstant + res shouldBe exp + exp shouldBe res + } else { + val exp = Coll( + (Digest32Coll @@ ErgoAlgos.decodeUnsafe(token1).toColl) -> 10000000L, + (Digest32Coll @@ ErgoAlgos.decodeUnsafe(token2).toColl) -> 500L + ).map(identity).toConstant + res shouldBe exp + } } { // test case for R3 @@ -470,7 +481,6 @@ class ErgoLikeTransactionSpec extends SigmaDslTesting with JsonCodecs { // test equivalence of "from Json" and "from bytes" deserialization tx2.id shouldBe tx.id tx2.id shouldBe "d5c0a7908bbb8eefe72ad70a9f668dd47b748239fd34378d3588d5625dd75c82" - println(tx2.id) } property("Tuple in register test vector") { diff --git a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala index 431c5166e1..68fe1022e7 100644 --- a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala +++ b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala @@ -804,13 +804,6 @@ class BasicOpsSpecification extends CompilerTestingCommons } } - property("coll equality") { - def collTest() = test("R1", env, ext, - "{ SELF.tokens == Coll[(Coll[Byte], Long)]() }", - null - ) - } - property("Relation operations") { test("R1", env, ext, "{ allOf(Coll(getVar[Boolean](trueVar).get, true, true)) }", From 5cabedd6f73a3d0737a221919e51771a0c5653a2 Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Fri, 18 Oct 2024 14:42:40 +0300 Subject: [PATCH 9/9] equalsPairCollWithCollOverArray --- .../scala/sigma/data/CollsOverArrays.scala | 86 +++++++++++++------ .../ErgoLikeTransactionSpec.scala | 2 +- 2 files changed, 63 insertions(+), 25 deletions(-) diff --git a/core/shared/src/main/scala/sigma/data/CollsOverArrays.scala b/core/shared/src/main/scala/sigma/data/CollsOverArrays.scala index dc73253628..2d6a4a5cdf 100644 --- a/core/shared/src/main/scala/sigma/data/CollsOverArrays.scala +++ b/core/shared/src/main/scala/sigma/data/CollsOverArrays.scala @@ -1,6 +1,8 @@ package sigma.data import debox.{Buffer, cfor} +import sigma.Evaluation.stypeToRType +import sigma.data.CollOverArray.equalsPairCollWithCollOverArray import sigma.data.RType._ import sigma.util.{CollectionUtil, MaxArrayLength, safeConcatArrays_v5} import sigma.{Coll, CollBuilder, PairColl, VersionContext, requireSameLength} @@ -12,7 +14,9 @@ class CollOverArray[@specialized A](val toArray: Array[A], val builder: CollBuil s"Cannot create collection with size ${toArray.length} greater than $MaxArrayLength") override def tItem: RType[A] = tA + @inline def length: Int = toArray.length + @inline def apply(i: Int): A = toArray.apply(i) override def isEmpty: Boolean = length == 0 @@ -29,8 +33,11 @@ class CollOverArray[@specialized A](val toArray: Array[A], val builder: CollBuil } def foreach(f: A => Unit): Unit = toArray.foreach(f) + def exists(p: A => Boolean): Boolean = toArray.exists(p) + def forall(p: A => Boolean): Boolean = toArray.forall(p) + def filter(p: A => Boolean): Coll[A] = builder.fromArray(toArray.filter(p)) def foldLeft[B](zero: B, op: ((B, A)) => B): B = toArray.foldLeft(zero)((b, a) => op((b, a))) @@ -117,12 +124,14 @@ class CollOverArray[@specialized A](val toArray: Array[A], val builder: CollBuil override def unionSet(that: Coll[A]): Coll[A] = { val set = debox.Set.ofSize[A](this.length) val res = Buffer.ofSize[A](this.length) + @inline def addItemToSet(x: A) = { if (!set(x)) { set.add(x) res += x } } + def addToSet(arr: Array[A]) = { val limit = arr.length cfor(0)(_ < limit, _ + 1) { i => @@ -140,19 +149,41 @@ class CollOverArray[@specialized A](val toArray: Array[A], val builder: CollBuil override def equals(obj: scala.Any): Boolean = (this eq obj.asInstanceOf[AnyRef]) || (obj match { case obj: CollOverArray[_] if obj.tItem == this.tItem => java.util.Objects.deepEquals(obj.toArray, this.toArray) - case obj: PairColl[_, _] if obj.tItem == this.tItem => - if(VersionContext.current.isV6SoftForkActivated) { - java.util.Objects.deepEquals(obj.toArray, this.toArray) + case obj: PairColl[Any, Any] if obj.tItem == this.tItem => + if (VersionContext.current.isV6SoftForkActivated) { + equalsPairCollWithCollOverArray(obj, this.asInstanceOf[CollOverArray[Any]]) } else { false } case _ => false }) - override def hashCode() = CollectionUtil.deepHashCode(toArray) + override def hashCode(): Int = CollectionUtil.deepHashCode(toArray) } -private[sigma] class CollOverArrayBuilder extends CollBuilder { builder => +object CollOverArray { + + // comparing PairColl and CollOverArray instances + private[data] def equalsPairCollWithCollOverArray(pc: PairColl[Any, Any], coa: CollOverArray[Any]): Boolean = { + val ls = pc.ls + val rs = pc.rs + val ts = coa.toArray + if (ts.length == ls.length && ts.isInstanceOf[Array[(Any, Any)]]) { + val ta = ts.asInstanceOf[Array[(Any, Any)]] + var eq = true + cfor(0)(_ < ta.length && eq, _ + 1) { i => + eq = java.util.Objects.deepEquals(ta(i)._1, ls(i)) && java.util.Objects.deepEquals(ta(i)._2, rs(i)) + } + eq + } else { + false + } + } + +} + +private[sigma] class CollOverArrayBuilder extends CollBuilder { + builder => @inline override def pairColl[@specialized A, @specialized B](as: Coll[A], bs: Coll[B]): PairColl[A, B] = { if (VersionContext.current.isJitActivated) { @@ -176,12 +207,12 @@ private[sigma] class CollOverArrayBuilder extends CollBuilder { builder => } } - private def fromBoxedPairs[A, B](seq: Seq[(A, B)])(implicit tA: RType[A], tB: RType[B]): PairColl[A,B] = { + private def fromBoxedPairs[A, B](seq: Seq[(A, B)])(implicit tA: RType[A], tB: RType[B]): PairColl[A, B] = { val len = seq.length val resA = Array.ofDim[A](len)(tA.classTag) val resB = Array.ofDim[B](len)(tB.classTag) cfor(0)(_ < len, _ + 1) { i => - val item = seq.apply(i).asInstanceOf[(A,B)] + val item = seq.apply(i).asInstanceOf[(A, B)] resA(i) = item._1 resB(i) = item._2 } @@ -189,7 +220,7 @@ private[sigma] class CollOverArrayBuilder extends CollBuilder { builder => } override def fromItems[T](items: T*)(implicit cT: RType[T]): Coll[T] = cT match { - case pt: PairType[a,b] => + case pt: PairType[a, b] => val tA = pt.tFst val tB = pt.tSnd fromBoxedPairs(items)(tA, tB) @@ -198,16 +229,16 @@ private[sigma] class CollOverArrayBuilder extends CollBuilder { builder => } override def fromArray[@specialized T: RType](arr: Array[T]): Coll[T] = RType[T] match { - case pt: PairType[a,b] => + case pt: PairType[a, b] => val tA = pt.tFst val tB = pt.tSnd - fromBoxedPairs[a,b](arr.asInstanceOf[Array[(a,b)]])(tA, tB) + fromBoxedPairs[a, b](arr.asInstanceOf[Array[(a, b)]])(tA, tB) case _ => new CollOverArray(arr, builder) } override def replicate[@specialized T: RType](n: Int, v: T): Coll[T] = RType[T] match { - case pt: PairType[a,b] => + case pt: PairType[a, b] => val tA = pt.tFst val tB = pt.tSnd val tuple = v.asInstanceOf[(a, b)] @@ -216,8 +247,8 @@ private[sigma] class CollOverArrayBuilder extends CollBuilder { builder => fromArray(Array.fill(n)(v)) } - override def unzip[@specialized A, @specialized B](xs: Coll[(A,B)]): (Coll[A], Coll[B]) = xs match { - case pa: PairColl[_,_] => (pa.ls, pa.rs) + override def unzip[@specialized A, @specialized B](xs: Coll[(A, B)]): (Coll[A], Coll[B]) = xs match { + case pa: PairColl[_, _] => (pa.ls, pa.rs) case _ => val limit = xs.length implicit val tA = xs.tItem.tFst @@ -236,7 +267,7 @@ private[sigma] class CollOverArrayBuilder extends CollBuilder { builder => left.zip(right).map { case (l, r) => (l ^ r).toByte } override def emptyColl[T](implicit cT: RType[T]): Coll[T] = cT match { - case pt: PairType[a,b] => + case pt: PairType[a, b] => val ls = emptyColl(pt.tFst) val rs = emptyColl(pt.tSnd) pairColl(ls, rs).asInstanceOf[Coll[T]] @@ -245,14 +276,14 @@ private[sigma] class CollOverArrayBuilder extends CollBuilder { builder => } } -class PairOfCols[@specialized L, @specialized R](val ls: Coll[L], val rs: Coll[R]) extends PairColl[L,R] { +class PairOfCols[@specialized L, @specialized R](val ls: Coll[L], val rs: Coll[R]) extends PairColl[L, R] { override def equals(that: scala.Any): Boolean = (this eq that.asInstanceOf[AnyRef]) || (that match { - case that: PairColl[_,_] if that.tItem == this.tItem => + case that: PairColl[_, _] if that.tItem == this.tItem => ls == that.ls && rs == that.rs - case that: CollOverArray[_] if that.tItem == this.tItem => + case that: CollOverArray[Any] if that.tItem == this.tItem => if (VersionContext.current.isV6SoftForkActivated) { - java.util.Objects.deepEquals(that.toArray, this.toArray) + equalsPairCollWithCollOverArray(this.asInstanceOf[PairColl[Any, Any]], that) } else { false } @@ -260,7 +291,9 @@ class PairOfCols[@specialized L, @specialized R](val ls: Coll[L], val rs: Coll[R }) override def hashCode() = ls.hashCode() * 41 + rs.hashCode() + @inline implicit def tL: RType[L] = ls.tItem + @inline implicit def tR: RType[R] = rs.tItem override lazy val tItem: RType[(L, R)] = { @@ -268,8 +301,11 @@ class PairOfCols[@specialized L, @specialized R](val ls: Coll[L], val rs: Coll[R } override def builder: CollBuilder = ls.builder + override def toArray: Array[(L, R)] = ls.toArray.zip(rs.toArray) + @inline override def length: Int = if (ls.length <= rs.length) ls.length else rs.length + @inline override def apply(i: Int): (L, R) = (ls(i), rs(i)) override def isEmpty: Boolean = length == 0 @@ -317,7 +353,7 @@ class PairOfCols[@specialized L, @specialized R](val ls: Coll[L], val rs: Coll[R true } - override def filter(p: ((L, R)) => Boolean): Coll[(L,R)] = { + override def filter(p: ((L, R)) => Boolean): Coll[(L, R)] = { val len = ls.length val resL: Buffer[L] = Buffer.empty[L](ls.tItem.classTag) val resR: Buffer[R] = Buffer.empty[R](rs.tItem.classTag) @@ -346,9 +382,9 @@ class PairOfCols[@specialized L, @specialized R](val ls: Coll[L], val rs: Coll[R state } - override def slice(from: Int, until: Int): PairColl[L,R] = builder.pairColl(ls.slice(from, until), rs.slice(from, until)) + override def slice(from: Int, until: Int): PairColl[L, R] = builder.pairColl(ls.slice(from, until), rs.slice(from, until)) - def append(other: Coll[(L, R)]): Coll[(L,R)] = { + def append(other: Coll[(L, R)]): Coll[(L, R)] = { val arrs = builder.unzip(other) builder.pairColl(ls.append(arrs._1), rs.append(arrs._2)) } @@ -365,7 +401,7 @@ class PairOfCols[@specialized L, @specialized R](val ls: Coll[L], val rs: Coll[R } } - def zip[@specialized B](ys: Coll[B]): PairColl[(L,R), B] = builder.pairColl(this, ys) + def zip[@specialized B](ys: Coll[B]): PairColl[(L, R), B] = builder.pairColl(this, ys) def startsWith(ys: Coll[(L, R)]): Boolean = ys match { case yp: PairOfCols[L, R] => ls.startsWith(yp.ls) && rs.startsWith(yp.rs) @@ -421,18 +457,20 @@ class PairOfCols[@specialized L, @specialized R](val ls: Coll[L], val rs: Coll[R } override def unionSet(that: Coll[(L, R)]): Coll[(L, R)] = { - val set = new java.util.HashSet[(L,R)](32) + val set = new java.util.HashSet[(L, R)](32) implicit val ctL = ls.tItem.classTag implicit val ctR = rs.tItem.classTag val resL = Buffer.empty[L] val resR = Buffer.empty[R] - def addToSet(item: (L,R)) = { + + def addToSet(item: (L, R)) = { if (!set.contains(item)) { set.add(item) resL += item._1 resR += item._2 } } + var i = 0 val thisLen = math.min(ls.length, rs.length) while (i < thisLen) { diff --git a/sc/shared/src/test/scala/org/ergoplatform/ErgoLikeTransactionSpec.scala b/sc/shared/src/test/scala/org/ergoplatform/ErgoLikeTransactionSpec.scala index 3fc9c7fd3d..4b3aa2eab5 100644 --- a/sc/shared/src/test/scala/org/ergoplatform/ErgoLikeTransactionSpec.scala +++ b/sc/shared/src/test/scala/org/ergoplatform/ErgoLikeTransactionSpec.scala @@ -23,7 +23,7 @@ import sigma.ast.SCollection.SByteArray import sigmastate.CrossVersionProps import sigmastate.utils.Helpers.EitherOps // required for Scala 2.11 -class ErgoLikeTransactionSpec extends SigmaDslTesting with CrossVersionProps with JsonCodecs { + class ErgoLikeTransactionSpec extends SigmaDslTesting with CrossVersionProps with JsonCodecs { property("ErgoBox test vectors") { val token1 = "6e789ab7b2fffff12280a6cd01557f6fb22b7f80ff7aff8e1f7f15973d7f0001"