diff --git a/build.sbt b/build.sbt
index ad6e95a3..74ee7983 100644
--- a/build.sbt
+++ b/build.sbt
@@ -60,6 +60,9 @@ libraryDependencies ++= Seq(
"com.typesafe.akka" %% "akka-http" % akkaHttpVersion,
"com.typesafe.akka" %% "akka-http-spray-json" % akkaHttpVersion,
"de.heikoseeberger" % "akka-http-json4s_2.11" % "1.16.1",
+ "org.json4s" %% "json4s-native" % "3.5.4",
+ "org.json4s" %% "json4s-jackson" % "3.5.4",
+
"ch.megard" %% "akka-http-cors" % "0.2.2"
)
diff --git a/conf/system.conf b/conf/system.conf
index e2e27bf7..d2df08bc 100644
--- a/conf/system.conf
+++ b/conf/system.conf
@@ -77,11 +77,11 @@ system {
statistic_enable = 0 // 0,unable;able
httpServicePort = 8081//http服务的端口号,默认为8081
-
+
checkCertValidate = 0//设置是否检查证书的有效性,默认为0 0=不校验,1=校验
contractOperationMode = 0//设置合约的运行方式,0=debug方式,1=deploy,默认为debug方式,如果发布部署,必须使用deploy方式。
-
+
block {
//块内交易的最大数量
trans_num_limit = 50
diff --git a/jks/mykeystore_5.jks b/jks/mykeystore_5.jks
new file mode 100644
index 00000000..48a17d29
Binary files /dev/null and b/jks/mykeystore_5.jks differ
diff --git a/scripts/api_req/assets5.xml b/scripts/api_req/assets5.xml
new file mode 100644
index 00000000..3ed67b0c
--- /dev/null
+++ b/scripts/api_req/assets5.xml
@@ -0,0 +1,203 @@
+
+
+
+
+ 1
+
+
+
+
+
+ 0
+ string
+
+
+ val sp0 = ctx.api.getVal(sid)
+ val sp = read[IPTSignShare](ctx.api.getVal(sid).asInstanceOf[String])
+ splitShare(data.amount, sp.account_remain, sp.tpl_param)
+ case TPL.Fixed =>
+ val sp = read[IPTSignFixed](ctx.api.getVal(sid).asInstanceOf[String])
+ splitFixedRatio(data.amount, sp.account_remain, sp.ratio)
+ }
+ //返回分账计算结果
+ addToAccount(ctx, mr)
+ mr
+ }
+
+ /**
+ * 将分账结果增加到账户并持久化
+ */
+ def addToAccount(ctx: ContractContext, mr:Map[String,Int]){
+ for ((k, v) <- mr) {
+ val sk = ctx.api.getVal(k)
+ var dk = if(sk==null) 0 else sk.toString.toInt
+ ctx.api.setVal(k, dk+v)
+ }
+ }
+ /**
+ * 合约方法入口
+ */
+ def onAction(ctx: ContractContext,action:String, sdata:String ):Object={
+ val json = parse(sdata)
+
+ action match {
+ case ACTION.SignShare =>
+ signShare(ctx,json.extract[IPTSignShare])
+ case ACTION.SignFixed =>
+ signFixed(ctx,json.extract[IPTSignFixed])
+ case ACTION.Split =>
+ split(ctx, json.extract[IPTSplit])
+ case ACTION.ConfirmSign =>
+ confirmSign(ctx,json.extract[IPTConfirm])
+ case ACTION.CancelSign =>
+ cancelSign(ctx, json.extract[IPTConfirm])
+ }
+ }
+ //TODO case Transaction.Type.CHAINCODE_DESC 增加对合约描述的处理
+ def descAction(ctx: ContractContext,action:String, sdata:String ):String={
+ val json = parse(sdata)
+ null
+ }
+
+/**
+ * 内部函数, 获得分阶段的分成
+ */
+ def getShare(sr: Int, ar: Array[ShareRatio]) : Int={
+ var rv = 0
+ for(el <- ar) {
+ //击中金额范围
+ if(sr > el.from && sr <= el.to) {
+ //固定金额
+ if(el.fixed > 0)
+ rv = el.fixed
+ else //按比例分成
+ rv = (sr * el.ratio) .toInt
+ }
+ }
+ rv
+ }
+/**
+ * 合约中内置多种分账模版,签约时可选择模版,如果出现新的分账模版,则部署一版新的合约
+ * 分成模型, 除了销售方之外, 其他各方要求一个最低金额,分成按照金额阶段有所不同。
+ */
+ def splitShare(sr: Int, account_remain:String, rule: ShareMap): Map[String,Int] ={
+ //分账结果
+ val rm : Map[String, Int] = Map()
+ //分账余额
+ var remain = sr
+ for ((k, v) <- rule) {
+ val rv = getShare(sr, v)
+ rm += (k -> rv)
+ remain -= rv
+ }
+ rm += (account_remain -> remain)
+ }
+
+
+/**
+ * 各方固定比例分成,此模版仅仅为了合约对多模版的支持,可能无实际用途
+ */
+ def splitFixedRatio(sr: Int, account_remain: String, mr:FixedMap): Map[String,Int] ={
+ val rm : Map[String, Int] = Map()
+ var remain = sr
+ //根据固定分成
+ for ((k, v) <- mr) {
+ val rv = (sr* v ).toInt
+ rm += (k -> rv)
+ remain -= rv
+ }
+ //剩余的分给指定的余额账户
+ rm += (account_remain -> remain)
+ }
+}
+
+]]>
+
+ 1
+
\ No newline at end of file
diff --git a/scripts/example_deploy.js b/scripts/example_deploy.js
index 64f2464f..8d331581 100644
--- a/scripts/example_deploy.js
+++ b/scripts/example_deploy.js
@@ -1,67 +1,67 @@
-/*
- * Copyright 2018 Blockchain Technology and Application Joint Lab, Fintech Research Center of ISCAS.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BA SIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-function loadCert(cert){
- shim.loadCert(cert);
- print("cert:"+cert);
-}
-function write(pn,pv){
- shim.setVal(pn,pv);
- // print("setState:"+pn+":"+pv)
-}
-function set(pm){
- for(x in pm){
- write(x,pm[x]);
- }
-}
-function read(pn){
- return shim.getVal(pn);
-}
-function transfer(afrom,ato,amount){
- // print('tx_account:'+tx_account);
- if(afrom != tx_account)
- throw "["+tx_account+"]无权从["+afrom+"]转出资产"
- var rfrom = read(afrom);
- // print(rfrom + ":" + amount)
- if(rfrom
- println(s"transfer oook")
- transfer(ctx,json.extract[Transfer])
- case "set" =>
- println(s"set")
- set(ctx, json.extract[Map[String,Int]])
- case "put_proof" =>
- println(s"put_proof")
- put_proof(ctx, json.extract[Proof])
- case "signup" =>
- println(s"signup")
- null
- case "destroyCert" =>
- println(s"destroyCert")
- null
- case "replaceCert" =>
- println(s"replaceCert")
- null
- }
- }
-
-}
+
+import org.json4s._
+import org.json4s.jackson.JsonMethods._
+import rep.sc.contract._
+import rep.storage.FakeStorage.Key
+
+/**
+ * 资产管理合约
+ */
+
+class NewContract extends IContract{
+ case class Transfer(from:String, to:String, amount:Int)
+ case class Proof(key:String, content:String)
+ case class ReplaceCert(cert:String, addr:String)
+ case class Cert(cert:String, info:String)
+
+ implicit val formats = DefaultFormats
+
+ def init(ctx: ContractContext){
+ println(s"tid: $ctx.t.txid")
+ }
+
+ def set(ctx: ContractContext, data:Map[String,Int]):Object={
+ println(s"set data:$data")
+ for((k,v)<-data){
+ ctx.api.setVal(k, v)
+ }
+ null
+ }
+
+
+ def read(ctx: ContractContext, key: String):Any={
+ ctx.api.getVal(key)
+ }
+
+ def loadCert(ctx: ContractContext){
+
+ }
+
+ def write(ctx: ContractContext){
+
+ }
+
+// def put_proof(ctx: ContractContext, data:Proof):Object={
+// //先检查该hash是否已经存在,如果已存在,抛异常
+// val pn = data.key
+// val pv = data.content
+// var pv0 = ctx.api.getVal(pn)
+// if(pv0 != null)
+// throw new Exception("["+pn+"]已存在,当前值["+pv0+"]");
+// ctx.api.setVal(pn,pv);
+// print("putProof:"+pn+":"+pv);
+// "put_proof ok"
+// }
+
+ def put_proof(ctx: ContractContext, data:Map[String,Any]):Object={
+ //先检查该hash是否已经存在,如果已存在,抛异常
+ for((k,v)<-data){
+ var pv0 = ctx.api.getVal(k)
+ if(pv0 != null)
+ throw new Exception("["+k+"]已存在,当前值["+pv0+"]");
+ ctx.api.setVal(k,v);
+ print("putProof:"+k+":"+v);
+ }
+
+ "put_proof ok"
+ }
+
+
+
+ def signup(ctx: ContractContext, data: Cert):Object = {
+ val cert = data.cert
+ val info = data.info
+ ctx.api.check(ctx.t.cert.toStringUtf8,ctx.t)
+ ctx.api.signup(cert,info)
+ }
+
+ def destroyCert(ctx: ContractContext, certAddr: String): Object = {
+ ctx.api.check(ctx.t.cert.toStringUtf8,ctx.t) //ctx中自带交易内容
+ ctx.api.destroyCert(certAddr);
+ "destory scuccess"
+ }
+
+ def replaceCert(ctx: ContractContext, data:ReplaceCert): Object = {
+ val cert = data.cert
+ val addr = data.addr
+ ctx.api.check(ctx.t.cert.toStringUtf8,ctx.t)
+ ctx.api.replaceCert(cert,addr); // 返回短地址
+ }
+
+ def transfer(ctx: ContractContext, data:Transfer):Object={
+ val sfrom = ctx.api.getVal(data.from)
+ var dfrom =sfrom.toString.toInt
+ if(dfrom < data.amount)
+ throw new Exception("余额不足")
+ var dto = ctx.api.getVal(data.to).toString.toInt
+ //if(dto==null) dto = 0;
+
+ ctx.api.setVal(data.from,dfrom - data.amount)
+ ctx.api.setVal(data.to,dto + data.amount)
+ "transfer ok"
+ }
+
+ /**
+ * 根据action,找到对应的method,并将传入的json字符串parse为method需要的传入参数
+ */
+ def onAction(ctx: ContractContext,action:String, sdata:String ):Object={
+ //println(s"onAction---")
+ //return "transfer ok"
+ val json = parse(sdata)
+
+ action match {
+ case "transfer" =>
+ println(s"transfer oook")
+ transfer(ctx,json.extract[Transfer])
+ case "set" =>
+ println(s"set")
+ set(ctx, json.extract[Map[String,Int]])
+ case "put_proof" =>
+ println(s"put_proof")
+ put_proof(ctx, json.extract[Proof])
+ case "signup" =>
+ println(s"signup")
+ null
+ case "destroyCert" =>
+ println(s"destroyCert")
+ null
+ case "replaceCert" =>
+ println(s"replaceCert")
+ null
+ }
+ }
+
+}
diff --git a/src/main/scala/NewContract.scala b/src/main/scala/NewContract.scala
index 7e4bf247..309d5251 100644
--- a/src/main/scala/NewContract.scala
+++ b/src/main/scala/NewContract.scala
@@ -42,10 +42,9 @@ class NewContract extends IContract{
}
null
}
-
-
- def read(ctx: ContractContext, key: String):Any={
- ctx.api.getVal(key)
+
+ def read(ctx: ContractContext, key: String):Object={
+ ctx.api.getVal(key).toString
}
def loadCert(ctx: ContractContext, cert: String): Unit = {
@@ -137,6 +136,9 @@ class NewContract extends IContract{
case "replaceCert" =>
println(s"replaceCert")
replaceCert(ctx, json.extract[ReplaceCert])
+ case "read"=>
+ println(s"read")
+ read(ctx, json.extract[String])
}
}
diff --git a/src/main/scala/rep/api/SwaggerDocService.scala b/src/main/scala/rep/api/SwaggerDocService.scala
index 65d85a1a..10571359 100644
--- a/src/main/scala/rep/api/SwaggerDocService.scala
+++ b/src/main/scala/rep/api/SwaggerDocService.scala
@@ -1,44 +1,44 @@
-/*
- * Copyright 2018 Blockchain Technology and Application Joint Lab, Fintech Research Center of ISCAS.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BA SIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package rep.api
-
-import scala.reflect.runtime.{universe=>ru}
-import akka.actor.ActorSystem
-import akka.stream.ActorMaterializer
-import com.github.swagger.akka._
-import com.github.swagger.akka.model.`package`.Info
-import rep.api.rest._
-import io.swagger.models.ExternalDocs
-import io.swagger.models.auth.BasicAuthDefinition
-import rep.app.conf.SystemProfile
-
-/**集成Swagger到AKKA HTTP
- * @author c4w
- * @constructor 创建提供Swagger文档服务的实例
- * @param system 传入的AKKA系统实例
- *
- */
-class SwaggerDocService(system: ActorSystem) extends SwaggerHttpService with HasActorSystem {
- override implicit val actorSystem: ActorSystem = system
- override implicit val materializer: ActorMaterializer = ActorMaterializer()
- override val apiTypes = Seq(
- ru.typeOf[ChainService],
- ru.typeOf[BlockService],ru.typeOf[TransactionService],
- ru.typeOf[CertService], ru.typeOf[HashVerifyService])
- override val info = Info(version = "0.7")
- override val externalDocs = Some(new ExternalDocs("Developers Guide", "https://repchaindoc.readthedocs.io/zh/latest/index.html"))
- override val securitySchemeDefinitions = Map("basicAuth" -> new BasicAuthDefinition())
+/*
+ * Copyright 2018 Blockchain Technology and Application Joint Lab, Fintech Research Center of ISCAS.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BA SIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package rep.api
+
+import scala.reflect.runtime.{universe=>ru}
+import akka.actor.ActorSystem
+import akka.stream.ActorMaterializer
+import com.github.swagger.akka._
+import com.github.swagger.akka.model.`package`.Info
+import rep.api.rest._
+import io.swagger.models.ExternalDocs
+import io.swagger.models.auth.BasicAuthDefinition
+import rep.app.conf.SystemProfile
+
+/**集成Swagger到AKKA HTTP
+ * @author c4w
+ * @constructor 创建提供Swagger文档服务的实例
+ * @param system 传入的AKKA系统实例
+ *
+ */
+class SwaggerDocService(system: ActorSystem) extends SwaggerHttpService with HasActorSystem {
+ override implicit val actorSystem: ActorSystem = system
+ override implicit val materializer: ActorMaterializer = ActorMaterializer()
+ override val apiTypes = Seq(
+ ru.typeOf[ChainService],
+ ru.typeOf[BlockService],ru.typeOf[TransactionService],
+ ru.typeOf[CertService], ru.typeOf[HashVerifyService])
+ override val info = Info(version = "0.7")
+ override val externalDocs = Some(new ExternalDocs("Developers Guide", "https://repchaindoc.readthedocs.io/zh/latest/index.html"))
+ override val securitySchemeDefinitions = Map("basicAuth" -> new BasicAuthDefinition())
}
\ No newline at end of file
diff --git a/src/main/scala/rep/api/rest/RestActor.scala b/src/main/scala/rep/api/rest/RestActor.scala
index 4d89502f..67e3303f 100644
--- a/src/main/scala/rep/api/rest/RestActor.scala
+++ b/src/main/scala/rep/api/rest/RestActor.scala
@@ -178,10 +178,8 @@ class RestActor extends Actor with ModuleHelper with RepLogging {
val sig = txr.signature.toByteArray
val tOutSig1 = txr.withSignature(ByteString.EMPTY)
val tOutSig = tOutSig1.withMetadata(ByteString.EMPTY)
-
val cid = ChaincodeID.fromAscii(txr.chaincodeID.toStringUtf8).name
val certKey = WorldStateKeyPreFix + cid + "_" + PRE_CERT + txr.cert.toStringUtf8
-
try{
var cert = ECDSASign.getCertWithCheck(txr.cert.toStringUtf8,certKey,pe.getSysTag)
if(cert != None){
@@ -231,9 +229,9 @@ class RestActor extends Actor with ModuleHelper with RepLogging {
val future = sandbox ? PreTransaction(t)
val result = Await.result(future, timeout.duration).asInstanceOf[DoTransactionResult]
val rv = result
-
+
ImpDataPreloadMgr.Free(pe.getDBTag,t.txid)
-
+
rv.err match {
case None =>
//预执行正常,提交并广播交易
diff --git a/src/main/scala/rep/api/rest/RestService.scala b/src/main/scala/rep/api/rest/RestService.scala
index 7223427e..b27c4615 100644
--- a/src/main/scala/rep/api/rest/RestService.scala
+++ b/src/main/scala/rep/api/rest/RestService.scala
@@ -1,296 +1,296 @@
-/*
- * Copyright 2018 Blockchain Technology and Application Joint Lab, Fintech Research Center of ISCAS.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BA SIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package rep.api.rest
-
-import scala.concurrent.{ ExecutionContext, Future }
-import akka.actor.{ ActorRef, ActorSelection }
-import akka.util.Timeout
-import akka.http.scaladsl.model.Uri.Path.Segment
-import akka.http.scaladsl.server.Directives
-import io.swagger.annotations._
-import javax.ws.rs.Path
-import akka.http.scaladsl.model._
-import akka.http.scaladsl.server._
-import StatusCodes._
-import Directives._
-import rep.sc.Sandbox.SandboxException
-import rep.sc.Sandbox._
-import rep.sc.Shim._
-
-import de.heikoseeberger.akkahttpjson4s.Json4sSupport
-import rep.protos.peer._
-import rep.api.rest.RestActor._
-import spray.json.DefaultJsonProtocol._
-import org.json4s.{ DefaultFormats, Formats, jackson }
-
-import akka.http.scaladsl.server.Directives
-import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport
-import spray.json._
-
-
-import akka.http.scaladsl.marshallers.xml.ScalaXmlSupport
-import akka.http.scaladsl.model.{ContentTypes, HttpCharsets, MediaTypes}
-import akka.http.scaladsl.unmarshalling.{FromEntityUnmarshaller, Unmarshaller}
-
-import scala.xml.NodeSeq
-
-
-/** 获得区块链的概要信息
- * @author c4w
- */
-
-@Api(value = "/chaininfo", description = "获得当前区块链信息", produces = "application/json")
-@Path("chaininfo")
-class ChainService(ra: ActorRef)(implicit executionContext: ExecutionContext)
- extends Directives {
-
- import akka.pattern.ask
- import scala.concurrent.duration._
-
- import Json4sSupport._
- implicit val serialization = jackson.Serialization // or native.Serialization
- implicit val formats = DefaultFormats
- implicit val timeout = Timeout(20.seconds)
-
- val route = getBlockChainInfo
-
- @ApiOperation(value = "返回块链信息", notes = "", nickname = "getChainInfo", httpMethod = "GET")
- @ApiResponses(Array(
- new ApiResponse(code = 200, message = "返回块链信息", response = classOf[QueryResult])))
- def getBlockChainInfo =
- path("chaininfo") {
- get {
- complete { (ra ? ChainInfo).mapTo[QueryResult] }
- }
- }
-}
-
-/** 获得指定区块的详细信息
- * @author c4w
- */
-
-@Api(value = "/block", description = "获得区块数据", produces = "application/json")
-@Path("block")
-class BlockService(ra: ActorRef)(implicit executionContext: ExecutionContext)
- extends Directives {
- import akka.pattern.ask
- import scala.concurrent.duration._
-
- implicit val timeout = Timeout(20.seconds)
- import Json4sSupport._
- implicit val serialization = jackson.Serialization // or native.Serialization
- implicit val formats = DefaultFormats
-
- val route = getBlockById ~ getBlockByHeight
-
- @Path("/hash/{blockId}")
- @ApiOperation(value = "返回指定id的区块", notes = "", nickname = "getBlockById", httpMethod = "GET")
- @ApiImplicitParams(Array(
- new ApiImplicitParam(name = "blockId", value = "区块id", required = true, dataType = "string", paramType = "path")))
- @ApiResponses(Array(
- new ApiResponse(code = 200, message = "返回区块json内容", response = classOf[QueryResult])))
- def getBlockById =
- path("block" / "hash" / Segment) { blockId =>
- get {
- complete { (ra ? BlockId(blockId)).mapTo[QueryResult] }
- }
- }
-
- @Path("/{blockHeight}")
- @ApiOperation(value = "返回指定高度的区块", notes = "", nickname = "getBlockByHeight", httpMethod = "GET")
- @ApiImplicitParams(Array(
- new ApiImplicitParam(name = "blockHeight", value = "区块高度", required = true, dataType = "int", paramType = "path")))
- @ApiResponses(Array(
- new ApiResponse(code = 200, message = "返回区块json内容", response = classOf[QueryResult])))
- def getBlockByHeight =
- path("block" / Segment) { blockHeight =>
- get {
- complete { (ra ? BlockHeight(blockHeight.toInt)).mapTo[QueryResult] }
- }
- }
-
-}
-
-/** 获得指定交易的详细信息,提交签名交易
- * @author c4w
- */
-
-@Api(value = "/transaction", description = "获得交易数据", consumes = "application/json,application/xml", produces = "application/json,application/xml")
-@Path("transaction")
-class TransactionService(ra: ActorRef)(implicit executionContext: ExecutionContext)
- extends Directives {
-
- import akka.pattern.ask
- import scala.concurrent.duration._
-
- implicit val timeout = Timeout(20.seconds)
- import Json4sSupport._
- import ScalaXmlSupport._
-
- implicit val serialization = jackson.Serialization // or native.Serialization
- implicit val formats = DefaultFormats
-
- implicit val specFormat = jsonFormat9(CSpec)
- implicit val specUnmarshaller: FromEntityUnmarshaller[CSpec] = Unmarshaller.firstOf(
- //只能处理application/xml
- nodeSeqUnmarshaller(MediaTypes.`application/xml` withCharset HttpCharsets.`UTF-8`) map {
- case NodeSeq.Empty =>
- throw Unmarshaller.NoContentException
- case x =>
- CSpec(
- (x \ "stype").text.toInt,
- (x \ "idPath").text,
- Some((x \ "idName").text),
- (x \ "iptFunc").text,
- Seq((x \ "iptArgs").text),
- (x \ "timeout").text.toInt,
- (x \ "secureContext").text,
- (x \ "code").text,
- (x \ "ctype").text.toInt
- )
- },
- //只能处理application/json
- unmarshaller[CSpec].forContentTypes(MediaTypes.`application/json`)
- )
-
- val route = getTransaction ~ postSignTransaction ~ postTransaction
-
- @Path("/{transactionId}")
- @ApiOperation(value = "返回指定id的交易", notes = "", nickname = "getTransaction", httpMethod = "GET")
- @ApiImplicitParams(Array(
- new ApiImplicitParam(name = "transactionId", value = "交易id", required = false, dataType = "string", paramType = "path")))
- @ApiResponses(Array(
- new ApiResponse(code = 200, message = "返回交易json内容", response = classOf[QueryResult])))
- def getTransaction =
- path("transaction" / Segment) { transactionId =>
- get {
- complete { (ra ? TransactionId(transactionId)).mapTo[QueryResult] }
- }
- }
-//以十六进制字符串提交签名交易
- @Path("/postTranByString")
- @ApiOperation(value = "提交带签名的交易", notes = "", nickname = "postSignTransaction", httpMethod = "POST")
- @ApiImplicitParams(Array(
- new ApiImplicitParam(name = "body", value = "交易内容", required = true, dataType = "string", paramType = "body")))
- @ApiResponses(Array(
- new ApiResponse(code = 200, message = "返回交易id以及执行结果", response = classOf[PostResult]),
- new ApiResponse(code = 202, message = "处理存在异常", response = classOf[PostResult])))
- def postSignTransaction =
- path("transaction" / "postTranByString") {
- post {
- entity(as[String]) { trans =>
- //str=>
- //complete(OK, trans)
- complete { (ra ? tranSign(trans)).mapTo[PostResult] }
- }
- }
- }
-
- @Path("/postTran")
- @ApiOperation(value = "提交交易", notes = "", nickname = "postTransaction", httpMethod = "POST")
- @ApiImplicitParams(Array(
- new ApiImplicitParam(name = "body", value = "交易内容", required = true,
- dataTypeClass = classOf[CSpec], paramType = "body")))
- @ApiResponses(Array(
- new ApiResponse(code = 200, message = "返回交易id以及执行结果", response = classOf[PostResult]),
- new ApiResponse(code = 202, message = "处理存在异常", response = classOf[PostResult])))
- def postTransaction =
- path("transaction" / "postTran") {
- post {
- import akka.http.scaladsl.marshallers.xml.ScalaXmlSupport._
- entity(as[CSpec]) { request =>
- complete { (ra ? request).mapTo[PostResult] }
- }
- }
- }
- }
-
-@Api(value = "/certAddr", description = "获得证书短地址", produces = "application/json")
-@Path("certAddr")
-class CertService(ra: ActorRef)(implicit executionContext: ExecutionContext)
- extends Directives {
-
- import akka.pattern.ask
- import scala.concurrent.duration._
-
- import Json4sSupport._
- implicit val serialization = jackson.Serialization // or native.Serialization
- implicit val formats = DefaultFormats
- implicit val timeout = Timeout(20.seconds)
-
- val route = getAddrByCert ~ getCertByAddr
-
- @Path("/getAddrByCert")
- @ApiOperation(value = "返回证书短地址", notes = "", nickname = "getAddrByCert", httpMethod = "POST")
- @ApiImplicitParams(Array(
- new ApiImplicitParam(name = "body", value = "证书", required = true, dataTypeClass = classOf[PostCert], paramType = "body")))
- @ApiResponses(Array(
- new ApiResponse(code = 200, message = "查询证书短地址", response = classOf[QueryAddr])))
- def getAddrByCert =
- path("certAddr" / "getAddrByCert") {
- post {
- entity(as[PostCert]) { PostCert =>
- complete { (ra ? PostCert).mapTo[QueryAddr] }
- }
- }
- }
-
- @Path("/getCertByAddr")
- @ApiOperation(value = "返回证书字符串", notes = "", nickname = "getCertByAddr", httpMethod = "POST")
- @ApiImplicitParams(Array(
- new ApiImplicitParam(name = "body", value = "短地址", required = true, dataTypeClass = classOf[PostAddr], paramType = "body")))
- @ApiResponses(Array(
- new ApiResponse(code = 200, message = "查询证书字符串", response = classOf[QueryCert])))
- def getCertByAddr =
- path("certAddr" / "getCertByAddr") {
- post {
- entity(as[PostAddr]) { PostAddr =>
- complete { (ra ? PostAddr).mapTo[QueryCert] }
- }
- }
- }
- }
-
-
-@Api(value = "/hash", description = "验证hash是否存在", produces = "application/json")
-@Path("hash")
-class HashVerifyService(ra: ActorRef)(implicit executionContext: ExecutionContext)
- extends Directives {
-
- import akka.pattern.ask
- import scala.concurrent.duration._
-
- import Json4sSupport._
- implicit val serialization = jackson.Serialization // or native.Serialization
- implicit val formats = DefaultFormats
- implicit val timeout = Timeout(20.seconds)
-
- val route = verifyImageHash
-
- @Path("/verifyHash")
- @ApiOperation(value = "返回hash是否存在", notes = "", nickname = "verifyHash", httpMethod = "POST")
- @ApiImplicitParams(Array(
- new ApiImplicitParam(name = "body", value = "hash值与cid", required = true, dataTypeClass = classOf[PostHash], paramType = "body")))
- @ApiResponses(Array(new ApiResponse(code = 200, message = "验证hash值", response = classOf[QueryHash])))
- def verifyImageHash =
- path("hash" / "verifyHash") {
- post {
- entity(as[PostHash]) { PostHash =>
- complete { (ra ? PostHash).mapTo[QueryHash] }
- }
- }
- }
+/*
+ * Copyright 2018 Blockchain Technology and Application Joint Lab, Fintech Research Center of ISCAS.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BA SIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package rep.api.rest
+
+import scala.concurrent.{ ExecutionContext, Future }
+import akka.actor.{ ActorRef, ActorSelection }
+import akka.util.Timeout
+import akka.http.scaladsl.model.Uri.Path.Segment
+import akka.http.scaladsl.server.Directives
+import io.swagger.annotations._
+import javax.ws.rs.Path
+import akka.http.scaladsl.model._
+import akka.http.scaladsl.server._
+import StatusCodes._
+import Directives._
+import rep.sc.Sandbox.SandboxException
+import rep.sc.Sandbox._
+import rep.sc.Shim._
+
+import de.heikoseeberger.akkahttpjson4s.Json4sSupport
+import rep.protos.peer._
+import rep.api.rest.RestActor._
+import spray.json.DefaultJsonProtocol._
+import org.json4s.{ DefaultFormats, Formats, jackson }
+
+import akka.http.scaladsl.server.Directives
+import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport
+import spray.json._
+
+
+import akka.http.scaladsl.marshallers.xml.ScalaXmlSupport
+import akka.http.scaladsl.model.{ContentTypes, HttpCharsets, MediaTypes}
+import akka.http.scaladsl.unmarshalling.{FromEntityUnmarshaller, Unmarshaller}
+
+import scala.xml.NodeSeq
+
+
+/** 获得区块链的概要信息
+ * @author c4w
+ */
+
+@Api(value = "/chaininfo", description = "获得当前区块链信息", produces = "application/json")
+@Path("chaininfo")
+class ChainService(ra: ActorRef)(implicit executionContext: ExecutionContext)
+ extends Directives {
+
+ import akka.pattern.ask
+ import scala.concurrent.duration._
+
+ import Json4sSupport._
+ implicit val serialization = jackson.Serialization // or native.Serialization
+ implicit val formats = DefaultFormats
+ implicit val timeout = Timeout(20.seconds)
+
+ val route = getBlockChainInfo
+
+ @ApiOperation(value = "返回块链信息", notes = "", nickname = "getChainInfo", httpMethod = "GET")
+ @ApiResponses(Array(
+ new ApiResponse(code = 200, message = "返回块链信息", response = classOf[QueryResult])))
+ def getBlockChainInfo =
+ path("chaininfo") {
+ get {
+ complete { (ra ? ChainInfo).mapTo[QueryResult] }
+ }
+ }
+}
+
+/** 获得指定区块的详细信息
+ * @author c4w
+ */
+
+@Api(value = "/block", description = "获得区块数据", produces = "application/json")
+@Path("block")
+class BlockService(ra: ActorRef)(implicit executionContext: ExecutionContext)
+ extends Directives {
+ import akka.pattern.ask
+ import scala.concurrent.duration._
+
+ implicit val timeout = Timeout(20.seconds)
+ import Json4sSupport._
+ implicit val serialization = jackson.Serialization // or native.Serialization
+ implicit val formats = DefaultFormats
+
+ val route = getBlockById ~ getBlockByHeight
+
+ @Path("/hash/{blockId}")
+ @ApiOperation(value = "返回指定id的区块", notes = "", nickname = "getBlockById", httpMethod = "GET")
+ @ApiImplicitParams(Array(
+ new ApiImplicitParam(name = "blockId", value = "区块id", required = true, dataType = "string", paramType = "path")))
+ @ApiResponses(Array(
+ new ApiResponse(code = 200, message = "返回区块json内容", response = classOf[QueryResult])))
+ def getBlockById =
+ path("block" / "hash" / Segment) { blockId =>
+ get {
+ complete { (ra ? BlockId(blockId)).mapTo[QueryResult] }
+ }
+ }
+
+ @Path("/{blockHeight}")
+ @ApiOperation(value = "返回指定高度的区块", notes = "", nickname = "getBlockByHeight", httpMethod = "GET")
+ @ApiImplicitParams(Array(
+ new ApiImplicitParam(name = "blockHeight", value = "区块高度", required = true, dataType = "int", paramType = "path")))
+ @ApiResponses(Array(
+ new ApiResponse(code = 200, message = "返回区块json内容", response = classOf[QueryResult])))
+ def getBlockByHeight =
+ path("block" / Segment) { blockHeight =>
+ get {
+ complete { (ra ? BlockHeight(blockHeight.toInt)).mapTo[QueryResult] }
+ }
+ }
+
+}
+
+/** 获得指定交易的详细信息,提交签名交易
+ * @author c4w
+ */
+
+@Api(value = "/transaction", description = "获得交易数据", consumes = "application/json,application/xml", produces = "application/json,application/xml")
+@Path("transaction")
+class TransactionService(ra: ActorRef)(implicit executionContext: ExecutionContext)
+ extends Directives {
+
+ import akka.pattern.ask
+ import scala.concurrent.duration._
+
+ implicit val timeout = Timeout(20.seconds)
+ import Json4sSupport._
+ import ScalaXmlSupport._
+
+ implicit val serialization = jackson.Serialization // or native.Serialization
+ implicit val formats = DefaultFormats
+
+ implicit val specFormat = jsonFormat9(CSpec)
+ implicit val specUnmarshaller: FromEntityUnmarshaller[CSpec] = Unmarshaller.firstOf(
+ //只能处理application/xml
+ nodeSeqUnmarshaller(MediaTypes.`application/xml` withCharset HttpCharsets.`UTF-8`) map {
+ case NodeSeq.Empty =>
+ throw Unmarshaller.NoContentException
+ case x =>
+ CSpec(
+ (x \ "stype").text.toInt,
+ (x \ "idPath").text,
+ Some((x \ "idName").text),
+ (x \ "iptFunc").text,
+ Seq((x \ "iptArgs").text),
+ (x \ "timeout").text.toInt,
+ (x \ "secureContext").text,
+ (x \ "code").text,
+ (x \ "ctype").text.toInt
+ )
+ },
+ //只能处理application/json
+ unmarshaller[CSpec].forContentTypes(MediaTypes.`application/json`)
+ )
+
+ val route = getTransaction ~ postSignTransaction ~ postTransaction
+
+ @Path("/{transactionId}")
+ @ApiOperation(value = "返回指定id的交易", notes = "", nickname = "getTransaction", httpMethod = "GET")
+ @ApiImplicitParams(Array(
+ new ApiImplicitParam(name = "transactionId", value = "交易id", required = false, dataType = "string", paramType = "path")))
+ @ApiResponses(Array(
+ new ApiResponse(code = 200, message = "返回交易json内容", response = classOf[QueryResult])))
+ def getTransaction =
+ path("transaction" / Segment) { transactionId =>
+ get {
+ complete { (ra ? TransactionId(transactionId)).mapTo[QueryResult] }
+ }
+ }
+//以十六进制字符串提交签名交易
+ @Path("/postTranByString")
+ @ApiOperation(value = "提交带签名的交易", notes = "", nickname = "postSignTransaction", httpMethod = "POST")
+ @ApiImplicitParams(Array(
+ new ApiImplicitParam(name = "body", value = "交易内容", required = true, dataType = "string", paramType = "body")))
+ @ApiResponses(Array(
+ new ApiResponse(code = 200, message = "返回交易id以及执行结果", response = classOf[PostResult]),
+ new ApiResponse(code = 202, message = "处理存在异常", response = classOf[PostResult])))
+ def postSignTransaction =
+ path("transaction" / "postTranByString") {
+ post {
+ entity(as[String]) { trans =>
+ //str=>
+ //complete(OK, trans)
+ complete { (ra ? tranSign(trans)).mapTo[PostResult] }
+ }
+ }
+ }
+
+ @Path("/postTran")
+ @ApiOperation(value = "提交交易", notes = "", nickname = "postTransaction", httpMethod = "POST")
+ @ApiImplicitParams(Array(
+ new ApiImplicitParam(name = "body", value = "交易内容", required = true,
+ dataTypeClass = classOf[CSpec], paramType = "body")))
+ @ApiResponses(Array(
+ new ApiResponse(code = 200, message = "返回交易id以及执行结果", response = classOf[PostResult]),
+ new ApiResponse(code = 202, message = "处理存在异常", response = classOf[PostResult])))
+ def postTransaction =
+ path("transaction" / "postTran") {
+ post {
+ import akka.http.scaladsl.marshallers.xml.ScalaXmlSupport._
+ entity(as[CSpec]) { request =>
+ complete { (ra ? request).mapTo[PostResult] }
+ }
+ }
+ }
+ }
+
+@Api(value = "/certAddr", description = "获得证书短地址", produces = "application/json")
+@Path("certAddr")
+class CertService(ra: ActorRef)(implicit executionContext: ExecutionContext)
+ extends Directives {
+
+ import akka.pattern.ask
+ import scala.concurrent.duration._
+
+ import Json4sSupport._
+ implicit val serialization = jackson.Serialization // or native.Serialization
+ implicit val formats = DefaultFormats
+ implicit val timeout = Timeout(20.seconds)
+
+ val route = getAddrByCert ~ getCertByAddr
+
+ @Path("/getAddrByCert")
+ @ApiOperation(value = "返回证书短地址", notes = "", nickname = "getAddrByCert", httpMethod = "POST")
+ @ApiImplicitParams(Array(
+ new ApiImplicitParam(name = "body", value = "证书", required = true, dataTypeClass = classOf[PostCert], paramType = "body")))
+ @ApiResponses(Array(
+ new ApiResponse(code = 200, message = "查询证书短地址", response = classOf[QueryAddr])))
+ def getAddrByCert =
+ path("certAddr" / "getAddrByCert") {
+ post {
+ entity(as[PostCert]) { PostCert =>
+ complete { (ra ? PostCert).mapTo[QueryAddr] }
+ }
+ }
+ }
+
+ @Path("/getCertByAddr")
+ @ApiOperation(value = "返回证书字符串", notes = "", nickname = "getCertByAddr", httpMethod = "POST")
+ @ApiImplicitParams(Array(
+ new ApiImplicitParam(name = "body", value = "短地址", required = true, dataTypeClass = classOf[PostAddr], paramType = "body")))
+ @ApiResponses(Array(
+ new ApiResponse(code = 200, message = "查询证书字符串", response = classOf[QueryCert])))
+ def getCertByAddr =
+ path("certAddr" / "getCertByAddr") {
+ post {
+ entity(as[PostAddr]) { PostAddr =>
+ complete { (ra ? PostAddr).mapTo[QueryCert] }
+ }
+ }
+ }
+ }
+
+
+@Api(value = "/hash", description = "验证hash是否存在", produces = "application/json")
+@Path("hash")
+class HashVerifyService(ra: ActorRef)(implicit executionContext: ExecutionContext)
+ extends Directives {
+
+ import akka.pattern.ask
+ import scala.concurrent.duration._
+
+ import Json4sSupport._
+ implicit val serialization = jackson.Serialization // or native.Serialization
+ implicit val formats = DefaultFormats
+ implicit val timeout = Timeout(20.seconds)
+
+ val route = verifyImageHash
+
+ @Path("/verifyHash")
+ @ApiOperation(value = "返回hash是否存在", notes = "", nickname = "verifyHash", httpMethod = "POST")
+ @ApiImplicitParams(Array(
+ new ApiImplicitParam(name = "body", value = "hash值与cid", required = true, dataTypeClass = classOf[PostHash], paramType = "body")))
+ @ApiResponses(Array(new ApiResponse(code = 200, message = "验证hash值", response = classOf[QueryHash])))
+ def verifyImageHash =
+ path("hash" / "verifyHash") {
+ post {
+ entity(as[PostHash]) { PostHash =>
+ complete { (ra ? PostHash).mapTo[QueryHash] }
+ }
+ }
+ }
}
\ No newline at end of file
diff --git a/src/main/scala/rep/app/conf/SystemProfile.scala b/src/main/scala/rep/app/conf/SystemProfile.scala
index d6d634d6..c023670e 100644
--- a/src/main/scala/rep/app/conf/SystemProfile.scala
+++ b/src/main/scala/rep/app/conf/SystemProfile.scala
@@ -56,7 +56,7 @@ object SystemProfile {
private def SERVERPORT_=(value: Int): Unit = {
_SERVERPORT = value
}
-
+
private def CHECKCERTVALIDATE_=(value: Int): Unit = {
_CHECKCERTVALIDATE = value
}
diff --git a/src/main/scala/rep/crypto/ECDSASign.scala b/src/main/scala/rep/crypto/ECDSASign.scala
index 704a55a7..b2420faf 100644
--- a/src/main/scala/rep/crypto/ECDSASign.scala
+++ b/src/main/scala/rep/crypto/ECDSASign.scala
@@ -1,422 +1,422 @@
-/*
- * Copyright 2018 Blockchain Technology and Application Joint Lab, Fintech Research Center of ISCAS.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BA SIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package rep.crypto
-
-import java.security._
-import java.io._
-import java.security.cert.{ Certificate, CertificateFactory }
-import rep.app.conf.SystemProfile
-import com.google.protobuf.ByteString
-import fastparse.utils.Base64
-import rep.utils.SerializeUtils
-import rep.storage._
-import scala.collection.mutable
-import com.fasterxml.jackson.core.Base64Variants
-import java.security.cert.X509Certificate
-
-/**
- * 系统密钥相关伴生对象
- * @author shidianyue
- * @version 0.7
- */
-object ECDSASign extends ECDSASign {
- //TODO kami (现阶段alias和SYSName相同,将来不一定,所以目前在接口层将其分开,但是调用时用的是一个)
-
- //store itsself key and certification
- var keyStorePath = mutable.HashMap[String, String]()
- var password = mutable.HashMap[String, String]()
- //store the trust list of other nodes' certification
- var trustKeyStorePath = ""
- var passwordTrust = ""
-
- var keyStore = mutable.HashMap[String, KeyStore]()
- var trustKeyStore = KeyStore.getInstance(KeyStore.getDefaultType)
- var trustkeysPubAddrMap = mutable.HashMap[String, Certificate]()
-
- def apply(alias: String, jksPath: String, password: String, jksTrustPath: String, passwordTrust: String) = {
- keyStorePath(alias) = jksPath
- this.password(alias) = password
- //TODO kami 如果与之前路径不同,如何处理?
- if (trustKeyStorePath == "") {
- trustKeyStorePath = jksTrustPath
- this.passwordTrust = passwordTrust
- }
- }
-
- /**
- * 通过参数获取相关的密钥对、证书(动态加载)
- *
- * @param jks_file
- * @param password
- * @param alias
- * @return
- */
- def getKeyPairFromJKS(jks_file: File, password: String, alias: String): (PrivateKey, PublicKey) = {
- val store = KeyStore.getInstance(KeyStore.getDefaultType)
- val fis = new FileInputStream(jks_file)
- val pwd = password.toCharArray()
- store.load(fis, pwd)
- val sk = store.getKey(alias, pwd)
- val cert = store.getCertificate(alias)
- (sk.asInstanceOf[PrivateKey], cert.getPublicKey())
- }
-
- /**
- * 在信任列表中获取证书(通过alias)
- *
- * @param cert
- * @return
- */
- def getAliasByCert(cert: Certificate): Option[String] = {
- val alias = trustKeyStore.getCertificateAlias(cert)
- if (alias == null) Option.empty else Option(alias)
- }
-
- /**
- * 获取证书的Base58地址
- * @param cert
- * @return
- */
- def getAddrByCert(cert: Certificate): String = {
- Base58.encode(Sha256.hash(cert.getPublicKey.getEncoded))
- }
-
- /**
- * 获取证书的短地址(Bitcoin方法)
- * @param cert 对象
- * @return
- */
- def getBitcoinAddrByCert(cert: Certificate): String = {
- BitcoinUtils.calculateBitcoinAddress(cert.getPublicKey.getEncoded)
- }
-
- /**
- * 获取证书的短地址
- * @param certByte 字节
- * @return
- */
- def getBitcoinAddrByCert(certByte: Array[Byte]): String = {
- val cert = SerializeUtils.deserialise(certByte).asInstanceOf[Certificate]
- BitcoinUtils.calculateBitcoinAddress(cert.getPublicKey.getEncoded)
- }
-
- /**
- * 获取指定alias的证书地址
- * @param alias
- * @return
- */
- def getAddr(alias: String): String = {
- getAddrByCert(keyStore(alias).getCertificate(alias))
- }
-
- /**
- * 根据短地址获取证书
- * @param addr
- * @return
- */
- def getCertByBitcoinAddr(addr: String): Option[Certificate] = {
- var tmpcert = trustkeysPubAddrMap.get(addr)
- if(checkCertificate(new java.util.Date(), tmpcert.get)){
- tmpcert
- }else{
- throw new RuntimeException("证书已经过期")
- }
-
-
- }
-
- /**
- * 通过配置信息获取证书(动态加载)
- *
- * @param jks_file
- * @param password
- * @param alias
- * @return
- */
- def getCertFromJKS(jks_file: File, password: String, alias: String): Certificate = {
- val store = KeyStore.getInstance(KeyStore.getDefaultType)
- val fis = new FileInputStream(jks_file)
- val pwd = password.toCharArray()
- store.load(fis, pwd)
- val sk = store.getKey(alias, pwd)
- val cert = store.getCertificate(alias)
- cert
- }
-
- /**
- * 将pem格式证书字符串转换为certificate
- * @param pem
- * @return
- */
- def getCertByPem(pemcert: String): Certificate = {
- val cf = CertificateFactory.getInstance("X.509")
- val cert = cf.generateCertificate(
- new ByteArrayInputStream(
- Base64.Decoder(pemcert.replaceAll("\r\n", "").stripPrefix("-----BEGIN CERTIFICATE-----").stripSuffix("-----END CERTIFICATE-----")).toByteArray))
- cert
- }
-
-
- /**
- * 获取alias的密钥对和证书(系统初始化)
- *
- * @param alias
- * @return
- */
- def getKeyPair(alias: String): (PrivateKey, PublicKey, Array[Byte]) = {
- val sk = keyStore(alias).getKey(alias, password(alias).toCharArray)
- val cert = keyStore(alias).getCertificate(alias)
- if(checkCertificate(new java.util.Date(), cert)){
- (sk.asInstanceOf[PrivateKey], cert.getPublicKey(), SerializeUtils.serialise(cert))
- }else{
- throw new RuntimeException("证书已经过期")
- }
- }
-
- /**
- * 获取alias的证书(系统初始化)
- *
- * @param alias
- * @return
- */
- def getCert(alias: String): Certificate = {
- keyStore(alias).getCertificate(alias)
- }
-
- /**
- * 在信任列表中获取alias的证书(系统初始化)
- *
- * @param alias
- * @return
- */
- def getKeyPairTrust(alias: String): PublicKey = {
- val sk = trustKeyStore.getKey(alias, passwordTrust.toCharArray)
- val cert = trustKeyStore.getCertificate(alias)
- cert.getPublicKey()
- }
-
- /**
- * 判断两个证书是否相同
- *
- * @param alias
- * @param cert
- * @return
- */
- def isCertTrust(alias: String, cert: Array[Byte]): Boolean = {
- val sk = trustKeyStore.getKey(alias, passwordTrust.toCharArray)
- val certT = trustKeyStore.getCertificate(alias)
- //寻找方法能够恢复cert?
- certT.getEncoded.equals(cert)
- }
-
- /**
- * 预加载系统密钥对和信任证书
- *
- * @param alias
- */
- def preLoadKey(alias: String): Unit = {
- val fis = new FileInputStream(new File(keyStorePath(alias)))
- val pwd = password(alias).toCharArray()
- if (keyStore.contains(alias)) keyStore(alias).load(fis, pwd)
- else {
- val keyS = KeyStore.getInstance(KeyStore.getDefaultType)
- keyS.load(fis, pwd)
- keyStore(alias) = keyS
- }
-
- val fisT = new FileInputStream(new File(trustKeyStorePath))
- val pwdT = passwordTrust.toCharArray()
- trustKeyStore.load(fisT, pwdT)
- loadTrustkeysPubAddrMap()
- }
-
- /**
- * 初始化信任证书中对短地址和证书的映射
- */
- def loadTrustkeysPubAddrMap(): Unit = {
- val enums = trustKeyStore.aliases()
- while (enums.hasMoreElements) {
- val alias = enums.nextElement()
- val cert = trustKeyStore.getCertificate(alias)
- trustkeysPubAddrMap.put(getBitcoinAddrByCert(cert), cert)
- }
- }
-
- /**
- * 获取本地证书,得到证书类和其序列化的字节序列
- *
- * @param certPath
- * @return 字节序列(通过base58进行转化)
- */
- def loadCertByPath(certPath: String): (Certificate, Array[Byte], String) = {
- val certF = CertificateFactory.getInstance("X.509")
- val fileInputStream = new FileInputStream(certPath)
- val x509Cert = certF.generateCertificate(fileInputStream)
- val arrayCert = SerializeUtils.serialise(x509Cert)
- (x509Cert, arrayCert, Base64.Encoder(arrayCert).toBase64)
- }
-
- /**
- * 添加证书到信任列表
- *
- * @param cert 字节数组
- * @param alias
- * @return
- */
- def loadTrustedCert(cert: Array[Byte], alias: String): Boolean = {
- val certTx = SerializeUtils.deserialise(cert).asInstanceOf[Certificate]
- getAliasByCert(certTx).getOrElse(None) match {
- case None =>
- trustKeyStore.setCertificateEntry(alias, certTx)
- trustkeysPubAddrMap.put(getBitcoinAddrByCert(certTx), certTx)
- val fileOutputStream = new FileOutputStream(trustKeyStorePath)
- trustKeyStore.store(fileOutputStream, passwordTrust.toCharArray)
- true
- case _ =>
- false
- }
- }
-
- /**
- * 添加证书到信任列表
- *
- * @param cert base64字符串
- * @param alias
- * @return
- */
- def loadTrustedCertBase64(cert: String, alias: String): Boolean = {
- val certTx = SerializeUtils.deserialise(Base64.Decoder(cert).toByteArray).asInstanceOf[Certificate]
- getAliasByCert(certTx).getOrElse(None) match {
- case None =>
- trustKeyStore.setCertificateEntry(alias, certTx)
- trustkeysPubAddrMap.put(getBitcoinAddrByCert(certTx), certTx)
- val fileOutputStream = new FileOutputStream(trustKeyStorePath)
- trustKeyStore.store(fileOutputStream, passwordTrust.toCharArray)
- true
- case _ =>
- false
- }
- }
- def main(args: Array[String]): Unit = {
- println(ByteString.copyFromUtf8(ECDSASign.getBitcoinAddrByCert(ECDSASign.getCertFromJKS(new File("jks/mykeystore_1.jks"), "123", "1"))).toStringUtf8)
- println(ECDSASign.getBitcoinAddrByCert(ECDSASign.getCertFromJKS(new File("jks/mykeystore_2.jks"), "123", "2")))
- println(ECDSASign.getBitcoinAddrByCert(ECDSASign.getCertFromJKS(new File("jks/mykeystore_3.jks"), "123", "3")))
- println(ECDSASign.getBitcoinAddrByCert(ECDSASign.getCertFromJKS(new File("jks/mykeystore_4.jks"), "123", "4")))
- println(ECDSASign.getBitcoinAddrByCert(ECDSASign.getCertFromJKS(new File("jks/mykeystore_5.jks"), "123", "5")))
- }
-
-}
-
-/**
- * 系统密钥相关类
- * @author shidianyue
- * @version 0.7
- * @since 1.0
- */
-class ECDSASign extends SignFunc {
- /**
- * 签名
- *
- * @param privateKey
- * @param message
- * @return
- */
- def sign(privateKey: PrivateKey, message: Array[Byte]): Array[Byte] = {
- val s1 = Signature.getInstance("SHA1withECDSA");
- s1.initSign(privateKey)
- s1.update(message)
- s1.sign()
- }
-
- /**
- * 验证
- *
- * @param signature
- * @param message
- * @param publicKey
- * @return
- */
- def verify(signature: Array[Byte], message: Array[Byte], publicKey: PublicKey): Boolean = {
- val s2 = Signature.getInstance("SHA1withECDSA");
- s2.initVerify(publicKey)
- s2.update(message)
- s2.verify(signature)
- }
-
- def getCertWithCheck(certAddr:String,certKey:String,sysTag:String):Option[java.security.cert.Certificate]={
- val cert = ECDSASign.getCertByBitcoinAddr(certAddr)
- if(cert != None) {
- if(checkCertificate(new java.util.Date(), cert.get)){
- cert
- }else{
- throw new RuntimeException("证书已经过期")
- }
- }else{
- if(certKey == null || sysTag == null){
- throw new RuntimeException("没有证书")
- }else{
- try{
- val sr: ImpDataAccess = ImpDataAccess.GetDataAccess(sysTag)
- val cert = Option(sr.Get(certKey))
- if (cert != None){
- if (new String(cert.get) == "null") {
- throw new RuntimeException("用户证书已经注销")
- }else{
- val kvcert = SerializeUtils.deserialise(cert.get).asInstanceOf[Certificate]
- if(kvcert != null){
- if(checkCertificate(new java.util.Date(), kvcert)){
- Some(kvcert)
- }else{
- throw new RuntimeException("证书已经过期")
- }
- }else{
- throw new RuntimeException("证书内容错误")
- }
- }
- }else{
- throw new RuntimeException("没有证书")
- }
- }catch{
- case e : Exception =>throw new RuntimeException("证书获取过程中发生错误",e)
- }
- }
- }
- }
-
- def checkCertificate(date:java.util.Date, cert:Certificate):Boolean={
- var isValid :Boolean = false
- var start = System.currentTimeMillis()
- try {
- if(SystemProfile.getCheckCertValidate == 0){
- isValid = true
- }else if(SystemProfile.getCheckCertValidate == 1){
- if(cert.isInstanceOf[X509Certificate]){
- var x509cert :X509Certificate = cert.asInstanceOf[X509Certificate]
- x509cert.checkValidity(date)
- isValid = true
- }
- }else{
- isValid = true
- }
- } catch{
- case e : Exception => isValid = false
- }
- var end = System.currentTimeMillis()
- //println("check cert validate,spent time="+(end-start))
- isValid;
- }
-
+/*
+ * Copyright 2018 Blockchain Technology and Application Joint Lab, Fintech Research Center of ISCAS.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BA SIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package rep.crypto
+
+import java.security._
+import java.io._
+import java.security.cert.{ Certificate, CertificateFactory }
+import rep.app.conf.SystemProfile
+import com.google.protobuf.ByteString
+import fastparse.utils.Base64
+import rep.utils.SerializeUtils
+import rep.storage._
+import scala.collection.mutable
+import com.fasterxml.jackson.core.Base64Variants
+import java.security.cert.X509Certificate
+
+/**
+ * 系统密钥相关伴生对象
+ * @author shidianyue
+ * @version 0.7
+ */
+object ECDSASign extends ECDSASign {
+ //TODO kami (现阶段alias和SYSName相同,将来不一定,所以目前在接口层将其分开,但是调用时用的是一个)
+
+ //store itsself key and certification
+ var keyStorePath = mutable.HashMap[String, String]()
+ var password = mutable.HashMap[String, String]()
+ //store the trust list of other nodes' certification
+ var trustKeyStorePath = ""
+ var passwordTrust = ""
+
+ var keyStore = mutable.HashMap[String, KeyStore]()
+ var trustKeyStore = KeyStore.getInstance(KeyStore.getDefaultType)
+ var trustkeysPubAddrMap = mutable.HashMap[String, Certificate]()
+
+ def apply(alias: String, jksPath: String, password: String, jksTrustPath: String, passwordTrust: String) = {
+ keyStorePath(alias) = jksPath
+ this.password(alias) = password
+ //TODO kami 如果与之前路径不同,如何处理?
+ if (trustKeyStorePath == "") {
+ trustKeyStorePath = jksTrustPath
+ this.passwordTrust = passwordTrust
+ }
+ }
+
+ /**
+ * 通过参数获取相关的密钥对、证书(动态加载)
+ *
+ * @param jks_file
+ * @param password
+ * @param alias
+ * @return
+ */
+ def getKeyPairFromJKS(jks_file: File, password: String, alias: String): (PrivateKey, PublicKey) = {
+ val store = KeyStore.getInstance(KeyStore.getDefaultType)
+ val fis = new FileInputStream(jks_file)
+ val pwd = password.toCharArray()
+ store.load(fis, pwd)
+ val sk = store.getKey(alias, pwd)
+ val cert = store.getCertificate(alias)
+ (sk.asInstanceOf[PrivateKey], cert.getPublicKey())
+ }
+
+ /**
+ * 在信任列表中获取证书(通过alias)
+ *
+ * @param cert
+ * @return
+ */
+ def getAliasByCert(cert: Certificate): Option[String] = {
+ val alias = trustKeyStore.getCertificateAlias(cert)
+ if (alias == null) Option.empty else Option(alias)
+ }
+
+ /**
+ * 获取证书的Base58地址
+ * @param cert
+ * @return
+ */
+ def getAddrByCert(cert: Certificate): String = {
+ Base58.encode(Sha256.hash(cert.getPublicKey.getEncoded))
+ }
+
+ /**
+ * 获取证书的短地址(Bitcoin方法)
+ * @param cert 对象
+ * @return
+ */
+ def getBitcoinAddrByCert(cert: Certificate): String = {
+ BitcoinUtils.calculateBitcoinAddress(cert.getPublicKey.getEncoded)
+ }
+
+ /**
+ * 获取证书的短地址
+ * @param certByte 字节
+ * @return
+ */
+ def getBitcoinAddrByCert(certByte: Array[Byte]): String = {
+ val cert = SerializeUtils.deserialise(certByte).asInstanceOf[Certificate]
+ BitcoinUtils.calculateBitcoinAddress(cert.getPublicKey.getEncoded)
+ }
+
+ /**
+ * 获取指定alias的证书地址
+ * @param alias
+ * @return
+ */
+ def getAddr(alias: String): String = {
+ getAddrByCert(keyStore(alias).getCertificate(alias))
+ }
+
+ /**
+ * 根据短地址获取证书
+ * @param addr
+ * @return
+ */
+ def getCertByBitcoinAddr(addr: String): Option[Certificate] = {
+ var tmpcert = trustkeysPubAddrMap.get(addr)
+ if(checkCertificate(new java.util.Date(), tmpcert.get)){
+ tmpcert
+ }else{
+ throw new RuntimeException("证书已经过期")
+ }
+
+
+ }
+
+ /**
+ * 通过配置信息获取证书(动态加载)
+ *
+ * @param jks_file
+ * @param password
+ * @param alias
+ * @return
+ */
+ def getCertFromJKS(jks_file: File, password: String, alias: String): Certificate = {
+ val store = KeyStore.getInstance(KeyStore.getDefaultType)
+ val fis = new FileInputStream(jks_file)
+ val pwd = password.toCharArray()
+ store.load(fis, pwd)
+ val sk = store.getKey(alias, pwd)
+ val cert = store.getCertificate(alias)
+ cert
+ }
+
+ /**
+ * 将pem格式证书字符串转换为certificate
+ * @param pem
+ * @return
+ */
+ def getCertByPem(pemcert: String): Certificate = {
+ val cf = CertificateFactory.getInstance("X.509")
+ val cert = cf.generateCertificate(
+ new ByteArrayInputStream(
+ Base64.Decoder(pemcert.replaceAll("\r\n", "").stripPrefix("-----BEGIN CERTIFICATE-----").stripSuffix("-----END CERTIFICATE-----")).toByteArray))
+ cert
+ }
+
+
+ /**
+ * 获取alias的密钥对和证书(系统初始化)
+ *
+ * @param alias
+ * @return
+ */
+ def getKeyPair(alias: String): (PrivateKey, PublicKey, Array[Byte]) = {
+ val sk = keyStore(alias).getKey(alias, password(alias).toCharArray)
+ val cert = keyStore(alias).getCertificate(alias)
+ if(checkCertificate(new java.util.Date(), cert)){
+ (sk.asInstanceOf[PrivateKey], cert.getPublicKey(), SerializeUtils.serialise(cert))
+ }else{
+ throw new RuntimeException("证书已经过期")
+ }
+ }
+
+ /**
+ * 获取alias的证书(系统初始化)
+ *
+ * @param alias
+ * @return
+ */
+ def getCert(alias: String): Certificate = {
+ keyStore(alias).getCertificate(alias)
+ }
+
+ /**
+ * 在信任列表中获取alias的证书(系统初始化)
+ *
+ * @param alias
+ * @return
+ */
+ def getKeyPairTrust(alias: String): PublicKey = {
+ val sk = trustKeyStore.getKey(alias, passwordTrust.toCharArray)
+ val cert = trustKeyStore.getCertificate(alias)
+ cert.getPublicKey()
+ }
+
+ /**
+ * 判断两个证书是否相同
+ *
+ * @param alias
+ * @param cert
+ * @return
+ */
+ def isCertTrust(alias: String, cert: Array[Byte]): Boolean = {
+ val sk = trustKeyStore.getKey(alias, passwordTrust.toCharArray)
+ val certT = trustKeyStore.getCertificate(alias)
+ //寻找方法能够恢复cert?
+ certT.getEncoded.equals(cert)
+ }
+
+ /**
+ * 预加载系统密钥对和信任证书
+ *
+ * @param alias
+ */
+ def preLoadKey(alias: String): Unit = {
+ val fis = new FileInputStream(new File(keyStorePath(alias)))
+ val pwd = password(alias).toCharArray()
+ if (keyStore.contains(alias)) keyStore(alias).load(fis, pwd)
+ else {
+ val keyS = KeyStore.getInstance(KeyStore.getDefaultType)
+ keyS.load(fis, pwd)
+ keyStore(alias) = keyS
+ }
+
+ val fisT = new FileInputStream(new File(trustKeyStorePath))
+ val pwdT = passwordTrust.toCharArray()
+ trustKeyStore.load(fisT, pwdT)
+ loadTrustkeysPubAddrMap()
+ }
+
+ /**
+ * 初始化信任证书中对短地址和证书的映射
+ */
+ def loadTrustkeysPubAddrMap(): Unit = {
+ val enums = trustKeyStore.aliases()
+ while (enums.hasMoreElements) {
+ val alias = enums.nextElement()
+ val cert = trustKeyStore.getCertificate(alias)
+ trustkeysPubAddrMap.put(getBitcoinAddrByCert(cert), cert)
+ }
+ }
+
+ /**
+ * 获取本地证书,得到证书类和其序列化的字节序列
+ *
+ * @param certPath
+ * @return 字节序列(通过base58进行转化)
+ */
+ def loadCertByPath(certPath: String): (Certificate, Array[Byte], String) = {
+ val certF = CertificateFactory.getInstance("X.509")
+ val fileInputStream = new FileInputStream(certPath)
+ val x509Cert = certF.generateCertificate(fileInputStream)
+ val arrayCert = SerializeUtils.serialise(x509Cert)
+ (x509Cert, arrayCert, Base64.Encoder(arrayCert).toBase64)
+ }
+
+ /**
+ * 添加证书到信任列表
+ *
+ * @param cert 字节数组
+ * @param alias
+ * @return
+ */
+ def loadTrustedCert(cert: Array[Byte], alias: String): Boolean = {
+ val certTx = SerializeUtils.deserialise(cert).asInstanceOf[Certificate]
+ getAliasByCert(certTx).getOrElse(None) match {
+ case None =>
+ trustKeyStore.setCertificateEntry(alias, certTx)
+ trustkeysPubAddrMap.put(getBitcoinAddrByCert(certTx), certTx)
+ val fileOutputStream = new FileOutputStream(trustKeyStorePath)
+ trustKeyStore.store(fileOutputStream, passwordTrust.toCharArray)
+ true
+ case _ =>
+ false
+ }
+ }
+
+ /**
+ * 添加证书到信任列表
+ *
+ * @param cert base64字符串
+ * @param alias
+ * @return
+ */
+ def loadTrustedCertBase64(cert: String, alias: String): Boolean = {
+ val certTx = SerializeUtils.deserialise(Base64.Decoder(cert).toByteArray).asInstanceOf[Certificate]
+ getAliasByCert(certTx).getOrElse(None) match {
+ case None =>
+ trustKeyStore.setCertificateEntry(alias, certTx)
+ trustkeysPubAddrMap.put(getBitcoinAddrByCert(certTx), certTx)
+ val fileOutputStream = new FileOutputStream(trustKeyStorePath)
+ trustKeyStore.store(fileOutputStream, passwordTrust.toCharArray)
+ true
+ case _ =>
+ false
+ }
+ }
+ def main(args: Array[String]): Unit = {
+ println(ByteString.copyFromUtf8(ECDSASign.getBitcoinAddrByCert(ECDSASign.getCertFromJKS(new File("jks/mykeystore_1.jks"), "123", "1"))).toStringUtf8)
+ println(ECDSASign.getBitcoinAddrByCert(ECDSASign.getCertFromJKS(new File("jks/mykeystore_2.jks"), "123", "2")))
+ println(ECDSASign.getBitcoinAddrByCert(ECDSASign.getCertFromJKS(new File("jks/mykeystore_3.jks"), "123", "3")))
+ println(ECDSASign.getBitcoinAddrByCert(ECDSASign.getCertFromJKS(new File("jks/mykeystore_4.jks"), "123", "4")))
+ println(ECDSASign.getBitcoinAddrByCert(ECDSASign.getCertFromJKS(new File("jks/mykeystore_5.jks"), "123", "5")))
+ }
+
+}
+
+/**
+ * 系统密钥相关类
+ * @author shidianyue
+ * @version 0.7
+ * @since 1.0
+ */
+class ECDSASign extends SignFunc {
+ /**
+ * 签名
+ *
+ * @param privateKey
+ * @param message
+ * @return
+ */
+ def sign(privateKey: PrivateKey, message: Array[Byte]): Array[Byte] = {
+ val s1 = Signature.getInstance("SHA1withECDSA");
+ s1.initSign(privateKey)
+ s1.update(message)
+ s1.sign()
+ }
+
+ /**
+ * 验证
+ *
+ * @param signature
+ * @param message
+ * @param publicKey
+ * @return
+ */
+ def verify(signature: Array[Byte], message: Array[Byte], publicKey: PublicKey): Boolean = {
+ val s2 = Signature.getInstance("SHA1withECDSA");
+ s2.initVerify(publicKey)
+ s2.update(message)
+ s2.verify(signature)
+ }
+
+ def getCertWithCheck(certAddr:String,certKey:String,sysTag:String):Option[java.security.cert.Certificate]={
+ val cert = ECDSASign.getCertByBitcoinAddr(certAddr)
+ if(cert != None) {
+ if(checkCertificate(new java.util.Date(), cert.get)){
+ cert
+ }else{
+ throw new RuntimeException("证书已经过期")
+ }
+ }else{
+ if(certKey == null || sysTag == null){
+ throw new RuntimeException("没有证书")
+ }else{
+ try{
+ val sr: ImpDataAccess = ImpDataAccess.GetDataAccess(sysTag)
+ val cert = Option(sr.Get(certKey))
+ if (cert != None){
+ if (new String(cert.get) == "null") {
+ throw new RuntimeException("用户证书已经注销")
+ }else{
+ val kvcert = SerializeUtils.deserialise(cert.get).asInstanceOf[Certificate]
+ if(kvcert != null){
+ if(checkCertificate(new java.util.Date(), kvcert)){
+ Some(kvcert)
+ }else{
+ throw new RuntimeException("证书已经过期")
+ }
+ }else{
+ throw new RuntimeException("证书内容错误")
+ }
+ }
+ }else{
+ throw new RuntimeException("没有证书")
+ }
+ }catch{
+ case e : Exception =>throw new RuntimeException("证书获取过程中发生错误",e)
+ }
+ }
+ }
+ }
+
+ def checkCertificate(date:java.util.Date, cert:Certificate):Boolean={
+ var isValid :Boolean = false
+ var start = System.currentTimeMillis()
+ try {
+ if(SystemProfile.getCheckCertValidate == 0){
+ isValid = true
+ }else if(SystemProfile.getCheckCertValidate == 1){
+ if(cert.isInstanceOf[X509Certificate]){
+ var x509cert :X509Certificate = cert.asInstanceOf[X509Certificate]
+ x509cert.checkValidity(date)
+ isValid = true
+ }
+ }else{
+ isValid = true
+ }
+ } catch{
+ case e : Exception => isValid = false
+ }
+ var end = System.currentTimeMillis()
+ //println("check cert validate,spent time="+(end-start))
+ isValid;
+ }
+
}
\ No newline at end of file
diff --git a/src/main/scala/rep/crypto/Sha256.scala b/src/main/scala/rep/crypto/Sha256.scala
index 32fbfad4..dcd66cd7 100644
--- a/src/main/scala/rep/crypto/Sha256.scala
+++ b/src/main/scala/rep/crypto/Sha256.scala
@@ -24,15 +24,16 @@ import com.google.protobuf.ByteString
object Sha256 extends CryptographicHash{
override val DigestSize: Int = 32
def hash(input: Array[Byte]): Array[Byte] = MessageDigest.getInstance("SHA-256").digest(input)
+
def hashstr(input: Array[Byte]):String ={
BytesHex.bytes2hex(hash(input))
}
-
+
def hashstr(input: String):String ={
val iptb = ByteString.copyFromUtf8(input)
BytesHex.bytes2hex(hash(iptb.toByteArray()))
}
-
+
def hashToBytes(input: String):Array[Byte] ={
val iptb = ByteString.copyFromUtf8(input)
hash(iptb.toByteArray())
diff --git a/src/main/scala/rep/log/EventActor.scala b/src/main/scala/rep/log/EventActor.scala
index 8b450652..74db0ea2 100644
--- a/src/main/scala/rep/log/EventActor.scala
+++ b/src/main/scala/rep/log/EventActor.scala
@@ -1,120 +1,120 @@
-/*
- * Copyright 2018 Blockchain Technology and Application Joint Lab, Fintech Research Center of ISCAS.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BA SIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package rep.log
-
-import rep.network.Topic
-import rep.protos.peer._
-import akka.stream.actor._
-import akka.actor.{Props,Address,PoisonPill}
-import akka.cluster.pubsub.DistributedPubSub
-import akka.cluster.pubsub.DistributedPubSubMediator.{Publish, Subscribe}
-import akka.cluster.Cluster
-import akka.cluster.ClusterEvent._
-import akka.cluster.MemberStatus
-import rep.ui.web.EventServer
-import rep.network.tools.PeerExtension
-import rep.storage._
-import akka.stream.Graph
-
-/** 负责处理websocket事件订阅的actor伴生对象
- * @author c4w
- */
-object EventActor {
- def props: Props = Props[EventActor]
-}
-
-/** 负责处理websocket事件订阅的Actor,一方面作为消费者在后台订阅Event,另一方面作为WebSocket的source
- * 向浏览器push事件流, 事件流采用protobuf流
- * @author c4w
- * @constructor
- */
-class EventActor extends ActorPublisher[Event] {
- import scala.concurrent.duration._
-
- val cluster = Cluster(context.system)
- var nodes = Set.empty[Address]
- var buffer = Vector.empty[Event]
-
- /** 启动,订阅集群入网、离网事件,订阅Topic事件
- *
- */
- override def preStart(): Unit ={
- cluster.subscribe(self, classOf[MemberEvent])
- val mediator = DistributedPubSub(context.system).mediator
- //发送订阅Event
- mediator ! Subscribe(Topic.Event, self)
- //发送当前出块人
- val pe = PeerExtension(context.system)
- self ! new Event( pe.getBlocker.toString, "", Event.Action.CANDIDATOR)
- }
-
- /** 停止处理,取消订阅
- *
- */
- override def postStop(): Unit =
- cluster unsubscribe self
-
- /** 接收Event处理,支持所谓“背压”方式,即根据web端消费能力push
- *
- */
- override def receive: Receive = {
- //Topic事件
- case evt:Event=>
- //当浏览器关掉,自杀
- if(this.isCanceled){
- self ! PoisonPill
- }else{
- if (buffer.isEmpty && totalDemand > 0) {
- onNext(evt)
- }
- else {
- buffer :+= evt
- if (totalDemand > 0) {
- val (use,keep) = buffer.splitAt(totalDemand.toInt)
- buffer = keep
- use foreach onNext
- }
- }
- }
- //集群事件
- case state: CurrentClusterState =>
- val iter = state.members.iterator;
- iter.foreach { m =>
- if (m.status == MemberStatus.Up){
- self ! new Event( m.address.toString, "", Event.Action.MEMBER_UP)
- }
- }
- //节点入网
- case MemberUp(member) =>
- nodes += member.address
- self !new Event( member.address.toString, "", Event.Action.MEMBER_UP)
- case UnreachableMember(member) =>
- //节点离网
- case MemberRemoved(member, _) =>
- val maddr = member.address.toString
- val saddr = Cluster(context.system).selfAddress.toString
- //println(s"-------$maddr-----$saddr")
- if(maddr == saddr){
- context.system.terminate()
- }else{
- nodes -= member.address
- self ! new Event( member.address.toString,"",Event.Action.MEMBER_DOWN)
- }
- case _: MemberEvent => // ignore
-
- }
-}
-
+/*
+ * Copyright 2018 Blockchain Technology and Application Joint Lab, Fintech Research Center of ISCAS.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BA SIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package rep.log
+
+import rep.network.Topic
+import rep.protos.peer._
+import akka.stream.actor._
+import akka.actor.{Props,Address,PoisonPill}
+import akka.cluster.pubsub.DistributedPubSub
+import akka.cluster.pubsub.DistributedPubSubMediator.{Publish, Subscribe}
+import akka.cluster.Cluster
+import akka.cluster.ClusterEvent._
+import akka.cluster.MemberStatus
+import rep.ui.web.EventServer
+import rep.network.tools.PeerExtension
+import rep.storage._
+import akka.stream.Graph
+
+/** 负责处理websocket事件订阅的actor伴生对象
+ * @author c4w
+ */
+object EventActor {
+ def props: Props = Props[EventActor]
+}
+
+/** 负责处理websocket事件订阅的Actor,一方面作为消费者在后台订阅Event,另一方面作为WebSocket的source
+ * 向浏览器push事件流, 事件流采用protobuf流
+ * @author c4w
+ * @constructor
+ */
+class EventActor extends ActorPublisher[Event] {
+ import scala.concurrent.duration._
+
+ val cluster = Cluster(context.system)
+ var nodes = Set.empty[Address]
+ var buffer = Vector.empty[Event]
+
+ /** 启动,订阅集群入网、离网事件,订阅Topic事件
+ *
+ */
+ override def preStart(): Unit ={
+ cluster.subscribe(self, classOf[MemberEvent])
+ val mediator = DistributedPubSub(context.system).mediator
+ //发送订阅Event
+ mediator ! Subscribe(Topic.Event, self)
+ //发送当前出块人
+ val pe = PeerExtension(context.system)
+ self ! new Event( pe.getBlocker.toString, "", Event.Action.CANDIDATOR)
+ }
+
+ /** 停止处理,取消订阅
+ *
+ */
+ override def postStop(): Unit =
+ cluster unsubscribe self
+
+ /** 接收Event处理,支持所谓“背压”方式,即根据web端消费能力push
+ *
+ */
+ override def receive: Receive = {
+ //Topic事件
+ case evt:Event=>
+ //当浏览器关掉,自杀
+ if(this.isCanceled){
+ self ! PoisonPill
+ }else{
+ if (buffer.isEmpty && totalDemand > 0) {
+ onNext(evt)
+ }
+ else {
+ buffer :+= evt
+ if (totalDemand > 0) {
+ val (use,keep) = buffer.splitAt(totalDemand.toInt)
+ buffer = keep
+ use foreach onNext
+ }
+ }
+ }
+ //集群事件
+ case state: CurrentClusterState =>
+ val iter = state.members.iterator;
+ iter.foreach { m =>
+ if (m.status == MemberStatus.Up){
+ self ! new Event( m.address.toString, "", Event.Action.MEMBER_UP)
+ }
+ }
+ //节点入网
+ case MemberUp(member) =>
+ nodes += member.address
+ self !new Event( member.address.toString, "", Event.Action.MEMBER_UP)
+ case UnreachableMember(member) =>
+ //节点离网
+ case MemberRemoved(member, _) =>
+ val maddr = member.address.toString
+ val saddr = Cluster(context.system).selfAddress.toString
+ //println(s"-------$maddr-----$saddr")
+ if(maddr == saddr){
+ context.system.terminate()
+ }else{
+ nodes -= member.address
+ self ! new Event( member.address.toString,"",Event.Action.MEMBER_DOWN)
+ }
+ case _: MemberEvent => // ignore
+
+ }
+}
+
diff --git a/src/main/scala/rep/network/PeerHelper.scala b/src/main/scala/rep/network/PeerHelper.scala
index 4780c356..89c205f8 100644
--- a/src/main/scala/rep/network/PeerHelper.scala
+++ b/src/main/scala/rep/network/PeerHelper.scala
@@ -132,7 +132,6 @@ object PeerHelper {
}catch{
case e:RuntimeException => throw e
}
-
t
}
diff --git a/src/main/scala/rep/network/cache/TransactionPool.scala b/src/main/scala/rep/network/cache/TransactionPool.scala
index bd523bd7..afaf9f98 100644
--- a/src/main/scala/rep/network/cache/TransactionPool.scala
+++ b/src/main/scala/rep/network/cache/TransactionPool.scala
@@ -93,7 +93,7 @@ class TransactionPool(moduleName: String) extends ModuleBase(moduleName) {
}catch{
case e : RuntimeException => throw e
}
-
+
CheckedTransactionResult(result, resultMsg)
}
diff --git a/src/main/scala/rep/network/consensus/block/BlockHelper.scala b/src/main/scala/rep/network/consensus/block/BlockHelper.scala
index 416c5dc5..57753b7a 100644
--- a/src/main/scala/rep/network/consensus/block/BlockHelper.scala
+++ b/src/main/scala/rep/network/consensus/block/BlockHelper.scala
@@ -53,7 +53,6 @@ object BlockHelper {
}catch{
case e:RuntimeException => throw e
}
-
}
/**
@@ -77,7 +76,7 @@ object BlockHelper {
}catch{
case e : RuntimeException => false
}
-
+
}
//用于对交易对签名验证
@@ -88,7 +87,6 @@ object BlockHelper {
val tOutSig1 = t.withSignature(ByteString.EMPTY)
val tOutSig = tOutSig1.withMetadata(ByteString.EMPTY)
-
try{
val cid = ChaincodeID.fromAscii(t.chaincodeID.toStringUtf8).name
val certKey = IdxPrefix.WorldStateKeyPreFix + cid + "_" + "CERT_" + t.cert.toStringUtf8 // 普通用户证书的key
@@ -101,7 +99,6 @@ object BlockHelper {
}catch{
case e : RuntimeException => resultMsg = s"The transaction(${t.txid}) is not trusted${e.getMessage}"
}
-
result
}
@@ -234,5 +231,5 @@ object BlockHelper {
println("sorted")
}
}
-
+
}
diff --git a/src/main/scala/rep/network/consensus/endorse/EndorsementModule.scala b/src/main/scala/rep/network/consensus/endorse/EndorsementModule.scala
index 303e4d8b..f37c202d 100644
--- a/src/main/scala/rep/network/consensus/endorse/EndorsementModule.scala
+++ b/src/main/scala/rep/network/consensus/endorse/EndorsementModule.scala
@@ -73,7 +73,7 @@ class EndorsementModule(moduleName: String) extends ModuleBase(moduleName) {
)
r
}
-
+
private def hasRepeatOfTrans(trans:Seq[Transaction]):Boolean={
var isRepeat : Boolean = false
val aliaslist = trans.distinct
@@ -95,7 +95,7 @@ class EndorsementModule(moduleName: String) extends ModuleBase(moduleName) {
}
-
+
private def endorseForWork(blk:Block, actRef: ActorRef,blkidentifier:String)={
val dbinstancename = "endorse_"+blk.transactions.head.txid
val preload: ImpDataPreload = ImpDataPreloadMgr.GetImpDataPreload(pe.getSysTag,dbinstancename)
diff --git a/src/main/scala/rep/network/consensus/transaction/PreloadTransactionModule.scala b/src/main/scala/rep/network/consensus/transaction/PreloadTransactionModule.scala
index f5df2a29..80229c13 100644
--- a/src/main/scala/rep/network/consensus/transaction/PreloadTransactionModule.scala
+++ b/src/main/scala/rep/network/consensus/transaction/PreloadTransactionModule.scala
@@ -127,15 +127,25 @@ class PreloadTransactionModule(moduleName: String, transProcessor:ActorRef) exte
logTime(s"Trans Preload End, Trans size ${transResult.size - errorCount}", CRFD_STEP._6_PRELOAD_END,
getActorRef(ActorType.STATISTIC_COLLECTION))
isPreload = false
- ImpDataPreloadMgr.Free(pe.getDBTag,blk.transactions.head.txid)
- clearCache() //是否是多余的,确保一定执行了
+ freeSource
schedulerLink = clearSched()
}
+ def freeSource={
+ if(blk != null){
+ if(blk.transactions.size > 0){
+ ImpDataPreloadMgr.Free(pe.getDBTag,blk.transactions.head.txid)
+ }
+ }
+ clearCache() //是否是多余的,确保一定执行了
+ }
+
override def receive = {
case PreTransBlock(blc, from,blkIdentifier) =>
val preBlk = dataaccess.getBlockByHash(blk.previousBlockHash.toStringUtf8)
+ freeSource
+
if((preBlk!=null && dataaccess.getBlockChainInfo().currentWorldStateHash == getBlkFromByte(preBlk).stateHash.toStringUtf8)
|| blk.previousBlockHash == ByteString.EMPTY){
blkIdentifier_src = blkIdentifier
@@ -214,10 +224,12 @@ class PreloadTransactionModule(moduleName: String, transProcessor:ActorRef) exte
preLoadFeedBackInfo(false, blk, preloadFrom, pe.getMerk)
blkIdentifier_src = ""
isPreload = false
- ImpDataPreloadMgr.Free(pe.getDBTag,blk.transactions.head.txid)
- clearCache() //是否是多余的,确保一定执行了
+ freeSource
schedulerLink = clearSched()
- case false => logMsg(LOG_TYPE.INFO, "Preload trans timeout checked, successfully")
+ case false => {
+ freeSource
+ logMsg(LOG_TYPE.INFO, "Preload trans timeout checked, successfully")
+ }
}
diff --git a/src/main/scala/rep/network/consensus/vote/CRFDVoter.scala b/src/main/scala/rep/network/consensus/vote/CRFDVoter.scala
index c1d72839..b867f05b 100644
--- a/src/main/scala/rep/network/consensus/vote/CRFDVoter.scala
+++ b/src/main/scala/rep/network/consensus/vote/CRFDVoter.scala
@@ -97,5 +97,5 @@ trait CRFDVoter extends VoterBase {
}
}
-
+
}
diff --git a/src/main/scala/rep/network/tools/PeerExtension.scala b/src/main/scala/rep/network/tools/PeerExtension.scala
index df3a0b8f..5cd05e74 100644
--- a/src/main/scala/rep/network/tools/PeerExtension.scala
+++ b/src/main/scala/rep/network/tools/PeerExtension.scala
@@ -259,7 +259,7 @@ class PeerExtensionImpl extends Extension {
candidatorLock.unlock()
}
}
-
+
def resetCandidator(nds: Array[ String ]): Unit = {
candidatorLock.lock()
try{
diff --git a/src/main/scala/rep/sc/Shim.scala b/src/main/scala/rep/sc/Shim.scala
index b45455d4..3a8f78ce 100644
--- a/src/main/scala/rep/sc/Shim.scala
+++ b/src/main/scala/rep/sc/Shim.scala
@@ -213,7 +213,7 @@ class Shim(system: ActorSystem, cid: String) {
val sig = tx.signature.toByteArray
val tOutSig1 = tx.withSignature(ByteString.EMPTY)
val tOutSig = tOutSig1.withMetadata(ByteString.EMPTY)
-
+
try{
val peercer = ECDSASign.getCertByBitcoinAddr(bitcoinaddr)
ECDSASign.verify(sig, PeerHelper.getTxHash(tOutSig), peercer.get.getPublicKey) match {
diff --git a/src/main/scala/rep/sc/contract/Compiler.scala b/src/main/scala/rep/sc/contract/Compiler.scala
index 5757b736..952591f3 100644
--- a/src/main/scala/rep/sc/contract/Compiler.scala
+++ b/src/main/scala/rep/sc/contract/Compiler.scala
@@ -27,6 +27,7 @@ import java.io._
import org.json4s._
import org.json4s.jackson.JsonMethods._
import rep.crypto.Sha256
+
import rep.app.conf.SystemProfile
import scala.reflect.runtime.currentMirror
import scala.tools.reflect.ToolBox
@@ -120,10 +121,20 @@ class Compiler(targetDir: Option[File], bDebug:Boolean) {
* @return 编译生成的类定义
*/
def compilef(pcode: String, cid: String): Class[_]= {
- val p1 = pcode.indexOf("extends IContract{")
+ //去掉package声明,将class放在default路径下
+ var p0 = pcode.indexOf("import")
+ //第一个定位点应加强容错能力,允许空白字符
+ val pattern = "extends\\s+IContract\\s*\\{".r
+ val p1str = pattern.findFirstIn(pcode).get
+ val p1 = pcode.indexOf(p1str)
val p2 = pcode.lastIndexOf("}")
val p3 = pcode.lastIndexOf("class ",p1)
+ //可能不存在import指令
+ if(p0.equals(-1))
+ p0 = p3
+ if(p1.equals(-1) || p1.equals(-1) || p1.equals(-1))
+ throw new RuntimeException("合约语法错误")
val className = if(cid!=null) PRE_CLS_NAME+cid else classNameForCode(pcode)
try{
val cl = Class.forName(className)
@@ -132,7 +143,7 @@ class Compiler(targetDir: Option[File], bDebug:Boolean) {
case e:Throwable =>
findClass(className).getOrElse {
//替换类名为 hash256
- val ncode = pcode.substring(0,p3) + "class "+className+ " "+pcode.substring(p1,p2+1)
+ val ncode = pcode.substring(p0,p3) + "class "+className+ " "+pcode.substring(p1,p2+1)
//+"\nscala.reflect.classTag[ContractAssets2].runtimeClass"
if(path_source!=null)
saveCode(className,ncode)
diff --git a/src/main/scala/rep/sc/scalax/SandboxScala.scala b/src/main/scala/rep/sc/scalax/SandboxScala.scala
index b51d76b3..76ae17a9 100644
--- a/src/main/scala/rep/sc/scalax/SandboxScala.scala
+++ b/src/main/scala/rep/sc/scalax/SandboxScala.scala
@@ -72,6 +72,7 @@ class SandboxScala(cid:String) extends Sandbox(cid){
shim.ol.append(new Oper(key, null, txid))
encodeJson(cid)
//新建class实例并执行合约,传参为json数据
+ //TODO case Transaction.Type.CHAINCODE_DESC 增加对合约描述的处理
case Transaction.Type.CHAINCODE_INVOKE =>
//获得合约action
val action = cs.ctorMsg.get.function
diff --git a/src/main/scala/rep/sc/tpl/SupplyTPL.scala b/src/main/scala/rep/sc/tpl/SupplyTPL.scala
new file mode 100644
index 00000000..9b51c47a
--- /dev/null
+++ b/src/main/scala/rep/sc/tpl/SupplyTPL.scala
@@ -0,0 +1,171 @@
+
+
+package rep.sc.tpl
+
+import rep.sc.contract._
+import org.json4s._
+import org.json4s.jackson.JsonMethods._
+import scala.reflect.ManifestFactory.classType
+import scala.collection.mutable.Map
+import org.json4s.native.Serialization
+import org.json4s.native.Serialization.{read, write}
+import org.json4s.{DefaultFormats, Formats, jackson}
+
+/**
+ * 供应链分账合约
+ */
+class SupplyTPL extends IContract {
+ import rep.sc.tpl.SupplyType._
+
+ val SPLIT_CHAR = "_";
+ val TPL_MODE = "_PM";
+ implicit val formats = DefaultFormats
+
+
+ def init(ctx: ContractContext){
+ println(s"tid: $ctx.t.txid")
+ }
+
+ /**
+ * 追加确认签名 TODO 逻辑实现
+ */
+ def confirmSign(ctx: ContractContext, data:IPTConfirm ):Object={
+ null
+ }
+ /**
+ * 取消追加确认签名 TODO 逻辑实现
+ */
+ def cancelSign(ctx: ContractContext, data:IPTConfirm ):Object={
+ null
+ }
+ /**
+ * 设计方、原料方、生产方、销售方 签订对销售额的分成合约, 对于销售方账号+产品型号决定唯一的分账合约
+ */
+ def signShare(ctx: ContractContext, data:IPTSignShare ):Object={
+ val sid = data.account_sale +SPLIT_CHAR + data.product_id
+ val pid = sid+TPL_MODE
+ //签约输入持久化,默认的类型转换无法胜任,以json字符串形式持久化
+ ctx.api.setVal(sid, write(data))
+ ctx.api.setVal(pid, TPL.Share)
+ sid
+ }
+
+ def signFixed(ctx: ContractContext, data:IPTSignFixed ):Object={
+ val sid = data.account_sale +SPLIT_CHAR + data.product_id
+ val pid = sid+TPL_MODE
+ //签约输入持久化
+ ctx.api.setVal(sid, write(data))
+ ctx.api.setVal(pid, TPL.Fixed)
+ sid
+ }
+
+ /**
+ * 分账的调度方法,负责根据调用相应的分账模版, 传入模版定制参数和销售数据,进行分账
+ */
+ def split(ctx: ContractContext, data:IPTSplit ):Object={
+ //根据销售方账号和产品Id获得分账脚本
+ val sid = data.account_sale +SPLIT_CHAR + data.product_id
+ val pid = sid + TPL_MODE
+ val tm = ctx.api.getVal(pid).asInstanceOf[String]
+
+ //根据签约时选择的分账方式模版,验证定制参数
+ val mr = tm match {
+ case TPL.Share =>
+ val sp0 = ctx.api.getVal(sid)
+ val sp = read[IPTSignShare](ctx.api.getVal(sid).asInstanceOf[String])
+ splitShare(data.amount, sp.account_remain, sp.tpl_param)
+ case TPL.Fixed =>
+ val sp = read[IPTSignFixed](ctx.api.getVal(sid).asInstanceOf[String])
+ splitFixedRatio(data.amount, sp.account_remain, sp.ratio)
+ }
+ //返回分账计算结果
+ addToAccount(ctx, mr)
+ mr
+ }
+
+ /**
+ * 将分账结果增加到账户并持久化
+ */
+ def addToAccount(ctx: ContractContext, mr:Map[String,Int]){
+ for ((k, v) <- mr) {
+ val sk = ctx.api.getVal(k)
+ var dk = if(sk==null) 0 else sk.toString.toInt
+ ctx.api.setVal(k, dk+v)
+ }
+ }
+ /**
+ * 合约方法入口
+ */
+ def onAction(ctx: ContractContext,action:String, sdata:String ):Object={
+ val json = parse(sdata)
+
+ action match {
+ case ACTION.SignShare =>
+ signShare(ctx,json.extract[IPTSignShare])
+ case ACTION.SignFixed =>
+ signFixed(ctx,json.extract[IPTSignFixed])
+ case ACTION.Split =>
+ split(ctx, json.extract[IPTSplit])
+ case ACTION.ConfirmSign =>
+ confirmSign(ctx,json.extract[IPTConfirm])
+ case ACTION.CancelSign =>
+ cancelSign(ctx, json.extract[IPTConfirm])
+ }
+ }
+ //TODO case Transaction.Type.CHAINCODE_DESC 增加对合约描述的处理
+ def descAction(ctx: ContractContext,action:String, sdata:String ):String={
+ val json = parse(sdata)
+ null
+ }
+
+/**
+ * 内部函数, 获得分阶段的分成
+ */
+ def getShare(sr: Int, ar: Array[ShareRatio]) : Int={
+ var rv = 0
+ for(el <- ar) {
+ //击中金额范围
+ if(sr > el.from && sr <= el.to) {
+ //固定金额
+ if(el.fixed > 0)
+ rv = el.fixed
+ else //按比例分成
+ rv = (sr * el.ratio) .toInt
+ }
+ }
+ rv
+ }
+/**
+ * 合约中内置多种分账模版,签约时可选择模版,如果出现新的分账模版,则部署一版新的合约
+ * 分成模型, 除了销售方之外, 其他各方要求一个最低金额,分成按照金额阶段有所不同。
+ */
+ def splitShare(sr: Int, account_remain:String, rule: ShareMap): Map[String,Int] ={
+ //分账结果
+ val rm : Map[String, Int] = Map()
+ //分账余额
+ var remain = sr
+ for ((k, v) <- rule) {
+ val rv = getShare(sr, v)
+ rm += (k -> rv)
+ remain -= rv
+ }
+ rm += (account_remain -> remain)
+ }
+
+
+/**
+ * 各方固定比例分成,此模版仅仅为了合约对多模版的支持,可能无实际用途
+ */
+ def splitFixedRatio(sr: Int, account_remain: String, mr:FixedMap): Map[String,Int] ={
+ val rm : Map[String, Int] = Map()
+ var remain = sr
+ //根据固定分成
+ for ((k, v) <- mr) {
+ val rv = (sr* v ).toInt
+ rm += (k -> rv)
+ remain -= rv
+ }
+ //剩余的分给指定的余额账户
+ rm += (account_remain -> remain)
+ }
+}
\ No newline at end of file
diff --git a/src/main/scala/rep/sc/tpl/SupplyType.scala b/src/main/scala/rep/sc/tpl/SupplyType.scala
new file mode 100644
index 00000000..d1a8068b
--- /dev/null
+++ b/src/main/scala/rep/sc/tpl/SupplyType.scala
@@ -0,0 +1,53 @@
+package rep.sc.tpl
+
+import scala.collection.mutable.Map
+
+/**
+ * 分账接口
+ */
+trait ISupplySplit {
+ /**
+ * @param sr 销售收入
+ * @param accounts 参与分账的账户
+ * @return 分账结果
+ */
+ def split(sr: Int, accounts: Array[String]): Array[Int]
+}
+
+
+package object SupplyType {
+ object ACTION {
+ val SignShare = "SignShare"
+ val SignFixed = "SignFixed"
+ val ConfirmSign = "ConfirmSign"
+ val CancelSign = "CancelSign"
+ val Split = "Split"
+
+ }
+
+ object TPL {
+ val Share = "Share"
+ val Fixed = "Fixed"
+ }
+ /**
+ * 按销售收入分段分成/固定值 的设置项
+ */
+ case class ShareRatio(from: Int, to: Int, ratio: Double, fixed: Int)
+ //多个账户的分段分成定义
+ type ShareMap = scala.collection.mutable.Map[String, Array[ShareRatio]]
+ type FixedMap = scala.collection.mutable.Map[String,Double]
+ /**
+ * 签署分成合约的输入参数
+ * @param account_sale 提交销售数据的账号
+ * @param
+ */
+ case class IPTSignShare(account_sale :String, product_id: String, account_remain :String, tpl_param: ShareMap)
+ //固定分账比例
+ case class IPTSignFixed(account_sale :String, product_id: String, account_remain :String, ratio:Map[String,Double] )
+ //触发分账的输入参数
+ //TODO 如何防止重复提交?
+ case class IPTSplit(account_sale :String, product_id:String, amount:Int)
+
+ case class IPTConfirm(account: String, tx_id:String)
+}
+
diff --git a/src/main/scala/rep/storage/test/testmap.scala b/src/main/scala/rep/storage/test/testmap.scala
index f0119ad5..b1cf9364 100644
--- a/src/main/scala/rep/storage/test/testmap.scala
+++ b/src/main/scala/rep/storage/test/testmap.scala
@@ -256,7 +256,7 @@ def testTreeMapclear{
println(tm)
}
-
+
case class myobject(txid:String,name:String)
def main(args: Array[String]): Unit = {
@@ -271,6 +271,6 @@ case class myobject(txid:String,name:String)
val tmp = as.distinct
println("tmpsize="+tmp.length+",assize="+as.length)
-
+
}
}
\ No newline at end of file
diff --git a/src/main/scala/rep/storage/util/pathUtil.java b/src/main/scala/rep/storage/util/pathUtil.java
index d6bf84b7..9558f27c 100644
--- a/src/main/scala/rep/storage/util/pathUtil.java
+++ b/src/main/scala/rep/storage/util/pathUtil.java
@@ -119,6 +119,7 @@ public class pathUtil {
}
return l;
}
+
public static int bytesToInt(byte[] inputs){
if(inputs == null) return 0;
diff --git a/src/main/scala/sha0bfbe2faf858dd495e712fb0f897dd66082f06b879fa21a80fcc2acbc199b8d7.scala b/src/main/scala/sha0bfbe2faf858dd495e712fb0f897dd66082f06b879fa21a80fcc2acbc199b8d7.scala
new file mode 100644
index 00000000..febb6254
--- /dev/null
+++ b/src/main/scala/sha0bfbe2faf858dd495e712fb0f897dd66082f06b879fa21a80fcc2acbc199b8d7.scala
@@ -0,0 +1,127 @@
+import org.json4s._
+import org.json4s.jackson.JsonMethods._
+import rep.sc.contract._
+import rep.storage.FakeStorage.Key
+
+/**
+ * 资产管理合约
+ */
+
+class sha0bfbe2faf858dd495e712fb0f897dd66082f06b879fa21a80fcc2acbc199b8d7 extends IContract{
+ case class Transfer(from:String, to:String, amount:Int)
+// case class Proof(key:String, content:String)
+ case class ReplaceCert(cert:String, addr:String)
+// case class Cert(cert:String, info:String)
+
+ implicit val formats = DefaultFormats
+
+ def init(ctx: ContractContext){
+ println(s"tid: $ctx.t.txid")
+ }
+
+ def set(ctx: ContractContext, data:Map[String,Int]):Object={
+ println(s"set data:$data")
+ for((k,v)<-data){
+ ctx.api.setVal(k, v)
+ }
+ null
+ }
+
+
+ def read(ctx: ContractContext, key: String):Any={
+ ctx.api.getVal(key)
+ }
+
+ def loadCert(ctx: ContractContext, cert: String): Unit = {
+ ctx.api.loadCert(cert);
+ print("cert:"+cert);
+ }
+
+ def write(ctx: ContractContext, data:Map[String,Int]):Object = {
+ for((k,v)<-data){
+ ctx.api.setVal(k, v)
+ }
+ null
+ }
+
+ def put_proof(ctx: ContractContext, data:Map[String,Any]):Object={
+ //先检查该hash是否已经存在,如果已存在,抛异常
+ for((k,v)<-data){
+ var pv0 = ctx.api.getVal(k)
+ if(pv0 != null)
+ throw new Exception("["+k+"]已存在,当前值["+pv0+"]");
+ ctx.api.setVal(k,v);
+ print("putProof:"+k+":"+v);
+ }
+ "put_proof ok"
+ }
+
+
+
+ def signup(ctx: ContractContext, data:Map[String,String]):Object = {
+ var addr = ""
+ for((k,v)<-data){
+ ctx.api.check(ctx.t.cert.toStringUtf8,ctx.t)
+ addr = ctx.api.signup(k,v)
+ }
+ addr
+ }
+
+ def destroyCert(ctx: ContractContext, certAddr: String): Object = {
+ println(s"destroy cert->addr:$certAddr")
+ ctx.api.check(ctx.t.cert.toStringUtf8,ctx.t) //ctx中自带交易内容
+ ctx.api.destroyCert(certAddr);
+ "destory scuccess"
+ }
+
+ def replaceCert(ctx: ContractContext, data:ReplaceCert): Object = {
+ val cert = data.cert
+ val addr = data.addr
+ ctx.api.check(ctx.t.cert.toStringUtf8,ctx.t)
+ ctx.api.replaceCert(cert,addr); // 返回短地址
+ }
+
+ def transfer(ctx: ContractContext, data:Transfer):Object={
+ val sfrom = ctx.api.getVal(data.from)
+ var dfrom =sfrom.toString.toInt
+ if(dfrom < data.amount)
+ throw new Exception("余额不足")
+ var dto = ctx.api.getVal(data.to).toString.toInt
+ //if(dto==null) dto = 0;
+
+ ctx.api.setVal(data.from,dfrom - data.amount)
+ ctx.api.setVal(data.to,dto + data.amount)
+ "transfer ok"
+ }
+
+ /**
+ * 根据action,找到对应的method,并将传入的json字符串parse为method需要的传入参数
+ */
+ def onAction(ctx: ContractContext,action:String, sdata:String ):Object={
+ //println(s"onAction---")
+ //return "transfer ok"
+ val json = parse(sdata)
+
+ action match {
+ case "transfer" =>
+ println(s"transfer oook")
+ transfer(ctx,json.extract[Transfer])
+ case "set" =>
+ println(s"set")
+ set(ctx, json.extract[Map[String,Int]])
+ case "put_proof" =>
+ println(s"put_proof")
+ put_proof(ctx, json.extract[Map[String,Any]])
+ case "signup" =>
+ println(s"signup")
+ signup(ctx, json.extract[Map[String,String]])
+ case "destroyCert" =>
+ println(s"destroyCert")
+ destroyCert(ctx, json.extract[String])
+ case "replaceCert" =>
+ println(s"replaceCert")
+ replaceCert(ctx, json.extract[ReplaceCert])
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/src/test/scala/rep/sc/SplitSpec.scala b/src/test/scala/rep/sc/SplitSpec.scala
new file mode 100644
index 00000000..0f8acf17
--- /dev/null
+++ b/src/test/scala/rep/sc/SplitSpec.scala
@@ -0,0 +1,93 @@
+package rep.sc
+import org.scalatest._
+import rep.sc.tpl.SupplyTPL
+import prop._
+import scala.collection.immutable._
+import scala.collection.mutable.Map
+
+import org.json4s._
+import org.json4s.JsonDSL._
+import org.json4s.jackson.JsonMethods._
+import org.json4s.{DefaultFormats, Formats, jackson}
+import org.json4s.native.Serialization.writePretty
+import org.json4s.native.Serialization
+import org.json4s.native.Serialization.{read, write}
+
+
+class SplitSpec extends PropSpec with TableDrivenPropertyChecks with Matchers {
+ import rep.sc.tpl.SupplyType._
+ import rep.sc.tpl.SupplyType.FixedMap
+ implicit val formats = DefaultFormats
+ //implicit val formats = Serialization.formats(NoTypeHints)
+
+ val fm :FixedMap = Map("A" -> 0.2, "B"-> 0.2, "C"-> 0.1, "D" -> 0.1)
+ val sm :ShareMap = Map("A" -> Array(new ShareRatio(0,100,0.1,0), new ShareRatio(100,10000,0.15,0)),
+ "B" -> Array(new ShareRatio(0,10000,0,10)),
+ "C" -> Array(new ShareRatio(0,10000,0.1,0)),
+ "D" -> Array(new ShareRatio(0,100,0,10), new ShareRatio(100,10000,0.15,0)))
+ val account_remain = "R"
+ val account_sales = "S"
+ val product_id = "P201806270001"
+
+ val s1 = new SupplyTPL
+
+ val examples =
+ Table(
+ "sr",
+ 100,
+ 200,
+ 500,
+ 1000
+ )
+ property("JSon format works for IPTSignShare") {
+ val ipt1 = new IPTSignShare(account_sales,product_id,account_remain,sm)
+ val jstr = writePretty(ipt1)
+ println(s"${jstr}")
+ val ipt2 = read[IPTSignShare](jstr)
+ ipt2.account_remain should be (ipt1.account_remain)
+ ipt2.tpl_param("A").length should be (ipt1.tpl_param("A").length)
+ ipt2.tpl_param("A")(0) should be (ipt1.tpl_param("A")(0))
+ }
+ property("JSon format works for IPTSignFixed") {
+ val ipt1 = new IPTSignFixed(account_sales,product_id,account_remain,fm)
+ val jstr = write(ipt1)
+ println(s"${jstr}")
+ val ipt2 = read[IPTSignFixed](jstr)
+ ipt2.account_remain should be (ipt1.account_remain)
+ ipt2.ratio should be (ipt1.ratio)
+ }
+ property("JSon format works for IPTSplit") {
+ val ipt1 = new IPTSplit(account_sales,product_id,1000)
+ val jstr = write(ipt1)
+ println(s"${jstr}")
+ val ipt2 = read[IPTSplit](jstr)
+ ipt2.product_id should be (ipt1.product_id)
+ }
+ property(" Splitting sales-revenue by splitFixedRatio") {
+ forAll(examples) { sr =>
+ val rm = s1.splitFixedRatio(sr, account_remain,fm)
+ var total = 0
+ print(s"total:${sr} ")
+ for ((k, v) <- rm) {
+ total += v
+ print(s" ${k}: ${v} ")
+ }
+ println("")
+ total should be (sr)
+ }
+ }
+ property(" Splitting sales-revenue by splitShare") {
+ forAll(examples) { sr =>
+ val rm = s1.splitShare(sr, account_remain,sm)
+ var total = 0
+ print(s"total:${sr} ")
+ for ((k, v) <- rm) {
+ total += v
+ print(s" ${k}: ${v} ")
+ }
+ println("")
+ total should be (sr)
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/src/test/scala/rep/sc/SupplySpec.scala b/src/test/scala/rep/sc/SupplySpec.scala
new file mode 100644
index 00000000..5febde88
--- /dev/null
+++ b/src/test/scala/rep/sc/SupplySpec.scala
@@ -0,0 +1,187 @@
+/*
+ * Copyright 2018 Blockchain Technology and Application Joint Lab, Fintech Research Center of ISCAS.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BA SIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package rep.sc
+
+import org.scalatest.{ BeforeAndAfterAll, FlatSpecLike, Matchers }
+import akka.actor.ActorSystem
+import akka.testkit.TestKit
+
+import scala.concurrent.Await
+import scala.concurrent.duration._
+import rep.protos.peer._
+import rep.app.system.ClusterSystem
+import rep.app.system.ClusterSystem.InitType
+
+import rep.network.PeerHelper.transactionCreator
+import org.json4s.{ DefaultFormats, jackson }
+import de.heikoseeberger.akkahttpjson4s.Json4sSupport
+import org.json4s._
+import rep.network.module.ModuleManager
+import rep.storage.ImpDataAccess
+import rep.utils.Json4s._
+import rep.sc.contract._
+import java.io.IOException
+import java.io.PrintWriter
+import java.io.FileWriter
+import java.io.File
+
+import scala.collection.mutable.Map
+import org.json4s.{DefaultFormats, Formats, jackson}
+import org.json4s.native.Serialization.writePretty
+import org.json4s.native.Serialization
+import org.json4s.native.Serialization.{read, write}
+
+/** 合约容器实现的单元测试
+ * @author c4w
+ * @param _system 测试用例所在的actor System.
+ *
+ */
+class SupplySpec(_system: ActorSystem)
+ extends TestKit(_system)
+ with Matchers
+ with FlatSpecLike
+ with BeforeAndAfterAll {
+
+ import rep.sc.TransProcessor.DoTransaction
+ import rep.sc.Sandbox.DoTransactionResult
+
+ import akka.testkit.TestProbe
+ import akka.testkit.TestActorRef
+ import Json4sSupport._
+ import rep.sc.tpl.SupplyType._
+
+ implicit val serialization = jackson.Serialization
+ // or native.Serialization
+ implicit val formats = DefaultFormats
+
+ def this() = this(ActorSystem("SandBoxSpec", new ClusterSystem("1", InitType.MULTI_INIT, false).getConf))
+
+ override def afterAll: Unit = Await.ready(system.terminate(), Duration.Inf)
+
+ //Scala实现的资产管理合约测试,包括合约的部署、调用、结果返回验证
+ "container" should "deploy supply contract and call it for splitting then" in {
+ val sysName = "1"
+ val dbTag = "1"
+ //建立PeerManager实例是为了调用transactionCreator(需要用到密钥签名),无他
+ val pm = system.actorOf(ModuleManager.props("pm", sysName))
+ //加载合约脚本
+ val s1 = scala.io.Source.fromFile("src/main/scala/rep/sc/tpl/SupplyTPL.scala")
+ val l1 = try s1.mkString finally s1.close()
+
+ val fm :FixedMap= Map("A" -> 0.2, "B"-> 0.2, "C"-> 0.1, "D" -> 0.1)
+ val sm :ShareMap = Map("A" -> Array(new ShareRatio(0,100,0.1,0), new ShareRatio(100,10000,0.15,0)),
+ "B" -> Array(new ShareRatio(0,10000,0,10)),
+ "C" -> Array(new ShareRatio(0,10000,0.1,0)),
+ "D" -> Array(new ShareRatio(0,100,0,10), new ShareRatio(100,10000,0.15,0)))
+ val account_remain = "R"
+ val account_sales1 = "S1"
+ val account_sales2 = "S2"
+ val product_id = "P201806270001"
+
+ //构造签约交易合约模版1输入json字符串,销售1选择了合约模版1
+ val ipt2 = new IPTSignFixed(account_sales1,product_id,account_remain,fm)
+ val l2 = write(ipt2)
+
+ //构造签约交易合约模版2输入json字符串,,销售2选择了合约模版2
+ val ipt3 = new IPTSignShare(account_sales2,product_id,account_remain,sm)
+ val l3 = writePretty(ipt3)
+
+ //准备探针以验证调用返回结果
+ val probe = TestProbe()
+ val db = ImpDataAccess.GetDataAccess(sysName)
+ var sandbox = system.actorOf(TransProcessor.props("sandbox", "", probe.ref))
+ //生成deploy交易
+ val t1 = transactionCreator(sysName, rep.protos.peer.Transaction.Type.CHAINCODE_DEPLOY,
+ "", "", List(), l1, None, rep.protos.peer.ChaincodeSpec.CodeType.CODE_SCALA)
+
+ val msg_send1 = new DoTransaction(t1, probe.ref, "")
+ probe.send(sandbox, msg_send1)
+ val msg_recv1 = probe.expectMsgType[Sandbox.DoTransactionResult](1000.seconds)
+ val ol1 = msg_recv1.ol
+ val ol1str = compactJson(ol1)
+
+ //生成invoke交易
+ //获取deploy生成的chainCodeId
+ //初始化资产
+ val cname = t1.payload.get.chaincodeID.get.name
+ val t2 = transactionCreator(sysName, rep.protos.peer.Transaction.Type.CHAINCODE_INVOKE,
+ "", ACTION.SignFixed, Seq(l2), "", Option(cname))
+
+ val msg_send2 = new DoTransaction(t2, probe.ref, "")
+ probe.send(sandbox, msg_send2)
+ val msg_recv2 = probe.expectMsgType[Sandbox.DoTransactionResult](1000.seconds)
+
+ val t3 = transactionCreator(sysName, rep.protos.peer.Transaction.Type.CHAINCODE_INVOKE,
+ "", ACTION.SignShare, Seq(l3), "", Option(cname))
+ val msg_send3 = new DoTransaction(t3, probe.ref, "")
+ probe.send(sandbox, msg_send3)
+ val msg_recv3 = probe.expectMsgType[Sandbox.DoTransactionResult](1000.seconds)
+
+ //测试各种金额下的分账结果
+ val sr = Array(100, 200, 500, 1000)
+ for (el<- sr) {
+ //构造分账交易
+ val ipt4 = new IPTSplit(account_sales1,product_id,el)
+ val l4 = write(ipt4)
+ val t4 = transactionCreator(sysName, rep.protos.peer.Transaction.Type.CHAINCODE_INVOKE,
+ "", ACTION.Split, Seq(l4), "", Option(cname))
+ val msg_send4 = new DoTransaction(t4, probe.ref, "")
+
+ probe.send(sandbox, msg_send4)
+ val msg_recv4 = probe.expectMsgType[Sandbox.DoTransactionResult](1000.seconds)
+ val ol4 = msg_recv4.ol
+ val ol4str = compactJson(ol4)
+ println(s"oper log:${ol4str}")
+ //获得交易返回值
+ val jv4 = msg_recv4.r.asInstanceOf[JValue]
+ val rv4 = jv4.extract[Map[String,Int]]
+ println(rv4)
+ //分账之后总额应保持一致
+ var total = 0
+ for ((k, v) <- rv4) {
+ total += v
+ }
+ total should be(el)
+ }
+
+ for (el<- sr) {
+ //构造分账交易
+ val ipt4 = new IPTSplit(account_sales2,product_id,el)
+ val l4 = write(ipt4)
+ val t4 = transactionCreator(sysName, rep.protos.peer.Transaction.Type.CHAINCODE_INVOKE,
+ "", ACTION.Split, Seq(l4), "", Option(cname))
+ val msg_send4 = new DoTransaction(t4, probe.ref, "")
+
+ probe.send(sandbox, msg_send4)
+ val msg_recv4 = probe.expectMsgType[Sandbox.DoTransactionResult](1000.seconds)
+ val ol4 = msg_recv4.ol
+ val ol4str = compactJson(ol4)
+ println(s"oper log:${ol4str}")
+ //获得交易返回值
+ //获得交易返回值
+ val jv4 = msg_recv4.r.asInstanceOf[JValue]
+ val rv4 = jv4.extract[Map[String,Int]]
+ println(rv4)
+ //分账之后总额应保持一致
+ var total = 0
+ for ((k, v) <- rv4) {
+ total += v
+ }
+ total should be(el)
+ }
+
+ }
+}