Skip to content

Commit ac31fa8

Browse files
committed
fixbug: Trie/node put data
1 parent 7c1a49f commit ac31fa8

File tree

8 files changed

+99
-23
lines changed

8 files changed

+99
-23
lines changed

ast/src/main/scala/fssi/ast/BlockStore.scala

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,4 +29,9 @@ import java.io._
2929
* @param determinedBlock the latest determined block which current undetermined block is based on.
3030
*/
3131
def appendTransactionToUnDeterminedBlock(determinedBlock: Block, transaction: Transaction): P[F, Block]
32+
33+
/** when some block is agreed, the undetermined block should be cleared, for next block to use it
34+
* @param block current reached agreement block
35+
*/
36+
def cleanUndeterminedBlock(block: Block): P[F, Unit]
3237
}

ast/src/main/scala/fssi/ast/uc/CoreNodeProgram.scala

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ trait CoreNodeProgram[F[_]] extends BaseProgram[F] with CoreNodeProgramHelper[F]
7070
import crypto._
7171
import consensusEngine._
7272
import network._
73+
import log._
7374
for {
7475
toBeSingedBytes <- calculateSingedBytesOfTransaction(transaction)
7576
verified <- verifySignature(toBeSingedBytes,
@@ -80,11 +81,15 @@ trait CoreNodeProgram[F[_]] extends BaseProgram[F] with CoreNodeProgramHelper[F]
8081
_ <- requireM(
8182
verified,
8283
new FSSIException(s"Transaction of id=${transaction.id} signature can't be verified"))
83-
determinedBlock <- getLatestDeterminedBlock()
84+
determinedBlock <- getLatestDeterminedBlock()
85+
_ <- info(
86+
s"found latest block: ${determinedBlock.height},${determinedBlock.hash.value.toString}")
8487
undeterminedBlock <- appendTransactionToUnDeterminedBlock(determinedBlock, transaction)
85-
node <- network.getCurrentNode()
86-
_ <- log.info("try to agree block...")
87-
_ <- tryToAgreeBlock(node.account.get, undeterminedBlock, undeterminedBlock)
88+
_ <- info(
89+
s"current undetermined block: ${undeterminedBlock.height}, transaction size: ${undeterminedBlock.transactions.size}")
90+
node <- network.getCurrentNode()
91+
92+
_ <- tryToAgreeBlock(node.account.get, undeterminedBlock, undeterminedBlock)
8893
} yield ()
8994
}
9095

@@ -152,12 +157,12 @@ trait CoreNodeProgram[F[_]] extends BaseProgram[F] with CoreNodeProgramHelper[F]
152157
case Left(t) =>
153158
for {
154159
_ <- info(s"run block(height=${block.height}) transactions failed", Some(t))
155-
_ <- rollback(block.height)
160+
_ <- rollback(block)
156161
} yield ()
157162
case Right(_) =>
158163
for {
159164
_ <- info(s"run block(height=${block.height}) transactions successfully")
160-
_ <- commit(block.height)
165+
_ <- commit(block)
161166
} yield ()
162167
}
163168
} yield ()

ast/src/main/scala/fssi/ast/uc/CoreNodeProgramHelper.scala

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,13 +46,17 @@ private[uc] trait CoreNodeProgramHelper[F[_]] extends BaseProgram[F] {
4646
def tempRunRunContract(height: BigInt,
4747
runContract: Transaction.RunContract): SP[F, Either[Throwable, Unit]] = ???
4848

49-
def commit(height: BigInt): SP[F, Unit] = {
49+
def commit(block: Block): SP[F, Unit] = {
5050
import tokenStore._
5151
import contractDataStore._
5252
import contractStore._
53+
import blockStore._
5354
import log._
5455

56+
val height = block.height
5557
for {
58+
_ <- saveBlock(block)
59+
_ <- cleanUndeterminedBlock(block)
5660
_ <- commitStagedToken(height)
5761
_ <- info(s"commit staged token of block($height)")
5862
_ <- commitStagedContract(height)
@@ -63,12 +67,13 @@ private[uc] trait CoreNodeProgramHelper[F[_]] extends BaseProgram[F] {
6367

6468
}
6569

66-
def rollback(height: BigInt): SP[F, Unit] = {
70+
def rollback(block: Block): SP[F, Unit] = {
6771
import tokenStore._
6872
import contractDataStore._
6973
import contractStore._
7074
import log._
7175

76+
val height = block.height
7277
for {
7378
_ <- rollbackStagedToken(height)
7479
_ <- info(s"rollback staged token of block($height)")

interpreter/src/main/scala/fssi/interpreter/BlockStoreHandler.scala

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,17 @@ class BlockStoreHandler extends BlockStore.Handler[Stack] with BlockCalSupport w
168168
hashedBlock
169169

170170
}
171+
172+
override def cleanUndeterminedBlock(block: Block): Stack[Unit] = Stack { setting =>
173+
val tmp = undeterminedBlockRef.get()
174+
if (tmp.isDefined) {
175+
val tmpBlock = tmp.get
176+
if (tmpBlock.height <= block.height)
177+
undeterminedBlockRef.set(None)
178+
else ()
179+
} else ()
180+
181+
}
171182
}
172183

173184
object BlockStoreHandler {

interpreter/src/main/scala/fssi/interpreter/ContractDataStoreHandler.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,18 +38,18 @@ class ContractDataStoreHandler extends ContractDataStore.Handler[Stack] with Log
3838

3939
reloadResult match {
4040
case Left(t) =>
41-
log.error("reload block trie faield", t)
41+
log.error("reload contract data trie faield", t)
4242
throw t
4343
case Right(trie) =>
4444
contractDataTrie := trie
45-
log.info(s"reloaded block trie, root hash = ${trie.rootHexHash}")
45+
log.info(s"reloaded contract data trie, root hash = ${trie.rootHexHash}")
4646
}
4747
} else if (f.notExists) {
4848
//init
4949
val trie = Trie.empty[Char, String]
5050
f.overwrite(trie.asJson.spaces2)
5151
contractDataTrie := trie
52-
log.info("init block trie.")
52+
log.info("init contract data trie.")
5353
} else
5454
throw new RuntimeException(s"$f should be empty to init or a regular file to load.")
5555

interpreter/src/main/scala/fssi/interpreter/ContractStoreHandler.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,18 +41,18 @@ class ContractStoreHandler extends ContractStore.Handler[Stack] with LogSupport
4141

4242
reloadResult match {
4343
case Left(t) =>
44-
log.error("reload block trie faield", t)
44+
log.error("reload contract trie faield", t)
4545
throw t
4646
case Right(trie) =>
4747
contractTrie := trie
48-
log.info(s"reloaded block trie, root hash = ${trie.rootHexHash}")
48+
log.info(s"reloaded contract trie, root hash = ${trie.rootHexHash}")
4949
}
5050
} else if (f.notExists) {
5151
//init
5252
val trie = Trie.empty[Char, String]
5353
f.overwrite(trie.asJson.spaces2)
5454
contractTrie := trie
55-
log.info("init block trie.")
55+
log.info("init contract trie.")
5656
} else
5757
throw new RuntimeException(s"$f should be empty to init or a regular file to load.")
5858

interpreter/src/main/scala/fssi/interpreter/TokenStoreHandler.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,18 +49,18 @@ class TokenStoreHandler extends TokenStore.Handler[Stack] with LogSupport {
4949

5050
reloadResult match {
5151
case Left(t) =>
52-
log.error("reload block trie faield", t)
52+
log.error("reload token trie faield", t)
5353
throw t
5454
case Right(trie) =>
5555
tokenTrie := trie
56-
log.info(s"reloaded block trie, root hash = ${trie.rootHexHash}")
56+
log.info(s"reloaded token trie, root hash = ${trie.rootHexHash}")
5757
}
5858
} else if (f.notExists) {
5959
//init
6060
val trie = Trie.empty[Char, String]
6161
f.overwrite(trie.asJson.spaces2)
6262
tokenTrie := trie
63-
log.info("init block trie.")
63+
log.info("init token trie.")
6464
} else
6565
throw new RuntimeException(s"$f should be empty to init or a regular file to load.")
6666

trie/src/main/scala/fssi/trie/Node.scala

Lines changed: 56 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,8 @@ object Node {
4040

4141
}
4242

43-
def branch[K, V](slots: Slot[K, V]*): Branch[K, V] = Branch(slots.map(x => x.idx -> x).toMap)
43+
def branch[K: ClassTag, V](slots: Slot[K, V]*): Branch[K, V] =
44+
Branch(slots.map(x => x.idx -> x).toMap)
4445

4546
case class Slot[K: ClassTag, V](idx: K, data: Option[V], node: Option[Node[K, V]])
4647
extends Node[K, V] {
@@ -88,6 +89,8 @@ object Node {
8889
case class Compact[K: ClassTag, V](indexes: Array[K], data: Option[V], node: Option[Node[K, V]])
8990
extends Node[K, V] {
9091

92+
require(indexes.length > 0)
93+
9194
/** put a k-v to the node
9295
*
9396
* @return new node contains k-v data and old node
@@ -103,9 +106,15 @@ object Node {
103106
// key is prefix of indexes
104107
Compact(prefix, Some(_data), Some(copy(indexes = indexes.drop(prefix.length))))
105108
} else if (prefix sameElements indexes) {
109+
val restKeys = key.drop(prefix.length)
110+
val n =
111+
if (restKeys.length > 1) Compact(restKeys, Some(_data), None)
112+
else Slot(restKeys.head, Some(_data), None)
113+
/*
106114
val n = Compact(key.drop(prefix.length), Some(_data), None)
115+
*/
107116
// add n to this node
108-
copy(node = node.map(_.put(key.drop(prefix.length), _data)).orElse(Some(n)))
117+
copy(node = node.map(_.put(restKeys, _data)).orElse(Some(n)))
109118
} else {
110119
val n: Node[K, V] = {
111120
val k1 = indexes.drop(prefix.length)
@@ -123,8 +132,11 @@ object Node {
123132
Compact(prefix, None, Some(n))
124133
}
125134
} else {
126-
val slot1 = Slot(indexes.head, None, Some(copy(indexes = indexes.drop(1))))
127-
val slot2 = Slot(key.head, None, Some(Compact(key.drop(1), Some(_data), None)))
135+
val restKeys1 = indexes.drop(1)
136+
// output should be a branch
137+
// turn compact to a slot
138+
val slot1: Slot[K, V] = compactToSlot(this)
139+
val slot2: Slot[K, V] = compactToSlot(Compact(key, Some(_data), None))
128140
Branch(Map(slot1.idx -> slot1, slot2.idx -> slot2))
129141
}
130142
}
@@ -153,13 +165,45 @@ object Node {
153165
else s"Compact(${indexes.map(_.toString).mkString(",")} -> $data))"
154166
}
155167

156-
case class Branch[K, V](slots: Map[K, Slot[K, V]]) extends Node[K, V] {
168+
case class Branch[K: ClassTag, V](slots: Map[K, Slot[K, V]]) extends Node[K, V] {
157169

158170
/** put a k-v to the node
159171
*
160172
* @return new node contains k-v data and old node
161173
*/
162-
override def put(key: Array[K], data: V): Node[K, V] = ???
174+
override def put(key: Array[K], data: V): Node[K, V] = {
175+
require(key.length > 0)
176+
val head = key.head
177+
if (slots.contains(head)) {
178+
val slot = slots(head)
179+
if (key.length == 1) {
180+
val newSlot = slot.copy(data = Some(data))
181+
copy(slots = slots + (head -> newSlot))
182+
} else {
183+
val restKeys = key.drop(1)
184+
val n =
185+
if (restKeys.length > 1) Compact(restKeys, Some(data), None)
186+
else Slot(restKeys.head, Some(data), None)
187+
val newSlotNode = slot.node
188+
.map(_.put(restKeys, data))
189+
.getOrElse(n)
190+
val newSlot = slot.copy(node = Some(newSlotNode))
191+
copy(slots = slots + (head -> newSlot))
192+
}
193+
} else {
194+
if (key.length == 1) {
195+
val slot = Slot(head, Some(data), None)
196+
copy(slots = slots + (head -> slot))
197+
} else {
198+
val restKeys = key.drop(0)
199+
val n =
200+
if (restKeys.length > 1) Compact(key.drop(0), Some(data), None)
201+
else Slot(restKeys.head, Some(data), None)
202+
val slot = Slot(head, None, Some(n))
203+
copy(slots = slots + (head -> slot))
204+
}
205+
}
206+
}
163207

164208
/** get a value with key from node
165209
*
@@ -194,4 +238,10 @@ object Node {
194238
loop(k1, k2, Array.empty[K])
195239
}
196240

241+
def compactToSlot[K: ClassTag, V](compact: Compact[K, V]): Slot[K, V] = compact.indexes.toList match {
242+
case h :: Nil => Slot(h, compact.data, compact.node)
243+
case h :: t => Slot(h, None, Some(compact.copy(indexes = t.toArray)))
244+
case _ => throw new RuntimeException("compact indexes should not be nil") // impossible
245+
}
246+
197247
}

0 commit comments

Comments
 (0)