Skip to content

Commit

Permalink
fixing and improving tests
Browse files Browse the repository at this point in the history
  • Loading branch information
kushti committed Jun 5, 2024
1 parent 7795e5d commit d01469c
Show file tree
Hide file tree
Showing 12 changed files with 142 additions and 85 deletions.
14 changes: 10 additions & 4 deletions data/shared/src/main/scala/org/ergoplatform/ErgoHeader.scala
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
package org.ergoplatform

import org.bouncycastle.util.BigIntegers
import scorex.crypto.authds.ADDigest
import scorex.crypto.hash.{Blake2b256, Digest32}
import scorex.util.ModifierId
import sigma.Colls
import sigma.crypto.{CryptoConstants, EcPointType}
import sigma.crypto.{BigIntegers, CryptoConstants, EcPointType}
import sigma.serialization.{GroupElementSerializer, SigmaByteReader, SigmaByteWriter, SigmaSerializer}


Expand Down Expand Up @@ -88,6 +87,7 @@ object AutolykosSolution {
* @param extensionRoot - Merkle tree digest of the extension section of the block
* @param powSolution - solution for the proof-of-work puzzle
* @param votes - votes for changing system parameters
* @param unparsedBytes - bytes from future versions of the protocol our version can't parse
* @param _bytes - serialized bytes of the header when not `null`
*/
case class ErgoHeader(override val version: ErgoHeader.Version,
Expand All @@ -104,9 +104,9 @@ case class ErgoHeader(override val version: ErgoHeader.Version,
override val unparsedBytes: Array[Byte],
_bytes: Array[Byte]) extends
HeaderWithoutPow(version, parentId, ADProofsRoot, stateRoot, transactionsRoot, timestamp,
nBits, height, extensionRoot, votes, unparsedBytes) {
nBits, height, extensionRoot, votes, unparsedBytes) {

lazy val bytes = if (_bytes != null) {
lazy val bytes = if(_bytes != null) {
_bytes
} else {
ErgoHeader.sigmaSerializer.toBytes(this)
Expand All @@ -116,6 +116,12 @@ case class ErgoHeader(override val version: ErgoHeader.Version,

lazy val id = Colls.fromArray(serializedId)

override def hashCode(): Int = id.hashCode()

override def equals(other: Any): Boolean = other match {
case h: ErgoHeader => h.id == this.id
case _ => false
}
}


Expand Down
22 changes: 20 additions & 2 deletions data/shared/src/main/scala/sigma/data/CHeader.scala
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,24 @@ class CHeader(val ergoHeader: ErgoHeader) extends Header with WrapperOf[ErgoHead
Colls.fromArray(HeaderWithoutPowSerializer.toBytes(headerWithoutPow))
}

override def toString: String =
s"""CHeader(
| id: ${id},
| version: ${version},
| tx proofs hash: ${ADProofsRoot},
| state root: ${stateRoot.digest},
| transactions root: ${transactionsRoot},
| time: $timestamp,
| nbits: $nBits,
| extension root: $extensionRoot,
| miner pubkey: $minerPk,
| pow one time pubkey(from AL 1): $powOnetimePk,
| pow nonce: $powNonce,
| pow distance (from AL 1): $powDistance,
| votes: $votes,
| unparsed bytes: $unparsedBytes
|)""".stripMargin

override def hashCode(): Int = id.hashCode()

override def equals(other: Any): Boolean = other match {
Expand All @@ -87,7 +105,7 @@ object CHeader {
def apply( version: Byte,
parentId: Coll[Byte],
ADProofsRoot: Coll[Byte],
stateRoot: AvlTree,
stateRootDigest: Coll[Byte],
transactionsRoot: Coll[Byte],
timestamp: Long,
nBits: Long,
Expand All @@ -107,7 +125,7 @@ object CHeader {
powDistance.asInstanceOf[CBigInt].wrappedValue)

val h = ErgoHeader(version, bytesToId(parentId.toArray), Digest32 @@ ADProofsRoot.toArray,
ADDigest @@ stateRoot.digest.toArray, Digest32 @@ transactionsRoot.toArray, timestamp, nBits, height,
ADDigest @@ stateRootDigest.toArray, Digest32 @@ transactionsRoot.toArray, timestamp, nBits, height,
Digest32 @@ extensionRoot.toArray, solution, votes.toArray, unparsedBytes.toArray, null)

new CHeader(h)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,15 @@ import sigma.ast.{BigIntConstant, ByteArrayConstant, Constant, DeserializationSi
import sigmastate.eval._
import sigma.Extensions.ArrayOps
import sigma.ast._
import sigma.{AvlTree, Colls, Evaluation}
import sigma.{AvlTree, Colls, Evaluation, Header, VersionContext}
import sigma.ast.SType.AnyOps
import scorex.util.encode.Base16
import sigma.ast.BoolArrayConstant.BoolArrayTypeCode
import sigma.ast.ByteArrayConstant.ByteArrayTypeCode
import sigma.ast.syntax.{BoolValue, SValue}
import sigma.crypto.EcPointType
import sigma.util.Extensions.{BigIntegerOps, EcpOps, SigmaBooleanOps}

import scala.annotation.nowarn

class ConstantSerializerSpecification extends TableSerializationSpecification {
Expand All @@ -25,22 +26,29 @@ class ConstantSerializerSpecification extends TableSerializationSpecification {
implicit val wWrapped = wrappedTypeGen(tpe)
implicit val tT = Evaluation.stypeToRType(tpe)
implicit val tag = tT.classTag

val withVersion = if (tpe == SHeader) {
Some(VersionContext.V6SoftForkVersion)
} else {
None
}

forAll { xs: Array[T#WrappedType] =>
implicit val tAny = sigma.AnyType
roundTripTest(Constant[SCollection[T]](xs.toColl, SCollection(tpe)))
roundTripTest(Constant[SType](xs.toColl.map(x => (x, x)).asWrappedType, SCollection(STuple(tpe, tpe)))) // pairs are special case
roundTripTest(Constant[SCollection[T]](xs.toColl, SCollection(tpe)), withVersion)
roundTripTest(Constant[SType](xs.toColl.map(x => (x, x)).asWrappedType, SCollection(STuple(tpe, tpe))), withVersion) // pairs are special case
val triples = xs.toColl.map(x => TupleColl(x, x, x)).asWrappedType
roundTripTest(Constant[SType](triples, SCollection(STuple(tpe, tpe, tpe))))
roundTripTest(Constant[SType](triples, SCollection(STuple(tpe, tpe, tpe))), withVersion)
val quartets = xs.toColl.map(x => TupleColl(x, x, x, x)).asWrappedType
roundTripTest(Constant[SType](quartets, SCollection(STuple(tpe, tpe, tpe, tpe))))
roundTripTest(Constant[SCollection[SCollection[T]]](xs.toColl.map(x => Colls.fromItems(x, x)), SCollection(SCollection(tpe))))
roundTripTest(Constant[SType](quartets, SCollection(STuple(tpe, tpe, tpe, tpe))), withVersion)
roundTripTest(Constant[SCollection[SCollection[T]]](xs.toColl.map(x => Colls.fromItems(x, x)), SCollection(SCollection(tpe))), withVersion)
roundTripTest(Constant[SType](
xs.toColl.map { x =>
val arr = Colls.fromItems(x, x)
(arr, arr)
}.asWrappedType,
SCollection(STuple(SCollection(tpe), SCollection(tpe)))
))
), withVersion)
}
}

Expand All @@ -49,14 +57,19 @@ class ConstantSerializerSpecification extends TableSerializationSpecification {
implicit val tT = Evaluation.stypeToRType(tpe)
@nowarn implicit val tag = tT.classTag
implicit val tAny: RType[Any] = sigma.AnyType
val withVersion = if (tpe == SHeader) {
Some(VersionContext.V6SoftForkVersion)
} else {
None
}
forAll { in: (T#WrappedType, T#WrappedType) =>
val (x,y) = (in._1, in._2)
roundTripTest(Constant[SType]((x, y).asWrappedType, STuple(tpe, tpe)))
roundTripTest(Constant[SType](TupleColl(x, y, x).asWrappedType, STuple(tpe, tpe, tpe)))
roundTripTest(Constant[SType](TupleColl(x, y, x, y).asWrappedType, STuple(tpe, tpe, tpe, tpe)))
roundTripTest(Constant[STuple](Colls.fromItems[Any](x, y, (x, y)), STuple(tpe, tpe, STuple(tpe, tpe))))
roundTripTest(Constant[STuple](Colls.fromItems[Any](x, y, TupleColl(x, y, x)), STuple(tpe, tpe, STuple(tpe, tpe, tpe))))
roundTripTest(Constant[STuple](Colls.fromItems[Any](x, y, TupleColl(x, y, (x, y))), STuple(tpe, tpe, STuple(tpe, tpe, STuple(tpe, tpe)))))
roundTripTest(Constant[SType]((x, y).asWrappedType, STuple(tpe, tpe)), withVersion)
roundTripTest(Constant[SType](TupleColl(x, y, x).asWrappedType, STuple(tpe, tpe, tpe)), withVersion)
roundTripTest(Constant[SType](TupleColl(x, y, x, y).asWrappedType, STuple(tpe, tpe, tpe, tpe)), withVersion)
roundTripTest(Constant[STuple](Colls.fromItems[Any](x, y, (x, y)), STuple(tpe, tpe, STuple(tpe, tpe))), withVersion)
roundTripTest(Constant[STuple](Colls.fromItems[Any](x, y, TupleColl(x, y, x)), STuple(tpe, tpe, STuple(tpe, tpe, tpe))), withVersion)
roundTripTest(Constant[STuple](Colls.fromItems[Any](x, y, TupleColl(x, y, (x, y))), STuple(tpe, tpe, STuple(tpe, tpe, STuple(tpe, tpe)))), withVersion)
}
}

Expand All @@ -71,6 +84,7 @@ class ConstantSerializerSpecification extends TableSerializationSpecification {
forAll { x: SigmaBoolean => roundTripTest(Constant[SSigmaProp.type](x.toSigmaProp, SSigmaProp)) }
forAll { x: ErgoBox => roundTripTest(Constant[SBox.type](x, SBox)) }
forAll { x: AvlTree => roundTripTest(Constant[SAvlTree.type](x, SAvlTree)) }
forAll { x: Header => roundTripTest(Constant[SHeader.type](x, SHeader), Some(VersionContext.V6SoftForkVersion)) }
forAll { x: Array[Byte] => roundTripTest(Constant[SByteArray](x.toColl, SByteArray)) }
forAll { t: SPredefType => testCollection(t) }
forAll { t: SPredefType => testTuples(t) }
Expand All @@ -88,6 +102,7 @@ class ConstantSerializerSpecification extends TableSerializationSpecification {
testCollection(SUnit)
testCollection(SBox)
testCollection(SAvlTree)
testCollection(SHeader)
}

private def caseObjectValue(v: SValue) = (v, Array[Byte](v.opCode))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package sigma.serialization
import java.math.BigInteger
import org.ergoplatform.ErgoBox
import org.scalacheck.Arbitrary._
import sigma.data.{DataValueComparer, OptionType, RType, SigmaBoolean, TupleColl}
import sigma.data.{CBigInt, CHeader, DataValueComparer, OptionType, RType, SigmaBoolean, TupleColl}
import sigma.ast.SCollection.SByteArray
import sigmastate.eval._
import sigma.{AvlTree, Colls, Evaluation, Header, VersionContext}
Expand Down Expand Up @@ -55,7 +55,8 @@ class DataSerializerSpecification extends SerializationSpecification {
VersionContext.withVersions(ver, 1) {
test()
}
case None => test()
case None =>
test()
}
}

Expand All @@ -64,25 +65,32 @@ class DataSerializerSpecification extends SerializationSpecification {
implicit val tT = Evaluation.stypeToRType(tpe)
implicit val tagT = tT.classTag
implicit val tAny = sigma.AnyType

val withVersion = if (tpe == SHeader) {
Some(VersionContext.V6SoftForkVersion)
} else {
None
}
forAll { xs: Array[T#WrappedType] =>
roundtrip[SCollection[T]](xs.toColl, SCollection(tpe))
roundtrip[SType](xs.toColl.map(x => (x, x)).asWrappedType, SCollection(STuple(tpe, tpe)))
roundtrip[SCollection[T]](xs.toColl, SCollection(tpe), withVersion)
roundtrip[SType](xs.toColl.map(x => (x, x)).asWrappedType, SCollection(STuple(tpe, tpe)), withVersion)

val triples = xs.toColl.map(x => TupleColl(x, x, x)).asWrappedType
roundtrip(triples, SCollection(STuple(tpe, tpe, tpe)))
roundtrip(triples, SCollection(STuple(tpe, tpe, tpe)), withVersion)

val quartets = xs.toColl.map(x => TupleColl(x, x, x, x)).asWrappedType
roundtrip(quartets, SCollection(STuple(tpe, tpe, tpe, tpe)))
roundtrip(quartets, SCollection(STuple(tpe, tpe, tpe, tpe)), withVersion)

val nested = xs.toColl.map(x => Colls.fromItems[T#WrappedType](x, x))
roundtrip[SCollection[SCollection[T]]](nested, SCollection(SCollection(tpe)))
roundtrip[SCollection[SCollection[T]]](nested, SCollection(SCollection(tpe)), withVersion)

roundtrip[SType](
xs.toColl.map { x =>
val arr = Colls.fromItems[T#WrappedType](x, x)
(arr, arr)
}.asWrappedType,
SCollection(STuple(SCollection(tpe), SCollection(tpe)))
SCollection(STuple(SCollection(tpe), SCollection(tpe))),
withVersion
)
}
}
Expand All @@ -92,14 +100,19 @@ class DataSerializerSpecification extends SerializationSpecification {
val tT = Evaluation.stypeToRType(tpe)
@nowarn implicit val tag: ClassTag[T#WrappedType] = tT.classTag
implicit val tAny : RType[Any] = sigma.AnyType
val withVersion = if (tpe == SHeader) {
Some(VersionContext.V6SoftForkVersion)
} else {
None
}
forAll { in: (T#WrappedType, T#WrappedType) =>
val (x,y) = (in._1, in._2)
roundtrip[SType]((x, y).asWrappedType, STuple(tpe, tpe))
roundtrip[SType](TupleColl(x, y, x).asWrappedType, STuple(tpe, tpe, tpe))
roundtrip[SType](TupleColl(x, y, x, y).asWrappedType, STuple(tpe, tpe, tpe, tpe))
roundtrip[STuple](Colls.fromItems[Any](x, y, (x, y)), STuple(tpe, tpe, STuple(tpe, tpe)))
roundtrip[STuple](Colls.fromItems[Any](x, y, TupleColl(x, y, x)), STuple(tpe, tpe, STuple(tpe, tpe, tpe)))
roundtrip[STuple](Colls.fromItems[Any](x, y, TupleColl(x, y, (x, y))), STuple(tpe, tpe, STuple(tpe, tpe, STuple(tpe, tpe))))
roundtrip[SType]((x, y).asWrappedType, STuple(tpe, tpe), withVersion)
roundtrip[SType](TupleColl(x, y, x).asWrappedType, STuple(tpe, tpe, tpe), withVersion)
roundtrip[SType](TupleColl(x, y, x, y).asWrappedType, STuple(tpe, tpe, tpe, tpe), withVersion)
roundtrip[STuple](Colls.fromItems[Any](x, y, (x, y)), STuple(tpe, tpe, STuple(tpe, tpe)), withVersion)
roundtrip[STuple](Colls.fromItems[Any](x, y, TupleColl(x, y, x)), STuple(tpe, tpe, STuple(tpe, tpe, tpe)), withVersion)
roundtrip[STuple](Colls.fromItems[Any](x, y, TupleColl(x, y, (x, y))), STuple(tpe, tpe, STuple(tpe, tpe, STuple(tpe, tpe))), withVersion)
}
}

Expand Down Expand Up @@ -185,4 +198,28 @@ class DataSerializerSpecification extends SerializationSpecification {
})
}

property("header vector") {
val header = CHeader(
0.toByte,
Helpers.decodeBytes("7a7fe5347f09017818010062000001807f86808000ff7f66ffb07f7ad27f3362"),
Helpers.decodeBytes("c1d70ad9b1ffc1fb9a715fff19807f2401017fcd8b73db017f1cff77727fff08"),
Helpers.decodeBytes("54d23dd080006bdb56800100356080935a80ffb77e90b800057f00661601807f17"),
Helpers.decodeBytes("5e7f1164ccd0990080c501fc0e0181cb387fc17f00ff00c7d5ff767f91ff5e68"),
-7421721754642387858L,
-4826493284887861030L,
10,
Helpers.decodeBytes("e580c88001ff6fc89c5501017f80e001ff0101fe48c153ff7f00666b80d780ab"),
Helpers.decodeGroupElement("03e7f2875298fddd933c2e0a38968fe85bdeeb70dd8b389559a1d36e2ff1b58fc5"),
Helpers.decodeGroupElement("034e2d3b5f9e409e3ae8a2e768340760362ca33764eda5855f7a43487f14883300"),
Helpers.decodeBytes("974651c9efff7f00"),
CBigInt(new BigInteger("478e827dfa1e4b57", 16)),
Helpers.decodeBytes("01ff13"),
Colls.emptyColl
)

VersionContext.withVersions(VersionContext.V6SoftForkVersion, 1) {
roundtrip[SHeader.type](header, SHeader)
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import org.scalacheck.Arbitrary._
import org.scalatest.matchers.should.Matchers
import org.scalatest.propspec.AnyPropSpec
import org.scalatestplus.scalacheck.{ScalaCheckDrivenPropertyChecks, ScalaCheckPropertyChecks}
import sigma.VersionContext
import sigma.ast.SType
import sigma.ast._
import sigmastate.helpers.NegativeTesting
Expand All @@ -26,10 +27,20 @@ trait SerializationSpecification extends AnyPropSpec
with ValidationSpecification
with NegativeTesting {

protected def roundTripTest[V <: Value[_ <: SType]](v: V): Assertion = {
val bytes = ValueSerializer.serialize(v)
predefinedBytesTest(v, bytes)
predefinedBytesTestNotFomZeroElement(bytes, v)
protected def roundTripTest[V <: Value[_ <: SType]](v: V, withVersion: Option[Byte] = None): Assertion = {
def test() = {
val bytes = ValueSerializer.serialize(v)
predefinedBytesTest(v, bytes)
predefinedBytesTestNotFomZeroElement(bytes, v)
}
withVersion match {
case Some(ver) =>
VersionContext.withVersions(ver, 1) {
test()
}
case None =>
test()
}
}

protected def predefinedBytesTest[V <: Value[_ <: SType]](v: V, bytes: Array[Byte]): Assertion = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,7 @@ trait ObjectGenerators extends TypeGenerators
case SAvlTree => arbAvlTree
case SAny => arbAnyVal
case SUnit => arbUnit
case SHeader => arbHeader
case opt: SOption[a] =>
Arbitrary(frequency((5, None), (5, for (x <- wrappedTypeGen(opt.elemType)) yield Some(x))))
}).asInstanceOf[Arbitrary[T#WrappedType]].arbitrary
Expand Down Expand Up @@ -707,8 +708,9 @@ trait ObjectGenerators extends TypeGenerators
powDistance <- arbBigInt.arbitrary
votes <- minerVotesGen
unparsedBytes <- collOfRange(0, 32, arbByte.arbitrary)
} yield CHeader(version, parentId, adProofsRoot, stateRoot, transactionRoot, timestamp, nBits,
height, extensionRoot, minerPk.toGroupElement, powOnetimePk.toGroupElement, powNonce, powDistance, votes, unparsedBytes)
} yield CHeader(version, parentId, adProofsRoot, stateRoot.digest, transactionRoot, timestamp, nBits,
height, extensionRoot, minerPk.toGroupElement, powOnetimePk.toGroupElement, powNonce, powDistance, votes,
if(version > HeaderVersion.Interpreter60Version){ unparsedBytes } else {Colls.emptyColl[Byte]})

lazy val headerGen: Gen[Header] = for {
stateRoot <- avlTreeGen
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,13 @@ trait TypeGenerators {
implicit val boxTypeGen: Gen[SBox.type] = Gen.const(SBox)
implicit val avlTreeTypeGen: Gen[SAvlTree.type] = Gen.const(SAvlTree)
implicit val optionSigmaPropTypeGen: Gen[SOption[SSigmaProp.type]] = Gen.const(SOption(SSigmaProp))
implicit val headerTypeGen: Gen[SHeader.type] = Gen.const(SHeader)

implicit val primTypeGen: Gen[SPrimType] =
Gen.oneOf[SPrimType](SBoolean, SByte, SShort, SInt, SLong, SBigInt, SGroupElement, SSigmaProp, SUnit)
implicit val arbPrimType: Arbitrary[SPrimType] = Arbitrary(primTypeGen)
implicit val predefTypeGen: Gen[SPredefType] =
Gen.oneOf[SPredefType](SBoolean, SByte, SShort, SInt, SLong, SBigInt, SGroupElement, SSigmaProp, SUnit, SBox, SAvlTree)
Gen.oneOf[SPredefType](SBoolean, SByte, SShort, SInt, SLong, SBigInt, SGroupElement, SSigmaProp, SUnit, SBox, SAvlTree, SHeader)
implicit val arbPredefType: Arbitrary[SPredefType] = Arbitrary(predefTypeGen)

implicit def genToArbitrary[T: Gen]: Arbitrary[T] = Arbitrary(implicitly[Gen[T]])
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -240,16 +240,16 @@ trait SigmaTestingData extends TestingCommons with ObjectGenerators {

def createAvlTreeData() = AvlTreeData(
ErgoAlgos.decodeUnsafe("010180017f7f7b7f720c00007f7f7f0f01e857a626f37f1483d06af8077a008080").toColl,
AvlTreeFlags(false, true, false),
728138553,
Some(2147483647)
AvlTreeFlags(true, true, true),
32,
None
)

val h1_instances = new CloneSet(1000, CHeader(
0.toByte,
Helpers.decodeBytes("0180dd805b0000ff5400b997fd7f0b9b00de00fb03c47e37806a8186b94f07ff"),
Helpers.decodeBytes("01f07f60d100ffb970c3007f60ff7f24d4070bb8fffa7fca7f34c10001ffe39d"),
CAvlTree(createAvlTreeData()),
CAvlTree(createAvlTreeData()).digest,
Helpers.decodeBytes("804101ff01000080a3ffbd006ac080098df132a7017f00649311ec0e00000100"),
1L,
-1L,
Expand Down
Loading

0 comments on commit d01469c

Please sign in to comment.