Merge branch 'dev_wuwei1972'

This commit is contained in:
wuwei1972 2018-07-27 15:56:47 +08:00
commit 5b1022cafc
31 changed files with 1972 additions and 1113 deletions

View File

@ -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"
)

BIN
jks/mykeystore_5.jks Normal file

Binary file not shown.

203
scripts/api_req/assets5.xml Normal file
View File

@ -0,0 +1,203 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ 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.
-->
<CSpec>
<stype>1</stype>
<idPath></idPath>
<idName></idName>
<iptFunc></iptFunc>
<iptArgs>
</iptArgs>
<timeout>0</timeout>
<secureContext>string</secureContext>
<code>
<![CDATA[
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)
}
}
]]>
</code>
<ctype>1</ctype>
</CSpec>

View File

@ -43,9 +43,8 @@ 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])
}
}

View File

@ -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){

View File

@ -24,6 +24,7 @@ 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))
}

View File

@ -132,7 +132,6 @@ object PeerHelper {
}catch{
case e:RuntimeException => throw e
}
t
}

View File

@ -53,7 +53,6 @@ object BlockHelper {
}catch{
case e:RuntimeException => throw e
}
}
/**
@ -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
}

View File

@ -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")
}
}

View File

@ -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)

View File

@ -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

View File

@ -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)
}
}

View File

@ -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)
}

View File

@ -120,6 +120,7 @@ public class pathUtil {
return l;
}
public static int bytesToInt(byte[] inputs){
if(inputs == null) return 0;
if(inputs.length < 4) return 0;

View File

@ -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])
}
}
}

View File

@ -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)
}
}
}

View File

@ -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)
}
}
}