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

com.wavesplatform.block.validation.Validators.scala Maven / Gradle / Ivy

The newest version!
package com.wavesplatform.block.validation

import cats.syntax.either.*
import com.wavesplatform.block.Block.{GenerationSignatureLength, GenerationVRFSignatureLength, MaxFeaturesInBlock, ProtoBlockVersion}
import com.wavesplatform.block.{Block, MicroBlock}
import com.wavesplatform.crypto
import com.wavesplatform.crypto.{DigestLength, KeyLength}
import com.wavesplatform.mining.Miner.MaxTransactionsPerMicroblock
import com.wavesplatform.settings.GenesisSettings
import com.wavesplatform.transaction.GenesisTransaction
import com.wavesplatform.transaction.TxValidationError.GenericError

object Validators {
  type Validation[A] = Either[GenericError, A]

  def validateBlock(b: Block): Validation[Block] =
    (for {
      _ <- Either.cond(Block.validateReferenceLength(b.header.reference.arr.length), (), "Incorrect reference")
      genSigLength = if (b.header.version < ProtoBlockVersion) GenerationSignatureLength else GenerationVRFSignatureLength
      _ <- Either.cond(b.header.generationSignature.arr.length == genSigLength, (), "Incorrect generationSignature")
      _ <- Either.cond(b.header.generator.arr.length == KeyLength, (), "Incorrect signer")
      _ <- Either.cond(
        b.header.version > 2 || b.header.featureVotes.isEmpty,
        (),
        s"Block version ${b.header.version} could not contain feature votes"
      )
      _ <- Either.cond(b.header.featureVotes.distinct.size == b.header.featureVotes.size, (), s"Duplicates in feature votes")
      _ <- Either.cond(b.header.version < ProtoBlockVersion || b.header.featureVotes.sorted == b.header.featureVotes, (), s"Unsorted feature votes")
      _ <- Either.cond(b.header.featureVotes.size <= MaxFeaturesInBlock, (), s"Block could not contain more than $MaxFeaturesInBlock feature votes")
      _ <- Either.cond(b.header.stateHash.forall(_.size == DigestLength), (), "Incorrect block state hash")
    } yield b).leftMap(GenericError(_))

  def validateGenesisBlock(block: Block, genesisSettings: GenesisSettings, rideV6Activated: Boolean): Validation[Block] =
    for {
      // Common validation
      _ <- validateBlock(block)
      // Verify signature
      _ <- Either.cond(
        crypto.verify(block.signature, block.bodyBytes(), block.header.generator, rideV6Activated),
        (),
        GenericError("Passed genesis signature is not valid")
      )
      // Verify initial balance
      txsSum = block.transactionData.collect { case tx: GenesisTransaction => tx.amount.value }.reduce(Math.addExact(_: Long, _: Long))
      _ <- Either.cond(
        txsSum == genesisSettings.initialBalance,
        (),
        GenericError(s"Initial balance ${genesisSettings.initialBalance} did not match the distributions sum $txsSum")
      )
    } yield block

  def validateMicroBlock(mb: MicroBlock): Validation[MicroBlock] =
    (for {
      _ <- Either.cond(
        MicroBlock.validateReferenceLength(mb.version, mb.reference.arr.length),
        (),
        s"Incorrect prevResBlockSig: ${mb.reference.arr.length}"
      )
      _ <- Either.cond(
        mb.totalResBlockSig.arr.length == crypto.SignatureLength,
        (),
        s"Incorrect totalResBlockSig: ${mb.totalResBlockSig.arr.length}"
      )
      _ <- Either.cond(mb.sender.arr.length == KeyLength, (), s"Incorrect generator.publicKey: ${mb.sender.arr.length}")
      _ <- Either.cond(mb.transactionData.nonEmpty, (), "cannot create empty MicroBlock")
      _ <- Either.cond(
        mb.transactionData.size <= MaxTransactionsPerMicroblock,
        (),
        s"too many txs in MicroBlock: allowed: $MaxTransactionsPerMicroblock, actual: ${mb.transactionData.size}"
      )
    } yield mb).leftMap(GenericError(_))
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy