Skip to content

Commit

Permalink
Move classes into ergo-core to satisfy NipopowProof and NipopowVerifi…
Browse files Browse the repository at this point in the history
…er requirements
  • Loading branch information
ccellado committed Nov 15, 2023
1 parent e331fde commit fcf3d6f
Show file tree
Hide file tree
Showing 66 changed files with 280 additions and 256 deletions.
112 changes: 1 addition & 111 deletions ergo-core/src/main/scala/org/ergoplatform/http/api/ApiCodecs.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,9 @@ import org.bouncycastle.util.BigIntegers
import org.ergoplatform.ErgoBox.RegisterId
import org.ergoplatform._
import org.ergoplatform.http.api.ApiEncoderOption.Detalization
import org.ergoplatform.http.api.requests.{CryptoResult, ExecuteRequest, HintExtractionRequest}
import org.ergoplatform.mining.{groupElemFromBytes, groupElemToBytes}
import org.ergoplatform.modifiers.mempool.{ErgoTransaction, UnsignedErgoTransaction}
import org.ergoplatform.nodeView.history.ErgoHistory.Difficulty
import org.ergoplatform.nodeView.history.extra.ExtraIndexer.getAddress
import org.ergoplatform.nodeView.history.extra.{BalanceInfo, IndexedErgoBox, IndexedErgoTransaction, IndexedToken}
import org.ergoplatform.nodeView.history.ErgoHistoryConstants.Difficulty
import org.ergoplatform.nodeView.wallet.persistence.WalletDigest
import org.ergoplatform.nodeView.wallet.requests.{ExternalSecret, GenerateCommitmentsRequest, TransactionSigningRequest}
import org.ergoplatform.sdk.wallet.secrets.{DhtSecretKey, DlogSecretKey}
Expand All @@ -33,7 +30,6 @@ import sigmastate.crypto.VerifierMessage.Challenge
import sigmastate.crypto._
import sigmastate.interpreter._
import sigmastate.serialization.OpCodes
import sigma.AnyValue
import org.ergoplatform.nodeView.state.SnapshotsInfo
import org.ergoplatform.nodeView.state.UtxoState.ManifestId
import org.ergoplatform.sdk.JsonCodecs
Expand Down Expand Up @@ -246,25 +242,7 @@ trait ApiCodecs extends JsonCodecs {
}
}

implicit val hintExtractionRequestEncoder: Encoder[HintExtractionRequest] = {hr =>
Map(
"tx" -> hr.tx.asJson,
"real" -> hr.real.asJson,
"simulated" -> hr.simulated.asJson,
"inputsRaw" -> hr.inputs.asJson,
"dataInputsRaw" -> hr.dataInputs.asJson
).asJson
}

implicit val hintExtractionRequestDecoder: Decoder[HintExtractionRequest] = {cursor =>
for {
tx <- cursor.downField("tx").as[ErgoTransaction]
real <- cursor.downField("real").as[Seq[SigmaBoolean]]
simulated <- cursor.downField("simulated").as[Seq[SigmaBoolean]]
inputs <- cursor.downField("inputsRaw").as[Option[Seq[String]]]
dataInputs <- cursor.downField("dataInputsRaw").as[Option[Seq[String]]]
} yield HintExtractionRequest(tx, real, simulated, inputs, dataInputs)
}

implicit val firstProverMessageEncoder: Encoder[FirstProverMessage] = {
case cmtDlog: FirstDLogProverMessage =>
Expand Down Expand Up @@ -488,95 +466,7 @@ trait ApiCodecs extends JsonCodecs {
} yield GenerateCommitmentsRequest(tx, secretsOpt, inputs, dataInputs)
}

implicit val executeRequestDecoder = new Decoder[ExecuteRequest] {
def apply(cursor: HCursor): Decoder.Result[ExecuteRequest] = {
for {
script <- cursor.downField("script").as[String]
env <- cursor.downField("namedConstants").as[Map[String,AnyValue]]
ctx <- cursor.downField("context").as[ErgoLikeContext]
} yield ExecuteRequest(script, env.map({ case (k,v) => k -> v.value }), ctx)
}
}

implicit val cryptResultEncoder: Encoder[CryptoResult] = {
res =>
val fields = Map(
"value" -> res.value.asJson,
"cost" -> res.cost.asJson
)
fields.asJson
}

implicit val indexedBoxEncoder: Encoder[IndexedErgoBox] = { iEb =>
iEb.box.asJson.deepMerge(Json.obj(
"globalIndex" -> iEb.globalIndex.asJson,
"inclusionHeight" -> iEb.inclusionHeight.asJson,
"address" -> ergoAddressEncoder.toString(getAddress(iEb.box.ergoTree)).asJson,
"spentTransactionId" -> iEb.spendingTxIdOpt.asJson
))
}

implicit val indexedBoxSeqEncoder: Encoder[(Seq[IndexedErgoBox],Long)] = { iEbSeq =>
Json.obj(
"items" -> iEbSeq._1.asJson,
"total" -> iEbSeq._2.asJson
)
}

implicit val indexedTxEncoder: Encoder[IndexedErgoTransaction] = { iEt =>
Json.obj(
"id" -> iEt.txid.asJson,
"blockId" -> iEt.blockId.asJson,
"inclusionHeight" -> iEt.inclusionHeight.asJson,
"timestamp" -> iEt.timestamp.asJson,
"index" -> iEt.index.asJson,
"globalIndex" -> iEt.globalIndex.asJson,
"numConfirmations" -> iEt.numConfirmations.asJson,
"inputs" -> iEt.inputs.asJson,
"dataInputs" -> iEt.dataInputs.asJson,
"outputs" -> iEt.outputs.asJson,
"size" -> iEt.txSize.asJson
)
}

implicit val indexedTxSeqEncoder: Encoder[(Seq[IndexedErgoTransaction],Long)] = { iEtSeq =>
Json.obj(
"items" -> iEtSeq._1.asJson,
"total" -> iEtSeq._2.asJson
)
}

implicit val IndexedTokenEncoder: Encoder[IndexedToken] = { token =>
Json.obj(
"id" -> token.tokenId.asJson,
"boxId" -> token.boxId.asJson,
"emissionAmount" -> token.amount.asJson,
"name" -> token.name.asJson,
"description" -> token.description.asJson,
"decimals" -> token.decimals.asJson
)
}

implicit val BalanceInfoEncoder: Encoder[BalanceInfo] = { bal =>
Json.obj(
"nanoErgs" -> bal.nanoErgs.asJson,
"tokens" -> bal.tokens.map(token => {
Json.obj(
"tokenId" -> token._1.asJson,
"amount" -> token._2.asJson,
"decimals" -> bal.additionalTokenInfo(token._1)._2.asJson,
"name" -> bal.additionalTokenInfo(token._1)._1.asJson
)
}).asJson
)
}

implicit val TotalBalanceInfoEncoder: Encoder[(BalanceInfo,BalanceInfo)] = { tBal =>
Json.obj(
"confirmed" -> tBal._1.asJson,
"unconfirmed" -> tBal._2.asJson
)
}

}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import org.ergoplatform.modifiers.history.extension.ExtensionCandidate
import org.ergoplatform.modifiers.history.header.Header.{Timestamp, Version}
import org.ergoplatform.modifiers.history.header.{Header, HeaderSerializer, HeaderWithoutPow}
import org.ergoplatform.modifiers.mempool.ErgoTransaction
import org.ergoplatform.nodeView.history.ErgoHistory.GenesisHeight
import org.ergoplatform.nodeView.history.ErgoHistoryConstants.GenesisHeight
import org.ergoplatform.nodeView.mempool.TransactionMembershipProof
import scorex.crypto.authds.{ADDigest, SerializedAdProof}
import scorex.crypto.hash.{Blake2b256, Digest32}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package org.ergoplatform.mining
import io.circe.syntax._
import io.circe.{Encoder, Json}
import org.ergoplatform.http.api.ApiCodecs
import org.ergoplatform.nodeView.history.ErgoHistory.Height
import org.ergoplatform.nodeView.history.ErgoHistoryConstants.Height
import sigmastate.crypto.DLogProtocol.ProveDlog


Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package org.ergoplatform.mining.difficulty

import org.ergoplatform.modifiers.history.header.Header
import org.ergoplatform.nodeView.history.ErgoHistory.{Difficulty, Height}
import org.ergoplatform.nodeView.history.ErgoHistoryConstants.{Difficulty, Height}
import org.ergoplatform.settings.ChainSettings
import scorex.util.ScorexLogging
import scala.concurrent.duration.FiniteDuration
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package org.ergoplatform.mining.difficulty

import java.math.BigInteger

import org.ergoplatform.nodeView.history.ErgoHistory._
import org.ergoplatform.nodeView.history.ErgoHistoryConstants._
import scorex.core.serialization.ErgoSerializer
import scorex.util.serialization.{Reader, Writer}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package org.ergoplatform.modifiers.history
import org.ergoplatform.mining.AutolykosPowScheme
import org.ergoplatform.modifiers.history.header.Header
import org.ergoplatform.modifiers.history.header.Header._
import org.ergoplatform.nodeView.history.ErgoHistory
import org.ergoplatform.nodeView.history.ErgoHistoryConstants._
import org.ergoplatform.settings.Constants
import scorex.util._
import sigmastate.crypto.CryptoConstants.EcPointType
Expand Down Expand Up @@ -72,7 +72,7 @@ object PreHeader {
parentId = Header.GenesisParentId,
timestamp = 0,
nBits = Constants.InitialNBits,
height = ErgoHistory.EmptyHistoryHeight,
height = EmptyHistoryHeight,
votes = Array.fill(3)(0.toByte),
minerPk = org.ergoplatform.mining.group.generator
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package org.ergoplatform.modifiers.history.header

import io.circe.syntax._
import io.circe.{Decoder, Encoder, HCursor}
import org.ergoplatform.nodeView.history.ErgoHistory.{GenesisHeight, Difficulty}
import org.ergoplatform.nodeView.history.ErgoHistoryConstants.{GenesisHeight, Difficulty}
import org.ergoplatform.http.api.ApiCodecs
import org.ergoplatform.mining.AutolykosSolution
import org.ergoplatform.mining.difficulty.DifficultySerializer
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -163,106 +163,6 @@ class NipopowAlgos(val chainSettings: ChainSettings) {
NipopowProof(this, m, k, prefix, suffixHead, suffixTail, params.continuous)
}

/**
* Computes NiPoPow proof for the chain stored in `histReader`'s database,
* or a prefix of the chain which contains a specific header (if `headerIdOpt` is specified).
* In the latter case, header will be the first header of the suffix of max length `k`
* (`suffixHead` field of the result).
*/
def prove(histReader: ErgoHistoryReader,
headerIdOpt: Option[ModifierId] = None)(params: PoPowParams): Try[NipopowProof] = Try {
type Height = Int

val k = params.k
val m = params.m

require(params.k >= 1, s"$k < 1")
require(histReader.headersHeight >= k + m, s"Can not prove chain of size < ${k + m}")

def linksWithIndexes(header: PoPowHeader): Seq[(ModifierId, Int)] = header.interlinks.tail.reverse.zipWithIndex

def previousHeaderIdAtLevel(level: Int, currentHeader: PoPowHeader): Option[ModifierId] = {
linksWithIndexes(currentHeader).find(_._2 == level).map(_._1)
}

@scala.annotation.tailrec
def collectLevel(prevHeaderId: ModifierId,
level: Int,
anchoringHeight: Height,
acc: Seq[PoPowHeader] = Seq.empty): Seq[PoPowHeader] = {
val prevHeader = histReader.popowHeader(prevHeaderId).get // to be caught in outer (prove's) Try
if (prevHeader.height < anchoringHeight) {
acc
} else {
val newAcc = prevHeader +: acc
previousHeaderIdAtLevel(level, prevHeader) match {
case Some(newPrevHeaderId) => collectLevel(newPrevHeaderId, level, anchoringHeight, newAcc)
case None => newAcc
}
}
}

def provePrefix(initAnchoringHeight: Height,
lastHeader: PoPowHeader): Seq[PoPowHeader] = {

val collected = mutable.TreeMap[ModifierId, PoPowHeader]()

val levels = linksWithIndexes(lastHeader)
levels.foldRight(initAnchoringHeight) { case ((prevHeaderId, levelIdx), anchoringHeight) =>
val levelHeaders = collectLevel(prevHeaderId, levelIdx, anchoringHeight)
levelHeaders.foreach(ph => collected.update(ph.id, ph))
if (m < levelHeaders.length) {
levelHeaders(levelHeaders.length - m).height
} else {
anchoringHeight
}
}
collected.values.toSeq
}

val (suffixHead, suffixTail) = headerIdOpt match {
case Some(headerId) =>
val suffixHead = histReader.popowHeader(headerId).get // to be caught in outer (prove's) Try
val suffixTail = histReader.bestHeadersAfter(suffixHead.header, k - 1)
suffixHead -> suffixTail
case None =>
val suffix = histReader.lastHeaders(k).headers
histReader.popowHeader(suffix.head.id).get -> suffix.tail // .get to be caught in outer (prove's) Try
}

val storedHeights = mutable.Set[Height]() // cache to filter out duplicate headers
val prefixBuilder = mutable.ArrayBuilder.make[PoPowHeader]()

val genesisHeight = 1
prefixBuilder += histReader.popowHeader(genesisHeight).get // to be caught in outer (prove's) Try
storedHeights += genesisHeight

if (params.continuous) {
// put headers needed to check difficulty of new blocks after suffix into prefix
val epochLength = chainSettings.eip37EpochLength.getOrElse(chainSettings.epochLength)
diffAdjustment.heightsForNextRecalculation(suffixHead.height, epochLength).foreach { height =>
// check that header in or after suffix is not included, otherwise, sorting by height would be broken
if (height < suffixHead.height) {
histReader.popowHeader(height).foreach { ph =>
prefixBuilder += ph
storedHeights += ph.height
}
}
}
}

provePrefix(genesisHeight, suffixHead).foreach { ph =>
if (!storedHeights.contains(ph.height)) {
prefixBuilder += ph
storedHeights += ph.height
}
}

val prefix = prefixBuilder.result().sortBy(_.height)

NipopowProof(this, m, k, prefix, suffixHead, suffixTail, params.continuous)
}

}


Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package org.ergoplatform.nodeView.history

import org.ergoplatform.ErgoLikeContext

object ErgoHistoryConstants {
/**
* Type for time, represents machine-specific timestamp of a transaction
* or block section, as miliseconds passed since beginning of UNIX
* epoch on the machine
*/
type Time = Long

type Height = ErgoLikeContext.Height // Int
type Score = BigInt
type Difficulty = BigInt
type NBits = Long

val CharsetName = "UTF-8"

val EmptyHistoryHeight: Int = 0
val GenesisHeight: Int = EmptyHistoryHeight + 1 // first block has height == 1
}
19 changes: 0 additions & 19 deletions ergo-core/src/main/scala/org/ergoplatform/settings/Constants.scala
Original file line number Diff line number Diff line change
@@ -1,14 +1,7 @@
package org.ergoplatform.settings

import org.ergoplatform.mining.difficulty.DifficultySerializer
import org.ergoplatform.modifiers.NetworkObjectTypeId
import org.ergoplatform.modifiers.history.{ADProofs, BlockTransactions, BlockTransactionsSerializer, ADProofsSerializer}
import org.ergoplatform.modifiers.history.extension.{Extension, ExtensionSerializer}
import org.ergoplatform.modifiers.history.header.{Header, HeaderSerializer}
import org.ergoplatform.modifiers.mempool.{ErgoTransaction, ErgoTransactionSerializer}
import org.ergoplatform.nodeView.history.ErgoHistory.Difficulty
import scorex.core.NodeViewModifier
import scorex.core.serialization.ErgoSerializer
import scorex.crypto.authds.avltree.batch.AvlTreeParameters
import sigmastate.Values
import sigmastate.Values.ErgoTree
Expand Down Expand Up @@ -48,18 +41,6 @@ object Constants {
// Number of last block headers available is scripts from ErgoStateContext
val LastHeadersInContext = 10

/**
* Serializers for block sections and transactions
*
* // todo: move to NodeViewSynchronizer, used only there
*/
val modifierSerializers: Map[NetworkObjectTypeId.Value, ErgoSerializer[_ <: NodeViewModifier]] =
Map(Header.modifierTypeId -> HeaderSerializer,
Extension.modifierTypeId -> ExtensionSerializer,
BlockTransactions.modifierTypeId -> BlockTransactionsSerializer,
ADProofs.modifierTypeId -> ADProofsSerializer,
ErgoTransaction.modifierTypeId -> ErgoTransactionSerializer)

val SoftForkEpochs = 32 //about 45.5 days

def TrueLeaf: ErgoTree = Values.TrueLeaf.toSigmaProp
Expand Down
Loading

0 comments on commit fcf3d6f

Please sign in to comment.