All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.wavesplatform.lang.contract.serialization.ContractSerDeV1.scala Maven / Gradle / Ivy

package com.wavesplatform.lang.contract.serialization

import cats.instances.list._
import cats.syntax.either._
import cats.syntax.option._
import cats.syntax.traverse._
import com.wavesplatform.lang.contract.DApp
import com.wavesplatform.lang.contract.DApp.{CallableAnnotation, CallableFunction, VerifierAnnotation, VerifierFunction}
import com.wavesplatform.lang.v1.compiler.Terms.{DECLARATION, FUNC}
import com.wavesplatform.lang.utils.Serialize._
import com.wavesplatform.lang.v1.ContractLimits
import com.wavesplatform.lang.v1.serialization.SerdeV1
import com.wavesplatform.protobuf.dapp.DAppMeta
import monix.eval.Coeval

import java.io.ByteArrayOutputStream
import java.nio.ByteBuffer
import java.nio.charset.StandardCharsets

object ContractSerDeV1 extends ContractSerDe {

  def serialize(c: DApp): Either[String, Array[Byte]] =
    for {
      out <- tryEi {
        val out = new ByteArrayOutputStream()

        val metaBytes = c.meta.toByteArray

        // version byte
        out.writeInt(0)

        out.writeInt(metaBytes.length)
        out.write(metaBytes)

        out.writeInt(c.decs.size)
        c.decs.foreach(dec => serializeDeclaration(out, dec))

        out.writeInt(c.callableFuncs.size)
        c.callableFuncs.foreach(cFunc => serializeAnnotatedFunction(out, cFunc.u, cFunc.annotation.invocationArgName))

        c.verifierFuncOpt match {
          case None => out.writeInt(0)
          case Some(vf) =>
            out.writeInt(1)
            serializeAnnotatedFunction(out, vf.u, vf.annotation.invocationArgName)
        }
        out
      }
    } yield out.toByteArray

  def deserialize(arr: Array[Byte]): Either[String, DApp] = {
    val bb = ByteBuffer.wrap(arr)
    for {
      _               <- tryEi(bb.getInt())
      meta            <- deserializeMeta(bb)
      decs            <- deserializeList[DECLARATION](bb, deserializeDeclaration)
      callableFuncs   <- deserializeList(bb, deserializeCallableFunction)
      verifierFuncOpt <- deserializeOption(bb, deserializeVerifierFunction)
    } yield DApp(meta, decs, callableFuncs, verifierFuncOpt)
  }

  private[lang] def deserializeMeta(bb: ByteBuffer): Either[String, DAppMeta] =
    for {
      size <- tryEi(bb.getInt)
      meta <- tryEi {
        val arr = new Array[Byte](size)
        bb.get(arr, bb.arrayOffset(), size)
        DAppMeta.parseFrom(arr)
      }
    } yield meta

  private[lang] def serializeDeclaration(out: ByteArrayOutputStream, dec: DECLARATION): Unit = {
    SerdeV1.serializeDeclaration(out, dec, SerdeV1.serAux(out, Coeval.now(()), _)).value()
  }

  private[lang] def deserializeDeclaration(bb: ByteBuffer): Either[String, DECLARATION] = {
    val decType = bb.get()
    SerdeV1.deserializeDeclaration(bb, SerdeV1.desAux(bb), decType).attempt.value().leftMap(_.getMessage)
  }

  private[lang] def serializeAnnotation(out: ByteArrayOutputStream, invocationName: String): Unit = {
    out.writeString(invocationName)
  }

  private[lang] def serializeAnnotatedFunction(out: ByteArrayOutputStream, func: FUNC, annotationInvocName: String): Unit = {
    serializeAnnotation(out, annotationInvocName)
    serializeDeclaration(out, func)
  }

  private[lang] def deserializeCallableAnnotation(bb: ByteBuffer): Either[String, CallableAnnotation] =
    tryEi(CallableAnnotation(bb.getString))

  private[lang] def deserializeCallableFunction(bb: ByteBuffer): Either[String, CallableFunction] = {
    for {
      ca <- deserializeCallableAnnotation(bb)
      cf <- deserializeDeclaration(bb).map(_.asInstanceOf[FUNC])
      nameSize = cf.name.getBytes(StandardCharsets.UTF_8).length
      _ <- Either.cond(
        nameSize <= ContractLimits.MaxDeclarationNameInBytes,
        (),
        s"Callable function name (${cf.name}) size = $nameSize bytes exceeds ${ContractLimits.MaxDeclarationNameInBytes}"
      )
    } yield CallableFunction(ca, cf)
  }

  private[lang] def deserializeVerifiableAnnotation(bb: ByteBuffer): Either[String, VerifierAnnotation] =
    tryEi(VerifierAnnotation(bb.getString))

  private def deserializeVerifierFunction(bb: ByteBuffer): Either[String, VerifierFunction] = {
    for {
      a <- deserializeVerifiableAnnotation(bb)
      f <- deserializeDeclaration(bb).map(_.asInstanceOf[FUNC])
    } yield VerifierFunction(a, f)
  }

  private[lang] def deserializeList[A](bb: ByteBuffer, df: ByteBuffer => Either[String, A]): Either[String, List[A]] = {
    val len = bb.getInt
    if (len <= (bb.limit() - bb.position()) && len >= 0) {
      (1 to len).toList
        .traverse[Either[String, *], A](_ => df(bb))
    } else {
      Left(s"At position ${bb.position()} array of arguments too big.")
    }
  }

  private[lang] def deserializeOption[A](bb: ByteBuffer, df: ByteBuffer => Either[String, A]): Either[String, Option[A]] = {
    tryEi(bb.getInt > 0)
      .flatMap {
        case true  => df(bb).map(_.some)
        case false => Right(None)
      }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy