mirror of
https://github.com/fluencelabs/tendermint-demo
synced 2025-03-15 07:40:50 +00:00
entry class refactored, comments added
This commit is contained in:
parent
08dc8574f5
commit
2a1d836953
3
.gitignore
vendored
3
.gitignore
vendored
@ -99,3 +99,6 @@ ENV/
|
||||
|
||||
# mypy
|
||||
.mypy_cache/
|
||||
|
||||
# IntelliJ Idea
|
||||
.idea
|
@ -3,18 +3,23 @@ package kvstore
|
||||
import java.nio.ByteBuffer
|
||||
|
||||
import com.github.jtendermint.jabci.api._
|
||||
import com.github.jtendermint.jabci.socket.TSocket
|
||||
import com.github.jtendermint.jabci.types.{ResponseCheckTx, _}
|
||||
import com.google.protobuf.ByteString
|
||||
|
||||
import scala.collection.mutable.ArrayBuffer
|
||||
|
||||
object KVStoreServerRunner extends IDeliverTx with ICheckTx with ICommit with IQuery {
|
||||
|
||||
def main(args: Array[String]): Unit = {
|
||||
KVStoreServerRunner.start()
|
||||
}
|
||||
|
||||
/**
|
||||
* Tendermint establishes 3 socket connections with the app:
|
||||
* - Mempool for CheckTx
|
||||
* - Consensus for DeliverTx and Commit
|
||||
* - Info for Query
|
||||
*
|
||||
* According to specification the app maintains separate in-memory states for every connections:
|
||||
* – [[ABCIHandler.consensusRoot]]: the latest state modified with every successful transaction on DeliverTx
|
||||
* – [[ABCIHandler.storage]]: array of committed snapshots for Info connection
|
||||
* – [[ABCIHandler.mempoolRoot]]: the latest committed snapshot for Mempool connection (not used currently)
|
||||
*/
|
||||
object ABCIHandler extends IDeliverTx with ICheckTx with ICommit with IQuery {
|
||||
private val storage: ArrayBuffer[Node] = new ArrayBuffer[Node]()
|
||||
|
||||
private var consensusRoot: Node = Node.emptyNode
|
||||
@ -22,20 +27,6 @@ object KVStoreServerRunner extends IDeliverTx with ICheckTx with ICommit with IQ
|
||||
@volatile
|
||||
private var mempoolRoot: Node = Node.emptyNode
|
||||
|
||||
def start(): Unit = {
|
||||
System.out.println("starting KVStore")
|
||||
val socket = new TSocket
|
||||
|
||||
socket.registerListener(this)
|
||||
|
||||
val t = new Thread(() => socket.start(46658))
|
||||
t.setName("KVStore server Main Thread")
|
||||
t.start()
|
||||
while (true) {
|
||||
Thread.sleep(1000L)
|
||||
}
|
||||
}
|
||||
|
||||
override def receivedDeliverTx(req: RequestDeliverTx): ResponseDeliverTx = {
|
||||
val tx = req.getTx.toStringUtf8
|
||||
val txPayload = tx.split("###")(0)
|
||||
@ -72,7 +63,8 @@ object KVStoreServerRunner extends IDeliverTx with ICheckTx with ICommit with IQ
|
||||
}
|
||||
|
||||
override def requestCheckTx(req: RequestCheckTx): ResponseCheckTx = {
|
||||
// check mempoolRoot
|
||||
// no transaction processing logic currently
|
||||
// mempoolRoot is intended to be used here as the latest committed state
|
||||
|
||||
val tx = req.getTx.toStringUtf8
|
||||
if (tx == "BAD_CHECK") {
|
||||
@ -104,28 +96,18 @@ object KVStoreServerRunner extends IDeliverTx with ICheckTx with ICommit with IQ
|
||||
val lsPattern = "ls:(.*)".r
|
||||
|
||||
val query = req.getData.toStringUtf8
|
||||
query match {
|
||||
case getPattern(key) =>
|
||||
val result = root.getValue(key)
|
||||
val proof = if (result.isDefined && req.getProve) twoLevelMerkleListToString(root.getProof(key)) else ""
|
||||
|
||||
ResponseQuery.newBuilder.setCode(CodeType.OK)
|
||||
.setValue(ByteString.copyFromUtf8(result.getOrElse("")))
|
||||
.setProof(ByteString.copyFromUtf8(proof))
|
||||
.build
|
||||
case lsPattern(key) =>
|
||||
val result = root.listChildren(key)
|
||||
val proof = if (result.isDefined && req.getProve) twoLevelMerkleListToString(root.getProof(key)) else ""
|
||||
|
||||
ResponseQuery.newBuilder.setCode(CodeType.OK)
|
||||
.setValue(ByteString.copyFromUtf8(result.map(x => x.mkString(" ")).getOrElse("")))
|
||||
.setProof(ByteString.copyFromUtf8(proof))
|
||||
.build
|
||||
val (key, result) = query match {
|
||||
case getPattern(key) => (key, root.getValue(key))
|
||||
case lsPattern(key) => (key, root.listChildren(key).map(x => x.mkString(" ")))
|
||||
case _ =>
|
||||
ResponseQuery.newBuilder.setCode(CodeType.BAD).setLog("Invalid query path. Got " + query).build
|
||||
return ResponseQuery.newBuilder.setCode(CodeType.BAD).setLog("Invalid query path. Got " + query).build
|
||||
}
|
||||
}
|
||||
|
||||
private def twoLevelMerkleListToString(list: List[List[MerkleHash]]): String =
|
||||
list.map(level => level.map(MerkleUtil.merkleHashToHex).mkString(" ")).mkString(", ")
|
||||
val proof = if (result.isDefined && req.getProve) MerkleUtil.twoLevelMerkleListToString(root.getProof(key)) else ""
|
||||
|
||||
ResponseQuery.newBuilder.setCode(CodeType.OK)
|
||||
.setValue(ByteString.copyFromUtf8(result.getOrElse("")))
|
||||
.setProof(ByteString.copyFromUtf8(proof))
|
||||
.build
|
||||
}
|
||||
}
|
@ -19,4 +19,7 @@ object MerkleUtil {
|
||||
|
||||
def merkleHashToHex(merkleHash: MerkleHash): String =
|
||||
merkleHash.map("%02x".format(_)).mkString
|
||||
|
||||
def twoLevelMerkleListToString(list: List[List[MerkleHash]]): String =
|
||||
list.map(level => level.map(MerkleUtil.merkleHashToHex).mkString(" ")).mkString(", ")
|
||||
}
|
||||
|
@ -5,6 +5,15 @@ import kvstore.MerkleUtil._
|
||||
import scala.collection.immutable.HashMap
|
||||
import scala.util.Try
|
||||
|
||||
/**
|
||||
* Node
|
||||
*
|
||||
* merkleHash set to None when branch changed. Later None merkle hashes recalculated when [[Node.merkelize]] invoked
|
||||
*
|
||||
* @param children child nodes
|
||||
* @param value assigned value, if exists
|
||||
* @param merkleHash Merkle hash of a node's subtree, if calculated
|
||||
*/
|
||||
case class Node(children: NodeStorage, value: Option[String], merkleHash: Option[MerkleHash]) {
|
||||
def merkelize(): Node =
|
||||
if (merkleHash.isDefined)
|
||||
@ -34,6 +43,9 @@ case class Node(children: NodeStorage, value: Option[String], merkleHash: Option
|
||||
|
||||
key match {
|
||||
case rangeKeyValuePattern(rangeStartStr, rangeEndStr, keyPattern) =>
|
||||
// range pattern allows to set multiple keys in single transaction
|
||||
// range defined by starting and ending index, key pattern may contains hexadecimal digits of current index
|
||||
|
||||
val rangeStart = rangeStartStr.toInt
|
||||
val rangeEnd = rangeEndStr.toInt
|
||||
System.out.println(s"setting range from=$rangeStart to=$rangeEnd keyPattern=$keyPattern valuePattern=$value")
|
||||
|
25
tmdemoapp/src/main/scala/kvstore/ServerRunner.scala
Normal file
25
tmdemoapp/src/main/scala/kvstore/ServerRunner.scala
Normal file
@ -0,0 +1,25 @@
|
||||
package kvstore
|
||||
|
||||
import com.github.jtendermint.jabci.socket.TSocket
|
||||
|
||||
object ServerRunner {
|
||||
|
||||
def main(args: Array[String]): Unit = {
|
||||
val port = if (args.length > 0) args(0).toInt else 46658
|
||||
ServerRunner.start(port)
|
||||
}
|
||||
|
||||
def start(port: Int): Unit = {
|
||||
System.out.println("starting KVStore")
|
||||
val socket = new TSocket
|
||||
|
||||
socket.registerListener(ABCIHandler)
|
||||
|
||||
val t = new Thread(() => socket.start(port))
|
||||
t.setName("KVStore server Main Thread")
|
||||
t.start()
|
||||
while (true) {
|
||||
Thread.sleep(1000L)
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user