org.alephium.protocol.vm.Val.scala Maven / Gradle / Ivy
The newest version!
// Copyright 2018 The Alephium Authors
// This file is part of the alephium project.
//
// The library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the library. If not, see .
package org.alephium.protocol.vm
import akka.util.ByteString
import org.alephium.protocol.model.ContractId
import org.alephium.serde.{_deserialize => decode, serialize => encode, _}
import org.alephium.util
import org.alephium.util._
sealed trait Val extends Any {
def tpe: Val.Type
def toByteVec(): Val.ByteVec
def toDebugString(): ByteString
def estimateByteSize(): Int
def toConstInstr: Instr[StatelessContext]
}
// scalastyle:off number.of.methods
object Val {
implicit val serde: Serde[Val] = new Serde[Val] {
override def serialize(input: Val): ByteString = {
val content = input match {
case Bool(v) => encode(v)
case I256(v) => encode(v)
case U256(v) => encode(v)
case ByteVec(a) => encode(a)
case Address(a) => encode(a)
}
ByteString(input.tpe.id) ++ content
}
override def _deserialize(input: ByteString): SerdeResult[Staging[Val]] = {
byteSerde._deserialize(input).flatMap {
case Staging(code, content) if code >= 0 && code < Type.types.length =>
_deserialize(Type.types(code.toInt), content)
case Staging(code, _) => Left(SerdeError.wrongFormat(s"Invalid type id: $code"))
}
}
private def _deserialize(tpe: Type, content: ByteString): SerdeResult[Staging[Val]] =
tpe match {
case Bool => decode[Boolean](content).map(_.mapValue(Bool(_)))
case I256 => decode[util.I256](content).map(_.mapValue(I256(_)))
case U256 => decode[util.U256](content).map(_.mapValue(U256(_)))
case ByteVec => decode[ByteString](content).map(_.mapValue(ByteVec(_)))
case Address => decode[LockupScript](content).map(_.mapValue(Address(_)))
case _: FixedSizeArray | _: Struct | _: Map => Left(SerdeError.Other("Unexpected type"))
}
}
sealed trait Type {
def id: scala.Byte
def default: Val
def isNumeric: Boolean
}
object Type {
implicit val serde: Serde[Type] =
byteSerde.xfmap(
byte => {
types.get(Bytes.toPosInt(byte)).toRight(SerdeError.validation(s"Invalid Val Type"))
},
_.id
)
val types: AVector[Type] = AVector[Type](Bool, I256, U256, ByteVec, Address)
def getId(tpe: Type): scala.Byte = types.indexWhere(_ == tpe).toByte
}
// TODO: optimize using value class
final case class Bool(v: Boolean) extends AnyVal with Val {
def tpe: Val.Type = Bool
def not: Val.Bool = Bool(!v)
def and(other: Val.Bool): Val.Bool = Val.Bool(v && other.v)
def or(other: Val.Bool): Val.Bool = Val.Bool(v || other.v)
override def toByteVec(): ByteVec = ByteVec(encode(v))
override def toDebugString(): ByteString = ByteString.fromString(v.toString)
override def estimateByteSize(): Int = 1
override def toConstInstr: Instr[StatelessContext] = if (v) ConstTrue else ConstFalse
}
final case class I256(v: util.I256) extends Val {
def tpe: Val.Type = I256
override def toByteVec(): ByteVec = ByteVec(encode(v))
override def toDebugString(): ByteString = ByteString.fromString(v.toString)
override def estimateByteSize(): Int = 32
override def toConstInstr: Instr[StatelessContext] = ConstInstr.i256(this)
}
final case class U256(v: util.U256) extends Val {
def tpe: Val.Type = U256
override def toByteVec(): ByteVec = ByteVec(encode(v))
override def toDebugString(): ByteString = ByteString.fromString(v.toString)
override def estimateByteSize(): Int = 32
override def toConstInstr: Instr[StatelessContext] = ConstInstr.u256(this)
}
final case class ByteVec(bytes: ByteString) extends AnyVal with Val {
def tpe: Val.Type = ByteVec
override def toByteVec(): ByteVec = this
override def toDebugString(): ByteString = ByteString.fromString(Hex.toHexString(bytes))
override def estimateByteSize(): Int = bytes.length
override def toConstInstr: Instr[StatelessContext] = BytesConst(this)
}
final case class Address(lockupScript: LockupScript) extends AnyVal with Val {
def tpe: Val.Type = Address
override def toByteVec(): ByteVec = ByteVec(encode(lockupScript))
def toBase58: String = Base58.encode(encode(lockupScript))
override def toDebugString(): ByteString = ByteString.fromString(toBase58)
override def estimateByteSize(): Int = lockupScript match {
case LockupScript.P2MPKH(mpkh, _) => mpkh.length * 32
case _ => 32
}
override def toConstInstr: Instr[StatelessContext] = AddressConst(this)
}
object Bool extends Type {
implicit val serde: Serde[Bool] = boolSerde.xmap(Bool(_), _.v)
override lazy val id: scala.Byte = Type.getId(this)
override def default: Bool = Bool(false)
override def isNumeric: Boolean = false
override def toString: String = "Bool"
}
object I256 extends Type {
implicit val serde: Serde[I256] = i256Serde.xmap(I256(_), _.v)
override lazy val id: scala.Byte = Type.getId(this)
override def default: I256 = I256(util.I256.Zero)
override def isNumeric: Boolean = true
override def toString: String = "I256"
}
object U256 extends Type {
implicit val serde: Serde[U256] = u256Serde.xmap(U256(_), _.v)
override lazy val id: scala.Byte = Type.getId(this)
override def default: U256 = U256(util.U256.Zero)
override def isNumeric: Boolean = true
override def toString: String = "U256"
def unsafe(v: Int): U256 = {
U256(util.U256.unsafe(v))
}
}
object ByteVec extends Type {
implicit val serde: Serde[ByteVec] = bytestringSerde.xmap(ByteVec(_), _.bytes)
override lazy val id: scala.Byte = Type.getId(this)
override def default: ByteVec = ByteVec(ByteString.empty)
override def isNumeric: Boolean = false
override def toString: String = "ByteVec"
def from(bytes: RandomBytes): ByteVec = ByteVec(bytes.bytes)
def fromString(string: String): ByteVec = ByteVec(ByteString.fromString(string))
}
object Address extends Type {
implicit val serde: Serde[Address] = serdeImpl[LockupScript].xmap(Address(_), _.lockupScript)
override lazy val id: scala.Byte = Type.getId(this)
override def default: Address = Address(LockupScript.vmDefault)
override def isNumeric: Boolean = false
override def toString: String = "Address"
}
final case class FixedSizeArray(baseType: Type, size: Int) extends Type {
override def id: scala.Byte = throw new RuntimeException("FixedArray has no type id")
override def default: Val = throw new RuntimeException("FixedArray has no default value")
override def isNumeric: Boolean = false
override def toString: String = s"[$baseType;$size]"
}
final case class Struct(name: String) extends Type {
override def id: scala.Byte = throw new RuntimeException("Struct has no type id")
override def default: Val = throw new RuntimeException("Struct has no default value")
override def isNumeric: Boolean = false
override def toString: String = name
}
final case class Map(key: Type, value: Type) extends Type {
override def id: scala.Byte = throw new RuntimeException("Map has no type id")
override def default: Val = throw new RuntimeException("Map has no default value")
override def isNumeric: Boolean = false
override def toString: String = s"Map[$key,$value]"
}
val True: Bool = Bool(true)
val False: Bool = Bool(false)
val NullContractAddress: Val.Address = Val.Address(LockupScript.p2c(ContractId.zero))
val Enforced: ByteVec = ByteVec(ByteString.fromString("enforced"))
}
// scalastyle:on number.of.methods
© 2015 - 2025 Weber Informatics LLC | Privacy Policy