-
Notifications
You must be signed in to change notification settings - Fork 8
/
DummyBlockchainSimulationImpl.scala
162 lines (128 loc) · 5.17 KB
/
DummyBlockchainSimulationImpl.scala
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
package org.ergoplatform.playgroundenv.models
import org.ergoplatform.ErgoBox.BoxId
import org.ergoplatform.{ErgoBox, ErgoLikeTransaction}
import org.ergoplatform.compiler.ErgoScalaCompiler._
import org.ergoplatform.wallet.protocol.context.{ErgoLikeParameters, ErgoLikeStateContext}
import scorex.crypto.authds.ADDigest
import scorex.crypto.hash.Digest32
import scorex.util.encode.Base16
import scorex.util._
import sigmastate.eval.{CGroupElement, CPreHeader, Colls}
import sigmastate.interpreter.CryptoConstants
import special.collection.Coll
import special.sigma.{Header, PreHeader}
import sigmastate.eval.Extensions._
import scala.collection.mutable
import org.ergoplatform.playgroundenv.dsl.ObjectGenerators
import org.ergoplatform.playgroundenv.utils.TransactionVerifier
case class DummyBlockchainSimulationImpl(scenarioName: String)
extends BlockchainSimulation {
private var boxes: mutable.ArrayBuffer[ErgoBox] = new mutable.ArrayBuffer[ErgoBox]()
private var unspentBoxes: mutable.ArrayBuffer[ErgoBox] =
new mutable.ArrayBuffer[ErgoBox]()
private val tokenNames: mutable.Map[ModifierId, String] = mutable.Map()
private var chainHeight: Int = 0
private def getUnspentBoxesFor(address: Address): List[ErgoBox] =
unspentBoxes.filter { b =>
contract(address.pubKey).ergoTree == b.ergoTree
}.toList
def stateContext: ErgoLikeStateContext = new ErgoLikeStateContext {
override def sigmaLastHeaders: Coll[Header] = Colls.emptyColl
override def previousStateDigest: ADDigest =
Base16
.decode("a5df145d41ab15a01e0cd3ffbab046f0d029e5412293072ad0f5827428589b9302")
.map(ADDigest @@ _)
.getOrElse(throw new Error(s"Failed to parse genesisStateDigest"))
override def sigmaPreHeader: PreHeader = CPreHeader(
version = 0,
parentId = Colls.emptyColl[Byte],
timestamp = 0,
nBits = 0,
height = chainHeight,
minerPk = CGroupElement(CryptoConstants.dlogGroup.generator),
votes = Colls.emptyColl[Byte]
)
}
val parameters: ErgoLikeParameters = new ErgoLikeParameters {
override def storageFeeFactor: Int = 1250000
override def minValuePerByte: Int = 360
override def maxBlockSize: Int = 524288
override def tokenAccessCost: Int = 100
override def inputCost: Int = 2000
override def dataInputCost: Int = 100
override def outputCost: Int = 100
override def maxBlockCost: Long = 2000000
override def softForkStartingHeight: Option[Int] = None
override def softForkVotesCollected: Option[Int] = None
override def blockVersion: Byte = 1
}
def generateUnspentBoxesFor(
address: Address,
toSpend: Long,
tokensToSpend: List[TokenAmount]
): Unit = {
tokensToSpend.foreach { t =>
tokenNames += (t.token.tokenId.toArray.toModifierId -> t.token.tokenName)
}
val b = ErgoBox(
value = toSpend,
ergoTree = contract(address.pubKey).ergoTree,
creationHeight = chainHeight,
additionalTokens =
tokensToSpend.map(ta => (Digest32 @@ ta.token.tokenId.toArray, ta.tokenAmount))
)
unspentBoxes.append(b)
boxes.append(b)
}
def selectUnspentBoxesFor(
address: Address,
toSpend: Long,
tokensToSpend: List[TokenAmount]
): List[ErgoBox] = {
val treeToFind = contract(address.pubKey).ergoTree
val filtered = unspentBoxes.filter { b =>
b.ergoTree == treeToFind
}.toList
filtered
}
def getUnspentBox(id: BoxId): ErgoBox =
unspentBoxes.find(b => java.util.Arrays.equals(b.id, id)).get
def getBox(id: BoxId): ErgoBox =
boxes.find(b => java.util.Arrays.equals(b.id, id)).get
override def newParty(name: String): Party = {
val party = DummyPartyImpl(this, name)
val pk = party.wallet.getAddress.proveDlog
println(s"..$scenarioName: Creating new party: $name, pk: $pk")
party
}
override def send(tx: ErgoLikeTransaction): Unit = {
val boxesToSpend = tx.inputs.map(i => getUnspentBox(i.boxId)).toIndexedSeq
val dataInputBoxes = tx.dataInputs.map(i => getBox(i.boxId)).toIndexedSeq
TransactionVerifier.verify(tx, boxesToSpend, dataInputBoxes, parameters, stateContext)
val newBoxes: mutable.ArrayBuffer[ErgoBox] = new mutable.ArrayBuffer[ErgoBox]()
newBoxes.appendAll(tx.outputs)
newBoxes.appendAll(
unspentBoxes.filterNot(b =>
tx.inputs.map(_.boxId.toModifierId).contains(b.id.toModifierId)
)
)
unspentBoxes = newBoxes
boxes.appendAll(tx.outputs)
println(s"..$scenarioName: Accepting transaction ${tx.id} to the blockchain")
}
override def newToken(name: String): TokenInfo = {
val tokenId = ObjectGenerators.newErgoId
tokenNames += (tokenId.toArray.toModifierId -> name)
TokenInfo(tokenId, name)
}
def getUnspentCoinsFor(address: Address): Long =
getUnspentBoxesFor(address).map(_.value).sum
def getUnspentTokensFor(address: Address): List[TokenAmount] =
getUnspentBoxesFor(address).flatMap { b =>
b.additionalTokens.toArray.map { t =>
TokenAmount(TokenInfo(t._1.toColl, tokenNames(t._1.toModifierId)), t._2)
}
}
def getHeight: Int = chainHeight
def setHeight(height: Int): Unit = { chainHeight = height }
}