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

org.alephium.protocol.model.CoinbaseData.scala Maven / Gradle / Ivy

// 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.model

import akka.util.ByteString

import org.alephium.protocol.config.NetworkConfig
import org.alephium.protocol.vm.LockupScript
import org.alephium.serde.{_deserialize => _decode, serialize => encode, _}
import org.alephium.util.{AVector, TimeStamp}

final case class CoinbaseDataPrefix private (fromGroup: Byte, toGroup: Byte, blockTs: TimeStamp)

object CoinbaseDataPrefix {
  implicit val prefixSerde: Serde[CoinbaseDataPrefix] =
    Serde.forProduct3(
      CoinbaseDataPrefix.apply,
      prefix => (prefix.fromGroup, prefix.toGroup, prefix.blockTs)
    )

  def from(chainIndex: ChainIndex, blockTs: TimeStamp): CoinbaseDataPrefix = {
    CoinbaseDataPrefix(chainIndex.from.value.toByte, chainIndex.to.value.toByte, blockTs)
  }
}

sealed trait CoinbaseData {
  def prefix: CoinbaseDataPrefix
  def isGhostEnabled: Boolean = this match {
    case _: CoinbaseDataV1 => false
    case _                 => true
  }
}

final case class CoinbaseDataV1(
    prefix: CoinbaseDataPrefix,
    minerData: ByteString
) extends CoinbaseData

final case class GhostUncleData(blockHash: BlockHash, lockupScript: LockupScript.Asset)

object GhostUncleData {
  implicit val ghostUncleDataSerde: Serde[GhostUncleData] =
    Serde.forProduct2(GhostUncleData.apply, d => (d.blockHash, d.lockupScript))

  def from(uncle: SelectedGhostUncle): GhostUncleData =
    GhostUncleData(uncle.blockHash, uncle.lockupScript)
}

final case class CoinbaseDataV2(
    prefix: CoinbaseDataPrefix,
    ghostUncleData: AVector[GhostUncleData],
    minerData: ByteString
) extends CoinbaseData

object CoinbaseData {
  implicit def serde(implicit networkConfig: NetworkConfig): Serde[CoinbaseData] =
    new Serde[CoinbaseData] {
      def _deserialize(input: ByteString): SerdeResult[Staging[CoinbaseData]] = {
        for {
          prefixResult <- _decode[CoinbaseDataPrefix](input)
          hardFork = networkConfig.getHardFork(prefixResult.value.blockTs)
          coinbaseData <-
            if (hardFork.isRhoneEnabled()) {
              for {
                ghostUncleDataResult <- _decode[AVector[GhostUncleData]](prefixResult.rest)
              } yield Staging[CoinbaseData](
                CoinbaseDataV2(
                  prefixResult.value,
                  ghostUncleDataResult.value,
                  ghostUncleDataResult.rest
                ),
                ByteString.empty
              )
            } else {
              Right(
                Staging[CoinbaseData](
                  CoinbaseDataV1(prefixResult.value, prefixResult.rest),
                  ByteString.empty
                )
              )
            }
        } yield coinbaseData
      }

      def serialize(d: CoinbaseData): ByteString = {
        d match {
          case data: CoinbaseDataV1 => encode(data.prefix) ++ data.minerData
          case data: CoinbaseDataV2 =>
            encode(data.prefix) ++ encode(data.ghostUncleData) ++ data.minerData
        }
      }
    }

  def from(
      chainIndex: ChainIndex,
      blockTs: TimeStamp,
      sortedGhostUncles: AVector[SelectedGhostUncle],
      minerData: ByteString
  )(implicit
      networkConfig: NetworkConfig
  ): CoinbaseData = {
    val prefix   = CoinbaseDataPrefix.from(chainIndex, blockTs)
    val hardFork = networkConfig.getHardFork(blockTs)
    if (hardFork.isRhoneEnabled()) {
      CoinbaseDataV2(prefix, sortedGhostUncles.map(GhostUncleData.from), minerData)
    } else {
      CoinbaseDataV1(prefix, minerData)
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy