-
Notifications
You must be signed in to change notification settings - Fork 23
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fea(iris): ATL-1923 Implement in-memory ledger (#43)
- Loading branch information
Showing
36 changed files
with
654 additions
and
53 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
version = 3.5.8 | ||
runner.dialect = scala3 | ||
|
||
maxColumn = 120 | ||
trailingCommas = preserve |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
3 changes: 3 additions & 0 deletions
3
iris/service/core/src/main/scala/io/iohk/atala/iris/core/model/ledger/Funds.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
package io.iohk.atala.iris.core.model.ledger | ||
|
||
case class Funds(lovelaces: Int) |
12 changes: 12 additions & 0 deletions
12
iris/service/core/src/main/scala/io/iohk/atala/iris/core/model/ledger/Ledger.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
package io.iohk.atala.iris.core.model.ledger | ||
|
||
import enumeratum.{Enum, EnumEntry} | ||
|
||
import scala.collection.immutable.ArraySeq | ||
|
||
case class Ledger(name: String) | ||
|
||
object Ledger{ | ||
val InMemory: Ledger = Ledger("in-memory") | ||
val Mainnet: Ledger = Ledger("mainnet") | ||
} |
3 changes: 3 additions & 0 deletions
3
...service/core/src/main/scala/io/iohk/atala/iris/core/model/ledger/TransactionDetails.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
package io.iohk.atala.iris.core.model.ledger | ||
|
||
case class TransactionDetails(id: TransactionId, status: TransactionStatus) |
20 changes: 20 additions & 0 deletions
20
iris/service/core/src/main/scala/io/iohk/atala/iris/core/model/ledger/TransactionId.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
package io.iohk.atala.iris.core.model.ledger | ||
|
||
import com.typesafe.config.ConfigMemorySize | ||
import io.iohk.atala.shared.{HashValue, HashValueConfig, HashValueFrom} | ||
|
||
import scala.collection.immutable.ArraySeq | ||
|
||
class TransactionId(bytes: ArraySeq[Byte]) extends HashValue { | ||
override def value: ArraySeq[Byte] = bytes | ||
} | ||
|
||
object TransactionId extends HashValueFrom[TransactionId] { | ||
|
||
override val config: HashValueConfig = HashValueConfig( | ||
ConfigMemorySize.ofBytes(32) | ||
) | ||
|
||
override protected def constructor(value: ArraySeq[Byte]): TransactionId = | ||
new TransactionId(value) | ||
} |
16 changes: 16 additions & 0 deletions
16
.../service/core/src/main/scala/io/iohk/atala/iris/core/model/ledger/TransactionStatus.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
package io.iohk.atala.iris.core.model.ledger | ||
|
||
import enumeratum.{Enum, EnumEntry} | ||
import enumeratum.EnumEntry.Snakecase | ||
import scala.collection.immutable.ArraySeq | ||
|
||
sealed trait TransactionStatus extends EnumEntry with Snakecase | ||
|
||
object TransactionStatus extends Enum[TransactionStatus] { | ||
val values = ArraySeq(InMempool, Submitted, Expired, InLedger) | ||
|
||
case object InMempool extends TransactionStatus | ||
case object Submitted extends TransactionStatus | ||
case object Expired extends TransactionStatus | ||
case object InLedger extends TransactionStatus | ||
} |
6 changes: 3 additions & 3 deletions
6
...service/core/src/main/scala/io/iohk/atala/iris/core/repository/OperationsRepository.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,10 @@ | ||
package io.iohk.atala.iris.core.repository | ||
|
||
import io.iohk.atala.iris.core.model.{IrisOperation, IrisOperationId, SignedIrisOperation} | ||
import io.iohk.atala.iris.core.model as model | ||
import zio.* | ||
|
||
// TODO: replace with actual implementation | ||
trait OperationsRepository[F[_]] { | ||
def getOperation(id: IrisOperationId): F[IrisOperation] | ||
def saveOperations(ops: Seq[SignedIrisOperation]): F[Unit] | ||
def getOperation(id: model.IrisOperationId): F[model.IrisOperation] | ||
def saveOperations(ops: Seq[model.IrisOperation]): F[Unit] | ||
} |
110 changes: 110 additions & 0 deletions
110
...core/src/main/scala/io/iohk/atala/iris/core/service/InmemoryUnderlyingLedgerService.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
package io.iohk.atala.iris.core.service | ||
|
||
import io.iohk.atala.iris.core.model.ledger.TransactionStatus.{InLedger, InMempool} | ||
import io.iohk.atala.iris.core.model.ledger.{Funds, TransactionDetails, TransactionId} | ||
import io.iohk.atala.iris.core.service.InmemoryUnderlyingLedgerService.{CardanoBlock, CardanoTransaction, Config} | ||
import io.iohk.atala.iris.proto.dlt as proto | ||
import io.iohk.atala.prism.crypto.Sha256 | ||
import zio.stm.* | ||
import zio.* | ||
|
||
object InmemoryUnderlyingLedgerService { | ||
case class Config(blockEvery: Duration, initialFunds: Funds, txFee: Funds) | ||
|
||
case class CardanoTransaction(operations: Seq[proto.IrisOperation]) { | ||
lazy val transactionId: TransactionId = { | ||
val objectBytes = proto.IrisObject(operations).toByteArray | ||
val hash = Sha256.compute(objectBytes) | ||
TransactionId | ||
.from(hash.getValue) | ||
.getOrElse(throw new RuntimeException("Unexpected invalid hash")) | ||
} | ||
} | ||
|
||
case class CardanoBlock(txs: Seq[CardanoTransaction]) | ||
|
||
def layer(config: Config): ULayer[InmemoryUnderlyingLedgerService] = ZLayer.fromZIO { | ||
for { | ||
mempoolRef <- TRef.make(Vector[CardanoTransaction]()).commit | ||
blocksRef <- TRef.make(Vector[CardanoBlock]()).commit | ||
initialBalance <- TRef.make(config.initialFunds).commit | ||
srv = InmemoryUnderlyingLedgerService(config, mempoolRef, blocksRef, initialBalance) | ||
_ <- srv.startBackgroundProcess() | ||
} yield srv | ||
} | ||
} | ||
|
||
class InmemoryUnderlyingLedgerService( | ||
config: Config, | ||
mempoolRef: TRef[Vector[CardanoTransaction]], | ||
blocksRef: TRef[Vector[CardanoBlock]], | ||
balanceRef: TRef[Funds] | ||
) extends UnderlyingLedgerService { | ||
|
||
override def publish(operations: Seq[proto.IrisOperation]): IO[LedgerError, Unit] = | ||
STM.atomically { | ||
for { | ||
curFunds <- balanceRef.get | ||
newFunds <- STM.cond( | ||
curFunds.lovelaces >= config.txFee.lovelaces, | ||
Funds(curFunds.lovelaces - config.txFee.lovelaces), | ||
LedgerError("Insufficient wallet balance") | ||
) | ||
_ <- balanceRef.set(newFunds) | ||
_ <- mempoolRef.update(_.appended(CardanoTransaction(operations))) | ||
} yield () | ||
} | ||
|
||
override def getTransactionDetails(transactionId: TransactionId): IO[LedgerError, TransactionDetails] = | ||
STM.atomically { | ||
for { | ||
mempool <- mempoolRef.get | ||
blockchain <- blocksRef.get | ||
tdetails <- STM | ||
.fromOption { | ||
mempool | ||
.find(_.transactionId == transactionId) | ||
.map(_ => TransactionDetails(transactionId, InMempool)) | ||
} | ||
.orElse { | ||
STM.fromOption { | ||
blockchain | ||
.find(block => block.txs.exists(t => t.transactionId == transactionId)) | ||
.map(_ => TransactionDetails(transactionId, InLedger)) | ||
} | ||
} | ||
.orElseFail(LedgerError(s"Couldn't find tx $transactionId")) | ||
} yield tdetails | ||
} | ||
|
||
override def deleteTransaction(transactionId: TransactionId): IO[LedgerError, Unit] = STM.atomically { | ||
for { | ||
mempool <- mempoolRef.get | ||
_ <- STM.cond( | ||
mempool.exists(_.transactionId == transactionId), | ||
(), | ||
LedgerError(s"Transaction $transactionId not found in the mempool") | ||
) | ||
_ <- mempoolRef.update(m => m.filter(_.transactionId != transactionId)) | ||
_ <- balanceRef.update(b => Funds(b.lovelaces + config.txFee.lovelaces)) | ||
} yield () | ||
} | ||
|
||
override def getWalletBalance: IO[LedgerError, Funds] = balanceRef.get.commit | ||
|
||
def getMempool: UIO[List[CardanoTransaction]] = mempoolRef.get.commit.map(_.toList) | ||
|
||
def getBlocks: UIO[List[CardanoBlock]] = blocksRef.get.commit.map(_.toList) | ||
|
||
private[service] def startBackgroundProcess(): UIO[Unit] = STM | ||
.atomically { | ||
for { | ||
// Craft a new block from mempool transactions | ||
txs <- mempoolRef.modify(old => (old, Vector.empty)) | ||
_ <- blocksRef.update(_.appended(CardanoBlock(txs))) | ||
} yield () | ||
} | ||
.repeat(Schedule.spaced(config.blockEvery)) | ||
.fork | ||
.map(_ => ()) | ||
} |
6 changes: 3 additions & 3 deletions
6
iris/service/core/src/main/scala/io/iohk/atala/iris/core/service/PublishingService.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,17 +1,17 @@ | ||
package io.iohk.atala.iris.core.service | ||
|
||
import io.iohk.atala.iris.core.model.SignedIrisOperation | ||
import io.iohk.atala.iris.proto.dlt as proto | ||
import zio.* | ||
|
||
// TODO: replace with actual implementation | ||
trait PublishingService { | ||
def publishOperations(op: SignedIrisOperation): UIO[Unit] | ||
def publishOperation(op: proto.IrisOperation): UIO[Unit] | ||
} | ||
|
||
object MockPublishingService { | ||
val layer: ULayer[PublishingService] = ZLayer.succeed { | ||
new PublishingService { | ||
override def publishOperations(op: SignedIrisOperation): UIO[Unit] = ZIO.unit | ||
override def publishOperation(op: proto.IrisOperation): UIO[Unit] = ZIO.unit | ||
} | ||
} | ||
} |
20 changes: 20 additions & 0 deletions
20
...service/core/src/main/scala/io/iohk/atala/iris/core/service/UnderlyingLedgerService.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
package io.iohk.atala.iris.core.service | ||
|
||
import io.iohk.atala.iris.proto.dlt as proto | ||
import io.iohk.atala.iris.core.model.IrisOperation | ||
import io.iohk.atala.iris.core.model.ledger.{Funds, TransactionDetails, TransactionId} | ||
import zio.{IO, UIO} | ||
|
||
case class LedgerError(msg: String) extends RuntimeException(msg) | ||
|
||
trait UnderlyingLedgerService { | ||
// def getType: Ledger | ||
|
||
def publish(operations: Seq[proto.IrisOperation]): IO[LedgerError, Unit] | ||
|
||
def getTransactionDetails(transactionId: TransactionId): IO[LedgerError, TransactionDetails] | ||
|
||
def deleteTransaction(transactionId: TransactionId): IO[LedgerError, Unit] | ||
|
||
def getWalletBalance: IO[LedgerError, Funds] | ||
} |
7 changes: 3 additions & 4 deletions
7
iris/service/core/src/main/scala/io/iohk/atala/iris/core/worker/PublishingScheduler.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,17 +1,16 @@ | ||
package io.iohk.atala.iris.core.worker | ||
|
||
import io.iohk.atala.iris.core.model.SignedIrisOperation | ||
import io.iohk.atala.iris.core.service.PublishingService | ||
import io.iohk.atala.iris.proto.dlt as proto | ||
import zio.{UIO, ULayer, ZIO, ZLayer} | ||
|
||
trait PublishingScheduler { | ||
def scheduleOperations(op: SignedIrisOperation): UIO[Unit] | ||
def scheduleOperations(op: proto.IrisOperation): UIO[Unit] | ||
} | ||
|
||
object MockPublishingScheduler { | ||
val layer: ULayer[PublishingScheduler] = ZLayer.succeed { | ||
new PublishingScheduler { | ||
def scheduleOperations(op: SignedIrisOperation): UIO[Unit] = ZIO.unit | ||
def scheduleOperations(op: proto.IrisOperation): UIO[Unit] = ZIO.unit | ||
} | ||
} | ||
} |
Oops, something went wrong.