Skip to content

Commit

Permalink
merging w v6.0.0
Browse files Browse the repository at this point in the history
  • Loading branch information
kushti committed Sep 13, 2024
2 parents 65144a9 + d284f79 commit f20635e
Show file tree
Hide file tree
Showing 49 changed files with 1,597 additions and 327 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@
*.fdb_latexmk
*.gz


yarn.lock
*.log
yarn.lock
docs/spec/out/
test-out/
flamegraphs/
Expand Down
17 changes: 17 additions & 0 deletions core/shared/src/main/scala/sigma/SigmaDsl.scala
Original file line number Diff line number Diff line change
Expand Up @@ -459,6 +459,23 @@ trait Header {

/** Miner votes for changing system parameters. */
def votes: Coll[Byte] //3 bytes

/** Bytes which are coming from future versions of the protocol, so
* their meaning is not known to current version of Sigma, but they
* are stored to get the same id as future version users.
*/
def unparsedBytes: Coll[Byte]

/**
* @return header bytes without proof of work, a PoW is generated over them
*/
def serializeWithoutPoW: Coll[Byte]

/**
* @return result of header's proof-of-work validation
*/
def checkPow: Boolean

}

/** Runtime representation of Context ErgoTree type.
Expand Down
3 changes: 1 addition & 2 deletions core/shared/src/main/scala/sigma/ast/SType.scala
Original file line number Diff line number Diff line change
Expand Up @@ -587,7 +587,7 @@ case class SFunc(tDom: IndexedSeq[SType], tRange: SType, tpeParams: Seq[STypePa
}

object SFunc {
final val FuncTypeCode: TypeCode = TypeCodes.FirstFuncType
final val FuncTypeCode: TypeCode = TypeCodes.FuncType
def apply(tDom: SType, tRange: SType): SFunc = SFunc(Array(tDom), tRange) // HOTSPOT:
val identity = { x: Any => x }
}
Expand Down Expand Up @@ -654,7 +654,6 @@ object SOption extends STypeCompanion {
def apply[T <: SType](implicit elemType: T, ov: Overloaded1): SOption[T] = SOption(elemType)
}


/** Base class for descriptors of `Coll[T]` ErgoTree type for some elemType T. */
trait SCollection[T <: SType] extends SProduct with SGenericType {
def elemType: T
Expand Down
14 changes: 3 additions & 11 deletions core/shared/src/main/scala/sigma/ast/STypeParam.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,10 @@ package sigma.ast

/** Represents a type parameter in a type system.
*
* @param ident The identifier for this type parameter.
* @param upperBound The upper bound of this type parameter, if exists.
* @param lowerBound The lower bound of this type parameter, if exists.
* @note Type parameters with bounds are currently not supported.
* @param ident The identifier for this type parameter
*/
case class STypeParam(
ident: STypeVar,
upperBound: Option[SType] = None,
lowerBound: Option[SType] = None) {
assert(upperBound.isEmpty && lowerBound.isEmpty, s"Type parameters with bounds are not supported, but found $this")

override def toString = ident.toString + upperBound.fold("")(u => s" <: $u") + lowerBound.fold("")(l => s" >: $l")
case class STypeParam(ident: STypeVar) {
override def toString = ident.toString
}

object STypeParam {
Expand Down
6 changes: 2 additions & 4 deletions core/shared/src/main/scala/sigma/ast/TypeCodes.scala
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,8 @@ object TypeCodes {

val LastDataType : TypeCode = TypeCode @@ 111.toByte

/** SFunc types occupy remaining space of byte values [FirstFuncType .. 255] */
val FirstFuncType: TypeCode = TypeCode @@ (LastDataType + 1).toByte

val LastFuncType : TypeCode = TypeCode @@ 255.toByte
/** SFunc type */
val FuncType: TypeCode = TypeCode @@ (LastDataType + 1).toByte

/** We use optimized encoding of constant values to save space in serialization.
* Since Box registers are stored as Constant nodes we save 1 byte for each register.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,9 @@ object ReflectionData {
},
mkMethod(clazz, "powDistance", Array[Class[_]]()) { (obj, _) =>
obj.asInstanceOf[Header].powDistance
},
mkMethod(clazz, "checkPow", Array[Class[_]]()) { (obj, _) =>
obj.asInstanceOf[Header].checkPow
}
)
)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package sigma.serialization

import debox.cfor
import sigma.VersionContext
import sigma.ast.SCollectionType.{CollectionTypeCode, NestedCollectionTypeCode}
import sigma.ast._
import sigma.serialization.{CoreByteReader, CoreByteWriter, InvalidTypePrefix}
Expand Down Expand Up @@ -101,6 +102,17 @@ class TypeSerializer {
// `Tuple` type with more than 4 items `(Int, Byte, Box, Boolean, Int)`
serializeTuple(tup, w)
}
case SFunc(tDom, tRange, tpeParams) =>
w.put(SFunc.FuncTypeCode)
w.putUByte(tDom.length)
tDom.foreach { st =>
serialize(st, w)
}
serialize(tRange, w)
w.putUByte(tpeParams.length)
tpeParams.foreach { tp =>
serialize(tp.ident, w)
}
case typeIdent: STypeVar => {
w.put(typeIdent.typeCode)
val bytes = typeIdent.name.getBytes(StandardCharsets.UTF_8)
Expand Down Expand Up @@ -189,7 +201,24 @@ class TypeSerializer {
case SHeader.typeCode => SHeader
case SPreHeader.typeCode => SPreHeader
case SGlobal.typeCode => SGlobal
case SFunc.FuncTypeCode if VersionContext.current.isV6SoftForkActivated =>
val tdLength = r.getUByte()

val tDom = (1 to tdLength).map { _ =>
deserialize(r)
}
val tRange = deserialize(r)
val tpeParamsLength = r.getUByte()
val tpeParams = (1 to tpeParamsLength).map { _ =>
val ident = deserialize(r)
require(ident.isInstanceOf[STypeVar])
STypeParam(ident.asInstanceOf[STypeVar])
}
SFunc(tDom, tRange, tpeParams)
// todo: serialize tParams
case _ =>
// todo: 6.0: replace 1008 check with identical behavior but other opcode, to activate
// ReplacedRule(1008 -> new opcode) during 6.0 activation
CheckTypeCode(c.toByte)
NoType
}
Expand Down
84 changes: 84 additions & 0 deletions core/shared/src/main/scala/sigma/util/NBitsUtils.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package sigma.util

import java.math.BigInteger

object NBitsUtils {

/**
* <p>The "compact" format is a representation of a whole number N using an unsigned 32 bit number similar to a
* floating point format. The most significant 8 bits are the unsigned exponent of base 256. This exponent can
* be thought of as "number of bytes of N". The lower 23 bits are the mantissa. Bit number 24 (0x800000) represents
* the sign of N. Therefore, N = (-1^sign) * mantissa * 256^(exponent-3).</p>
*
* <p>Satoshi's original implementation used BN_bn2mpi() and BN_mpi2bn(). MPI uses the most significant bit of the
* first byte as sign. Thus 0x1234560000 is compact 0x05123456 and 0xc0de000000 is compact 0x0600c0de. Compact
* 0x05c0de00 would be -0x40de000000.</p>
*
* <p>Bitcoin only uses this "compact" format for encoding difficulty targets, which are unsigned 256bit quantities.
* Thus, all the complexities of the sign bit and using base 256 are probably an implementation accident.</p>
*/
def decodeCompactBits(compact: Long): BigInt = {
val size: Int = (compact >> 24).toInt & 0xFF
val bytes: Array[Byte] = new Array[Byte](4 + size)
bytes(3) = size.toByte
if (size >= 1) bytes(4) = ((compact >> 16) & 0xFF).toByte
if (size >= 2) bytes(5) = ((compact >> 8) & 0xFF).toByte
if (size >= 3) bytes(6) = (compact & 0xFF).toByte
decodeMPI(bytes)
}

/**
* @see Utils#decodeCompactBits(long)
*/
def encodeCompactBits(requiredDifficulty: BigInt): Long = {
val value = requiredDifficulty.bigInteger
var result: Long = 0L
var size: Int = value.toByteArray.length
if (size <= 3) {
result = value.longValue << 8 * (3 - size)
} else {
result = value.shiftRight(8 * (size - 3)).longValue
}
// The 0x00800000 bit denotes the sign.
// Thus, if it is already set, divide the mantissa by 256 and increase the exponent.
if ((result & 0x00800000L) != 0) {
result >>= 8
size += 1
}
result |= size << 24
val a: Int = if (value.signum == -1) 0x00800000 else 0
result |= a
result
}


/** Parse 4 bytes from the byte array (starting at the offset) as unsigned 32-bit integer in big endian format. */
def readUint32BE(bytes: Array[Byte]): Long = ((bytes(0) & 0xffL) << 24) | ((bytes(1) & 0xffL) << 16) | ((bytes(2) & 0xffL) << 8) | (bytes(3) & 0xffL)

/**
* MPI encoded numbers are produced by the OpenSSL BN_bn2mpi function. They consist of
* a 4 byte big endian length field, followed by the stated number of bytes representing
* the number in big endian format (with a sign bit).
*
*/
private def decodeMPI(mpi: Array[Byte]): BigInteger = {

val length: Int = readUint32BE(mpi).toInt
val buf = new Array[Byte](length)
System.arraycopy(mpi, 4, buf, 0, length)

if (buf.length == 0) {
BigInteger.ZERO
} else {
val isNegative: Boolean = (buf(0) & 0x80) == 0x80
if (isNegative) buf(0) = (buf(0) & 0x7f).toByte
val result: BigInteger = new BigInteger(buf)
if (isNegative) {
result.negate
} else {
result
}
}
}

}
Loading

0 comments on commit f20635e

Please sign in to comment.