Skip to content
This repository has been archived by the owner on Apr 13, 2022. It is now read-only.

Pull Request for Generic Boxes Issue #23 #25

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ case class SimpleBoxTransaction(from: IndexedSeq[(PublicKey25519Proposition, Non
signatures: IndexedSeq[Signature25519],
override val fee: Long,
override val timestamp: Long) extends
BoxTransaction[PublicKey25519Proposition, PublicKey25519NoncedBox] {
BoxTransaction[PublicKey25519Proposition, Long, PublicKey25519NoncedBox] {

override type M = SimpleBoxTransaction

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import scorex.crypto.signatures.Curve25519
import scala.util.{Failure, Success}

class SimpleNodeViewHolder(settings: Settings)
extends NodeViewHolder[PublicKey25519Proposition, SimpleTransaction, SimpleBlock] {
extends NodeViewHolder[Long, PublicKey25519Proposition, SimpleTransaction, SimpleBlock] {


override val networkChunkSize: Int = settings.networkChunkSize
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import scorex.crypto.signatures.Curve25519
case class PublicKey25519NoncedBox(override val proposition: PublicKey25519Proposition,
override val nonce: Long,
override val value: Long
) extends PublicKeyNoncedBox[PublicKey25519Proposition] with JsonSerializable {
) extends PublicKeyNoncedBox[PublicKey25519Proposition, Long] with JsonSerializable {

override def json: Json = Map(
"id" -> Base58.encode(id).asJson,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@ import scorex.crypto.encode.Base58

import scala.util.{Failure, Try}

case class TransactionChanges[P <: Proposition, BX <: Box[P]](toRemove: Set[BX], toAppend: Set[BX], minerReward: Long)
case class TransactionChanges[P <: Proposition, BX <: Box[P, Long]](toRemove: Set[BX], toAppend: Set[BX], minerReward: Long)

case class SimpleState(override val version: VersionTag = EmptyVersion,
storage: Map[ByteBuffer, PublicKey25519NoncedBox] = Map()) extends ScorexLogging
with MinimalState[PublicKey25519Proposition, PublicKey25519NoncedBox, SimpleTransaction, SimpleBlock, SimpleState] {
with MinimalState[Long, PublicKey25519Proposition, PublicKey25519NoncedBox, SimpleTransaction, SimpleBlock, SimpleState] {

def isEmpty: Boolean = version sameElements EmptyVersion

Expand All @@ -37,7 +37,7 @@ case class SimpleState(override val version: VersionTag = EmptyVersion,
Try(this)
}

override def applyChanges(change: StateChanges[PublicKey25519Proposition, PublicKey25519NoncedBox], newVersion: VersionTag): Try[SimpleState] = Try {
override def applyChanges(change: StateChanges[Long, PublicKey25519Proposition, PublicKey25519NoncedBox], newVersion: VersionTag): Try[SimpleState] = Try {
val rmap = change.toRemove.foldLeft(storage) { case (m, r) => m - ByteBuffer.wrap(r.boxId) }

val amap = change.toAppend.foldLeft(rmap) { case (m, a) =>
Expand Down Expand Up @@ -83,13 +83,13 @@ case class SimpleState(override val version: VersionTag = EmptyVersion,
}
}

override def changes(block: SimpleBlock): Try[StateChanges[PublicKey25519Proposition, PublicKey25519NoncedBox]] = Try {
override def changes(block: SimpleBlock): Try[StateChanges[Long, PublicKey25519Proposition, PublicKey25519NoncedBox]] = Try {
val generatorReward = block.txs.map(_.fee).sum
val gen = block.generator

val txChanges = block.txs.map(tx => changes(tx)).map(_.get)
val toRemove = txChanges.flatMap(_.toRemove).map(_.id).map(id =>
Removal[PublicKey25519Proposition, PublicKey25519NoncedBox](id))
Removal[Long, PublicKey25519Proposition, PublicKey25519NoncedBox](id))
val toAppendFrom = txChanges.flatMap(_.toAppend)
val (generator, withoutGenerator) = toAppendFrom.partition(_.proposition.address == gen.address)
val generatorBox: PublicKey25519NoncedBox = (generator ++ boxesOf(gen)).headOption match {
Expand All @@ -99,10 +99,10 @@ case class SimpleState(override val version: VersionTag = EmptyVersion,
PublicKey25519NoncedBox(gen, 1, generatorReward)
}
val toAppend = (withoutGenerator ++ Seq(generatorBox)).map(b =>
Insertion[PublicKey25519Proposition, PublicKey25519NoncedBox](b))
Insertion[Long, PublicKey25519Proposition, PublicKey25519NoncedBox](b))
assert(toAppend.forall(_.box.value >= 0))

StateChanges[PublicKey25519Proposition, PublicKey25519NoncedBox](toRemove ++ toAppend)
StateChanges[Long, PublicKey25519Proposition, PublicKey25519NoncedBox](toRemove ++ toAppend)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ case class SimpleWallet(seed: Array[Byte] = Random.randomBytes(PrivKeyLength),
chainTransactions: Map[TransactionId, SimpleTransaction] = Map(),
offchainTransactions: Map[TransactionId, SimpleTransaction] = Map(),
currentBalance: Long = 0)
extends Wallet[PublicKey25519Proposition, SimpleTransaction, SimpleBlock, SimpleWallet] {
extends Wallet[Long, PublicKey25519Proposition, SimpleTransaction, SimpleBlock, SimpleWallet] {
override type S = PrivateKey25519
override type PI = PublicKey25519Proposition

Expand Down Expand Up @@ -43,7 +43,7 @@ case class SimpleWallet(seed: Array[Byte] = Random.randomBytes(PrivKeyLength),

override def historyTransactions: Seq[WalletTransaction[PublicKey25519Proposition, SimpleTransaction]] = ???

override def boxes(): Seq[WalletBox[PublicKey25519Proposition, PublicKey25519NoncedBox]] = Seq()
override def boxes(): Seq[WalletBox[Long, PublicKey25519Proposition, PublicKey25519NoncedBox]] = Seq()

override def scanOffchain(tx: SimpleTransaction): SimpleWallet = tx match {
case sp: SimplePayment =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import scorex.core.{NodeViewHolder, NodeViewModifier}
import scorex.crypto.encode.Base58


class HybridNodeViewHolder(settings: MiningSettings) extends NodeViewHolder[PublicKey25519Proposition,
class HybridNodeViewHolder(settings: MiningSettings) extends NodeViewHolder[Long, PublicKey25519Proposition,
SimpleBoxTransaction,
HybridBlock] {
override val networkChunkSize: Int = settings.networkChunkSize
Expand Down
51 changes: 39 additions & 12 deletions examples/src/main/scala/examples/hybrid/state/HBoxStoredState.scala
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,20 @@ import examples.curvepos.transaction.{PublicKey25519NoncedBox, PublicKey25519Non
import examples.hybrid.blocks.{HybridBlock, PosBlock, PowBlock}
import io.iohk.iodb.{ByteArrayWrapper, LSMStore}
import scorex.core.settings.Settings
import scorex.core.transaction.box.proposition.PublicKey25519Proposition
import scorex.core.transaction.BoxTransaction
import scorex.core.transaction.box.Box
import scorex.core.transaction.box.proposition.{Proposition, PublicKey25519Proposition}
import scorex.core.transaction.state.MinimalState.VersionTag
import scorex.core.transaction.state.{Insertion, Removal, StateChangeOperation, StateChanges}
import scorex.core.transaction.state.authenticated.BoxMinimalState
import scorex.core.utils.ScorexLogging
import scorex.crypto.encode.Base58

import scala.util.{Success, Try}
import scala.util.{Failure, Success, Try}


case class HBoxStoredState(store: LSMStore, override val version: VersionTag) extends
BoxMinimalState[PublicKey25519Proposition,
BoxMinimalState[Long, PublicKey25519Proposition,
PublicKey25519NoncedBox,
SimpleBoxTransaction,
HybridBlock,
Expand All @@ -42,7 +44,7 @@ case class HBoxStoredState(store: LSMStore, override val version: VersionTag) ex
//there's no easy way to know boxes associated with a proposition, without an additional index
override def boxesOf(proposition: PublicKey25519Proposition): Seq[PublicKey25519NoncedBox] = ???

override def changes(mod: HPMOD): Try[StateChanges[PublicKey25519Proposition, PublicKey25519NoncedBox]] =
override def changes(mod: HPMOD): Try[StateChanges[Long, PublicKey25519Proposition, PublicKey25519NoncedBox]] =
HBoxStoredState.changes(mod)

//Validate transactions in block and generator box
Expand All @@ -64,7 +66,32 @@ case class HBoxStoredState(store: LSMStore, override val version: VersionTag) ex
}
}

override def applyChanges(changes: StateChanges[PublicKey25519Proposition, PublicKey25519NoncedBox],
override def validate(tx: SimpleBoxTransaction): Try[Unit] = {
val statefulValid = {
val boxesSumTry = tx.unlockers.foldLeft[Try[Long]](Success(0L)) { case (partialRes, unlocker) =>
partialRes.flatMap { partialSum =>
closedBox(unlocker.closedBoxId) match {
case Some(box) =>
unlocker.boxKey.isValid(box.proposition, tx.messageToSign) match {
case true => Success(partialSum + box.value)
case false => Failure(new Exception("Incorrect unlocker"))
}
case None => Failure(new Exception(s"Box for unlocker $unlocker is not in the state"))
}
}
}

boxesSumTry flatMap { openSum =>
tx.newBoxes.map(_.value).sum == openSum - tx.fee match {
case true => Success[Unit](Unit)
case false => Failure(new Exception("Negative fee"))
}
}
}
statefulValid.flatMap(_ => semanticValidity(tx))
}

override def applyChanges(changes: StateChanges[Long, PublicKey25519Proposition, PublicKey25519NoncedBox],
newVersion: VersionTag): Try[HBoxStoredState] = Try {
val boxIdsToRemove = changes.toRemove.view.map(_.boxId).map(ByteArrayWrapper.apply)
val boxesToAdd = changes.toAppend.view.map(_.box).map(b => ByteArrayWrapper(b.id) -> ByteArrayWrapper(b.bytes))
Expand Down Expand Up @@ -97,14 +124,14 @@ case class HBoxStoredState(store: LSMStore, override val version: VersionTag) ex
object HBoxStoredState {
def semanticValidity(tx: SimpleBoxTransaction): Try[Unit] = tx.semanticValidity

def changes(mod: HybridBlock): Try[StateChanges[PublicKey25519Proposition, PublicKey25519NoncedBox]] = {
def changes(mod: HybridBlock): Try[StateChanges[Long, PublicKey25519Proposition, PublicKey25519NoncedBox]] = {
mod match {
case pb: PowBlock =>
val proposition: PublicKey25519Proposition = pb.generatorProposition
val nonce: Long = SimpleBoxTransaction.nonceFromDigest(mod.id)
val value: Long = 1
val minerBox = PublicKey25519NoncedBox(proposition, nonce, value)
Success(StateChanges[PublicKey25519Proposition, PublicKey25519NoncedBox](Seq(Insertion(minerBox))))
Success(StateChanges[Long, PublicKey25519Proposition, PublicKey25519NoncedBox](Seq(Insertion(minerBox))))
case ps: PosBlock =>
Try {
val initial = (Seq(): Seq[Array[Byte]], Seq(): Seq[PublicKey25519NoncedBox], 0L)
Expand All @@ -118,11 +145,11 @@ object HBoxStoredState {
val forgerNonce = Longs.fromByteArray(ps.id.take(8))
val forgerBox = PublicKey25519NoncedBox(ps.generatorBox.proposition, forgerNonce, reward)

val ops: Seq[StateChangeOperation[PublicKey25519Proposition, PublicKey25519NoncedBox]] =
toRemove.map(id => Removal[PublicKey25519Proposition, PublicKey25519NoncedBox](id)) ++
toAdd.map(b => Insertion[PublicKey25519Proposition, PublicKey25519NoncedBox](b)) ++
Seq(Insertion[PublicKey25519Proposition, PublicKey25519NoncedBox](forgerBox))
StateChanges[PublicKey25519Proposition, PublicKey25519NoncedBox](ops)
val ops: Seq[StateChangeOperation[Long, PublicKey25519Proposition, PublicKey25519NoncedBox]] =
toRemove.map(id => Removal[Long, PublicKey25519Proposition, PublicKey25519NoncedBox](id)) ++
toAdd.map(b => Insertion[Long, PublicKey25519Proposition, PublicKey25519NoncedBox](b)) ++
Seq(Insertion[Long, PublicKey25519Proposition, PublicKey25519NoncedBox](forgerBox))
StateChanges[Long, PublicKey25519Proposition, PublicKey25519NoncedBox](ops)
}
}
}
Expand Down
8 changes: 4 additions & 4 deletions examples/src/main/scala/examples/hybrid/wallet/HWallet.scala
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import scala.util.Try


case class HWallet(seed: Array[Byte], store: LSMStore)
extends Wallet[PublicKey25519Proposition, SimpleBoxTransaction, HybridBlock, HWallet]
extends Wallet[Long, PublicKey25519Proposition, SimpleBoxTransaction, HybridBlock, HWallet]
with ScorexLogging {

override type S = PrivateKey25519
Expand All @@ -35,12 +35,12 @@ case class HWallet(seed: Array[Byte], store: LSMStore)
}

private lazy val walletBoxSerializer =
new WalletBoxSerializer[PublicKey25519Proposition, PublicKey25519NoncedBox](PublicKey25519NoncedBoxSerializer)
new WalletBoxSerializer[Long, PublicKey25519Proposition, PublicKey25519NoncedBox](PublicKey25519NoncedBoxSerializer)

//not implemented intentionally for now
override def historyTransactions: Seq[WalletTransaction[PublicKey25519Proposition, SimpleBoxTransaction]] = ???

override def boxes(): Seq[WalletBox[PublicKey25519Proposition, PublicKey25519NoncedBox]] = {
override def boxes(): Seq[WalletBox[Long, PublicKey25519Proposition, PublicKey25519NoncedBox]] = {
boxIds
.flatMap(id => store.get(ByteArrayWrapper(id)))
.map(_.data)
Expand Down Expand Up @@ -84,7 +84,7 @@ case class HWallet(seed: Array[Byte], store: LSMStore)
.find(t => t.newBoxes.exists(tb => tb.id sameElements box.id))
val txId = boxTransaction.map(_.id).getOrElse(Array.fill(32)(0: Byte))
val ts = boxTransaction.map(_.timestamp).getOrElse(modifier.timestamp)
val wb = WalletBox[PublicKey25519Proposition, PublicKey25519NoncedBox](box, txId, ts)(PublicKey25519NoncedBoxSerializer)
val wb = WalletBox[Long, PublicKey25519Proposition, PublicKey25519NoncedBox](box, txId, ts)(PublicKey25519NoncedBoxSerializer)
ByteArrayWrapper(box.id) -> ByteArrayWrapper(wb.bytes)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ trait SimulatorFuctions {
10000000000L
)
}
val genesisChanges: StateChanges[PublicKey25519Proposition, PublicKey25519NoncedBox] =
StateChanges(genesisBoxes.map(box => Insertion[PublicKey25519Proposition, PublicKey25519NoncedBox](box)))
val genesisChanges: StateChanges[Long, PublicKey25519Proposition, PublicKey25519NoncedBox] =
StateChanges(genesisBoxes.map(box => Insertion[Long, PublicKey25519Proposition, PublicKey25519NoncedBox](box)))
InMemoryAuthenticatedUtxo(genesisBoxes.size, None, defaultId).applyChanges(genesisChanges, defaultId).get
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import scorex.core.{NodeViewHolder, NodeViewModifier}
import scorex.crypto.encode.Base58


class TNodeViewHolder(settings: MiningSettings) extends NodeViewHolder[PublicKey25519Proposition,
class TNodeViewHolder(settings: MiningSettings) extends NodeViewHolder[Long, PublicKey25519Proposition,
SimpleBoxTransaction,
HybridBlock] {
override val networkChunkSize: Int = settings.networkChunkSize
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,15 @@ import scorex.core.transaction.state.authenticated.BoxMinimalState
import scorex.core.utils.ScorexLogging
import scorex.crypto.authds.avltree.batch.{Insert, Lookup, Remove}

import scala.util.Try
import scala.util.{Failure, Success, Try}
import examples.trimchain.utxo.PersistentAuthenticatedUtxo.ProverType

/**
* Only for simulations where chain grows strictly linearly. No rollback support.
*/
case class InMemoryAuthenticatedUtxo(size: Int, proverOpt: Option[ProverType], override val version: VersionTag)
extends
BoxMinimalState[PublicKey25519Proposition,
BoxMinimalState[Long, PublicKey25519Proposition,
PublicKey25519NoncedBox,
SimpleBoxTransaction,
TModifier,
Expand Down Expand Up @@ -53,7 +53,7 @@ case class InMemoryAuthenticatedUtxo(size: Int, proverOpt: Option[ProverType], o
//there's no easy way to know boxes associated with a proposition, without an additional index
override def boxesOf(proposition: PublicKey25519Proposition): Seq[PublicKey25519NoncedBox] = ???

override def changes(mod: TModifier): Try[StateChanges[PublicKey25519Proposition, PublicKey25519NoncedBox]] =
override def changes(mod: TModifier): Try[StateChanges[Long, PublicKey25519Proposition, PublicKey25519NoncedBox]] =
PersistentAuthenticatedUtxo.changes(mod)

//Validate transactions in block and generator box
Expand All @@ -66,8 +66,33 @@ case class InMemoryAuthenticatedUtxo(size: Int, proverOpt: Option[ProverType], o
super.validate(mod).get
}

override def validate(tx: SimpleBoxTransaction): Try[Unit] = {
val statefulValid = {
val boxesSumTry = tx.unlockers.foldLeft[Try[Long]](Success(0L)) { case (partialRes, unlocker) =>
partialRes.flatMap { partialSum =>
closedBox(unlocker.closedBoxId) match {
case Some(box) =>
unlocker.boxKey.isValid(box.proposition, tx.messageToSign) match {
case true => Success(partialSum + box.value)
case false => Failure(new Exception("Incorrect unlocker"))
}
case None => Failure(new Exception(s"Box for unlocker $unlocker is not in the state"))
}
}
}

boxesSumTry flatMap { openSum =>
tx.newBoxes.map(_.value).sum == openSum - tx.fee match {
case true => Success[Unit](Unit)
case false => Failure(new Exception("Negative fee"))
}
}
}
statefulValid.flatMap(_ => semanticValidity(tx))
}

//todo: newVersion is not used
override def applyChanges(changes: StateChanges[PublicKey25519Proposition, PublicKey25519NoncedBox],
override def applyChanges(changes: StateChanges[Long, PublicKey25519Proposition, PublicKey25519NoncedBox],
newVersion: VersionTag): Try[InMemoryAuthenticatedUtxo] = Try {

changes.operations foreach { op =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,8 @@ object OneMinerSimulation extends App with Simulators {
)
}

val genesisChanges: StateChanges[PublicKey25519Proposition, PublicKey25519NoncedBox] =
StateChanges(genesisBoxes.map(box => Insertion[PublicKey25519Proposition, PublicKey25519NoncedBox](box)))
val genesisChanges: StateChanges[Long, PublicKey25519Proposition, PublicKey25519NoncedBox] =
StateChanges(genesisBoxes.map(box => Insertion[Long, PublicKey25519Proposition, PublicKey25519NoncedBox](box)))

var currentUtxo = InMemoryAuthenticatedUtxo(genesisBoxes.size, None, defaultId).applyChanges(genesisChanges, defaultId).get

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ object ValidationSimulator extends App with Simulators {
)
}

val genesisChanges: StateChanges[PublicKey25519Proposition, PublicKey25519NoncedBox] =
StateChanges(genesisBoxes.map(box => Insertion[PublicKey25519Proposition, PublicKey25519NoncedBox](box)))
val genesisChanges: StateChanges[Long, PublicKey25519Proposition, PublicKey25519NoncedBox] =
StateChanges(genesisBoxes.map(box => Insertion[Long, PublicKey25519Proposition, PublicKey25519NoncedBox](box)))

val genesisUtxo = InMemoryAuthenticatedUtxo(genesisBoxes.size, None, defaultId).applyChanges(genesisChanges, defaultId).get
val rootHash = genesisUtxo.rootHash
Expand Down
Loading