Commit 5c0ea3b1 authored by 张振华's avatar 张振华

merge

parents e82c403e 227f5fbd
......@@ -5,9 +5,9 @@ dist: xenial
notifications:
email: false
jobs:
matrix:
include:
- stage: check_fmt
- name: check_fmt
sudo: require
go: "1.11.x"
install:
......@@ -20,20 +20,13 @@ jobs:
- make checkgofmt && make fmt_go
- make linter
- stage: unit-test
- name: unit-test
go: "1.9.x"
install: skip
script:
- make test
- stage: auto-test
go: "1.9.x"
install: skip
before_script: make build_ci
script:
- make autotest dapp=all
- stage: coverage
- name: coverage
if: branch = master
go: "1.9.x"
before_install:
......@@ -44,8 +37,14 @@ jobs:
after_success:
- bash <(curl -s https://codecov.io/bash)
- name: auto-test
go: "1.9.x"
install: skip
before_script: make build_ci
script:
- make autotest dapp=all
- stage: deploy
- name: deploy
if: env(DAPP) IS present
sudo: required
services:
......
......@@ -47,17 +47,34 @@ pipeline {
success {
echo 'I succeeeded!'
echo "email user: ${ghprbActualCommitAuthorEmail}"
mail to: "${ghprbActualCommitAuthorEmail}",
subject: "Successed Pipeline: ${currentBuild.fullDisplayName}",
body: "this is success with ${env.BUILD_URL}"
script{
try {
mail to: "${ghprbActualCommitAuthorEmail}",
subject: "Successed Pipeline: ${currentBuild.fullDisplayName}",
body: "this is success with ${env.BUILD_URL}"
}
catch (err){
echo 'email err'
}
}
echo currentBuild.result
}
failure {
echo 'I failed '
echo "email user: ${ghprbActualCommitAuthorEmail}"
mail to: "${ghprbActualCommitAuthorEmail}",
subject: "Failed Pipeline: ${currentBuild.fullDisplayName}",
body: "Something is wrong with ${env.BUILD_URL}"
script{
try {
mail to: "${ghprbActualCommitAuthorEmail}",
subject: "Failed Pipeline: ${currentBuild.fullDisplayName}",
body: "Something is wrong with ${env.BUILD_URL}"
}catch (err){
echo 'email err'
}
}
echo currentBuild.result
}
}
}
......@@ -23,6 +23,7 @@ NODE2="${1}_chain32_1"
NODE1="${1}_chain31_1"
NODE4="${1}_chain30_1"
#CLI4="docker exec ${NODE4} /root/chain33-cli"
NODE5="${1}_chain29_1"
CLI5="docker exec ${NODE5} /root/chain33-cli"
......@@ -99,7 +100,7 @@ function start() {
#docker-compose -f docker-compose.yml -f docker-compose-paracross.yml -f docker-compose-relay.yml up --build -d
docker-compose up --build -d
local SLEEP=30
local SLEEP=10
echo "=========== sleep ${SLEEP}s ============="
sleep ${SLEEP}
......@@ -111,26 +112,52 @@ function start() {
${CLI} net info
${CLI} net peer_info
peersCount=$(${CLI} net peer_info | jq '.[] | length')
echo "${peersCount}"
if [ "${peersCount}" -lt 2 ]; then
sleep 20
local count=100
while [ $count -gt 0 ]; do
peersCount=$(${CLI} net peer_info | jq '.[] | length')
echo "${peersCount}"
if [ "${peersCount}" -lt 2 ]; then
echo "peers error"
exit 1
if [ "${peersCount}" -ge 2 ]; then
break
fi
sleep 5
((count--))
echo "peers error: peersCount=${peersCount}"
done
miner "${CLI}"
block_wait "${CLI}" 1
echo "=========== check genesis hash ========== "
${CLI} block hash -t 0
res=$(${CLI} block hash -t 0 | jq ".hash")
count=$(echo "$res" | grep -c "0x67c58d6ba9175313f0468ae4e0ddec946549af7748037c2fdd5d54298afd20b6")
if [ "${count}" != 1 ]; then
echo "genesis hash error!"
exit 1
fi
echo "=========== query height ========== "
${CLI} block last_header
result=$(${CLI} block last_header | jq ".height")
if [ "${result}" -lt 1 ]; then
block_wait "${CLI}" 2
fi
sync_status "${CLI}"
${CLI} wallet status
${CLI} account list
${CLI} mempool list
}
function miner() {
#echo "=========== # create seed for wallet ============="
#seed=$(${CLI} seed generate -l 0 | jq ".seed")
#seed=$(${1} seed generate -l 0 | jq ".seed")
#if [ -z "${seed}" ]; then
# exit 1
#fi
echo "=========== # save seed to wallet ============="
result=$(${CLI} seed save -p 1314 -s "tortoise main civil member grace happy century convince father cage beach hip maid merry rib" | jq ".isok")
result=$(${1} seed save -p 1314 -s "tortoise main civil member grace happy century convince father cage beach hip maid merry rib" | jq ".isok")
if [ "${result}" = "false" ]; then
echo "save seed to wallet error seed, result: ${result}"
exit 1
......@@ -139,7 +166,7 @@ function start() {
sleep 1
echo "=========== # unlock wallet ============="
result=$(${CLI} wallet unlock -p 1314 -t 0 | jq ".isok")
result=$(${1} wallet unlock -p 1314 -t 0 | jq ".isok")
if [ "${result}" = "false" ]; then
exit 1
fi
......@@ -147,7 +174,7 @@ function start() {
sleep 1
echo "=========== # import private key returnAddr ============="
result=$(${CLI} account import_key -k CC38546E9E659D15E6B4893F0AB32A06D103931A8230B0BDE71459D2B27D6944 -l returnAddr | jq ".label")
result=$(${1} account import_key -k CC38546E9E659D15E6B4893F0AB32A06D103931A8230B0BDE71459D2B27D6944 -l returnAddr | jq ".label")
echo "${result}"
if [ -z "${result}" ]; then
exit 1
......@@ -156,7 +183,7 @@ function start() {
sleep 1
echo "=========== # import private key mining ============="
result=$(${CLI} account import_key -k 4257D8692EF7FE13C68B65D6A52F03933DB2FA5CE8FAF210B5B8B80C721CED01 -l minerAddr | jq ".label")
result=$(${1} account import_key -k 4257D8692EF7FE13C68B65D6A52F03933DB2FA5CE8FAF210B5B8B80C721CED01 -l minerAddr | jq ".label")
echo "${result}"
if [ -z "${result}" ]; then
exit 1
......@@ -164,36 +191,12 @@ function start() {
sleep 1
echo "=========== # close auto mining ============="
result=$(${CLI} wallet auto_mine -f 0 | jq ".isok")
result=$(${1} wallet auto_mine -f 0 | jq ".isok")
if [ "${result}" = "false" ]; then
exit 1
fi
block_wait "${CLI}" 1
echo "=========== check genesis hash ========== "
${CLI} block hash -t 0
res=$(${CLI} block hash -t 0 | jq ".hash")
count=$(echo "$res" | grep -c "0x67c58d6ba9175313f0468ae4e0ddec946549af7748037c2fdd5d54298afd20b6")
if [ "${count}" != 1 ]; then
echo "genesis hash error!"
exit 1
fi
echo "=========== query height ========== "
${CLI} block last_header
result=$(${CLI} block last_header | jq ".height")
if [ "${result}" -lt 1 ]; then
block_wait "${CLI}" 2
fi
sync_status "${CLI}"
${CLI} wallet status
${CLI} account list
${CLI} mempool list
}
function block_wait() {
if [ "$#" -lt 2 ]; then
echo "wrong block_wait params"
......@@ -215,7 +218,8 @@ function block_wait() {
function check_docker_status() {
status=$(docker-compose ps | grep chain33_1 | awk '{print $6}')
if [ "${status}" == "Exit" ]; then
statusPara=$(docker-compose ps | grep chain33_1 | awk '{print $3}')
if [ "${status}" == "Exit" ] || [ "${statusPara}" == "Exit" ]; then
echo "=========== chain33 service Exit logs ========== "
docker-compose logs chain33
echo "=========== chain33 service Exit logs End========== "
......
FROM ubuntu:16.04
WORKDIR /root
COPY chain33 ./
COPY chain33-cli ./
COPY autotest ./
COPY *.toml ./
CMD ["/root/chain33", "-f", "/root/chain33.toml"]
version: '3'
services:
chain33:
build:
context: .
dockerfile: Dockerfile-autotest
container_name: autotest-chain33
chain32:
build:
context: .
dockerfile: Dockerfile-autotest
container_name: autotest-chain32
#!/usr/bin/env bash
set -e
set -o pipefail
#set -o verbose
#set -o xtrace
# os: ubuntu16.04 x64
# first, you must install jq tool of json
# sudo apt-get install jq
# sudo apt-get install shellcheck, in order to static check shell script
# sudo apt-get install parallel
PWD=$(cd "$(dirname "$0")" && pwd)
export PATH="$PWD:$PATH"
CLI="./chain33-cli"
sedfix=""
if [ "$(uname)" == "Darwin" ]; then
sedfix=".bak"
fi
chain33Config="chain33.test.toml"
chain33BlockTime=2
function init() {
# update test environment
echo "# copy chain33 for solo test"
cp ../../chain33 ./
cp ../../chain33-cli ./
cp ../../../cmd/chain33/chain33.test.toml ./
}
function config_chain33() {
# shellcheck disable=SC2015
echo "# config chain33 solo test"
# update test environment
sed -i $sedfix 's/^Title.*/Title="local"/g' ${chain33Config}
# grep -q '^TestNet' ${chain33Config} && sed -i $sedfix 's/^TestNet.*/TestNet=true/' ${chain33Config} || sed -i '/^Title/a TestNet=true' ${chain33Config}
if grep -q '^TestNet' ${chain33Config}; then
sed -i $sedfix 's/^TestNet.*/TestNet=true/' ${chain33Config}
else
sed -i $sedfix '/^Title/a TestNet=true' ${chain33Config}
fi
#update fee
sed -i $sedfix 's/Fee=.*/Fee=100000/' ${chain33Config}
#update block time
#update wallet store driver
sed -i $sedfix '/^\[wallet\]/,/^\[wallet./ s/^driver.*/driver="leveldb"/' ${chain33Config}
}
autotestConfig="autotest.toml"
autotestTempConfig="autotest.temp.toml"
function config_autotest() {
#delete all blank lines
echo "# config autotest"
sed -i $sedfix '/^\s*$/d' ${autotestConfig}
if [[ $1 == "" ]] || [[ $1 == "all" ]]; then
cp ${autotestConfig} ${autotestTempConfig}
else
#copy config before [
sed -n '/^\[/!p;//q' ${autotestConfig} >${autotestTempConfig}
#copy specific dapp cofig
for dapp in "$@"; do
{
echo "[[TestCaseFile]]"
echo "contract=\"$dapp\""
echo "filename=\"$dapp.toml\""
} >>${autotestTempConfig}
done
fi
sed -i $sedfix 's/^checkSleepTime.*/checkSleepTime='${chain33BlockTime}'/' ${autotestTempConfig}
}
function start_chain33() {
echo "# start solo chain33, make sure there is no chain33 instance running"
rm -rf ../autotest/datadir ../autotest/logs ../autotest/grpc33.log
./chain33 -f chain33.test.toml >/dev/null 2>&1 &
local SLEEP=5
echo "=========== sleep ${SLEEP}s ============="
sleep ${SLEEP}
# query node run status
${CLI} block last_header
echo "=========== # save seed to wallet ============="
result=$(${CLI} seed save -p 1314 -s "tortoise main civil member grace happy century convince father cage beach hip maid merry rib" | jq ".isok")
if [ "${result}" = "false" ]; then
echo "save seed to wallet error seed, result: ${result}"
exit 1
fi
echo "=========== # unlock wallet ============="
result=$(${CLI} wallet unlock -p 1314 -t 0 | jq ".isok")
if [ "${result}" = "false" ]; then
exit 1
fi
echo "=========== # import private key returnAddr ============="
result=$(${CLI} account import_key -k CC38546E9E659D15E6B4893F0AB32A06D103931A8230B0BDE71459D2B27D6944 -l returnAddr | jq ".label")
echo "${result}"
if [ -z "${result}" ]; then
exit 1
fi
echo "=========== # import private key mining ============="
result=$(${CLI} account import_key -k 4257D8692EF7FE13C68B65D6A52F03933DB2FA5CE8FAF210B5B8B80C721CED01 -l minerAddr | jq ".label")
echo "${result}"
if [ -z "${result}" ]; then
exit 1
fi
echo "=========== # import test addr1 ============="
result=$(${CLI} account import_key -k 0x88b2fb90411935872f0501dd13345aba19b5fac9b00eb0dddd7df977d4d5477e -l test_addr1 | jq ".label")
echo "${result}"
if [ -z "${result}" ]; then
exit 1
fi
echo "=========== # import test addr2 ============="
result=$(${CLI} account import_key -k 0xa0c6f46de8d275ce21e935afa5363e9b8a087fe604e05f7a9eef1258dc781c3a -l test_addr2 | jq ".label")
echo "${result}"
if [ -z "${result}" ]; then
exit 1
fi
echo "=========== # import test addr3 ============="
result=$(${CLI} account import_key -k 0x9d4f8ab11361be596468b265cb66946c87873d4a119713fd0c3d8302eae0a8e4 -l test_addr3 | jq ".label")
echo "${result}"
if [ -z "${result}" ]; then
exit 1
fi
echo "=========== #transfer to miner addr ============="
hash=$(${CLI} send coins transfer -a 10000 -n test -t 12qyocayNF7Lv6C9qW4avxs2E7U41fKSfv -k CC38546E9E659D15E6B4893F0AB32A06D103931A8230B0BDE71459D2B27D6944)
sleep ${chain33BlockTime}
txs=$(${CLI} tx query_hash -s "${hash}" | jq ".txs")
if [ "${txs}" == "null" ]; then
echo "transferTokenAdmin cannot find tx"
exit 1
fi
echo "=========== #transfer to token amdin ============="
hash=$(${CLI} send coins transfer -a 10 -n test -t 1Q8hGLfoGe63efeWa8fJ4Pnukhkngt6poK -k CC38546E9E659D15E6B4893F0AB32A06D103931A8230B0BDE71459D2B27D6944)
sleep ${chain33BlockTime}
txs=$(${CLI} tx query_hash -s "${hash}" | jq ".txs")
if [ "${txs}" == "null" ]; then
echo "transferTokenAdmin cannot find tx"
exit 1
fi
echo "=========== #config token blacklist ============="
rawData=$(${CLI} config config_tx -k token-blacklist -o add -v BTC)
signData=$(${CLI} wallet sign -d "${rawData}" -k 0xc34b5d9d44ac7b754806f761d3d4d2c4fe5214f6b074c19f069c4f5c2a29c8cc)
hash=$(${CLI} wallet send -d "${signData}")
sleep ${chain33BlockTime}
txs=$(${CLI} tx query_hash -s "${hash}" | jq ".txs")
if [ "${txs}" == "null" ]; then
echo "transferTokenAdmin cannot find tx"
exit 1
fi
${CLI} wallet status
${CLI} account list
${CLI} mempool list
}
function start_autotest() {
echo "=========== #run autotest, make sure saving autotest.log.last file============="
if [ -e autotest.log ]; then
cat autotest.log >autotest.log.last
rm autotest.log
fi
./autotest -f ${autotestTempConfig}
}
function stop_chain33() {
echo "=========== #stop chain33 ============="
${CLI} close
#wait close
sleep ${chain33BlockTime}
}
function main() {
echo "==========================================main begin========================================================"
config_autotest "$@"
init
config_chain33
start_chain33
start_autotest
stop_chain33
echo "==========================================main end========================================================="
}
main "$@"
#!/usr/bin/env bash
set -e
set -o pipefail
#set -o verbose
#set -o xtrace
# os: ubuntu16.04 x64
# first, you must install jq tool of json
# sudo apt-get install jq
# sudo apt-get install shellcheck, in order to static check shell script
# sudo apt-get install parallel
# ./run-autotest.sh build
PWD=$(cd "$(dirname "$0")" && pwd)
export PATH="$PWD:$PATH"
PROJECT_NAME="${1}"
NODE3="autotest-chain33"
CLI="docker exec ${NODE3} /root/chain33-cli"
NODE2="autotest-chain32"
CLI2="docker exec ${NODE2} /root/chain33-cli"
sedfix=""
if [ "$(uname)" == "Darwin" ]; then
sedfix=".bak"
fi
function init() {
# update test environment
cp ../../chain33.toml ./
cp ../../chain33 ./
cp ../../chain33-cli ./
sed -i $sedfix 's/^Title.*/Title="local"/g' chain33.toml
sed -i $sedfix 's/^TestNet=.*/TestNet=true/g' chain33.toml
# p2p
sed -i $sedfix 's/^seeds=.*/seeds=["chain33:13802","chain32:13802"]/g' chain33.toml
#sed -i $sedfix 's/^enable=.*/enable=true/g' chain33.toml
sed -i $sedfix '0,/^enable=.*/s//enable=true/' chain33.toml
sed -i $sedfix 's/^isSeed=.*/isSeed=true/g' chain33.toml
sed -i $sedfix 's/^innerSeedEnable=.*/innerSeedEnable=false/g' chain33.toml
sed -i $sedfix 's/^useGithub=.*/useGithub=false/g' chain33.toml
# rpc
sed -i $sedfix 's/^jrpcBindAddr=.*/jrpcBindAddr="0.0.0.0:8801"/g' chain33.toml
sed -i $sedfix 's/^grpcBindAddr=.*/grpcBindAddr="0.0.0.0:8802"/g' chain33.toml
sed -i $sedfix 's/^whitelist=.*/whitelist=["localhost","127.0.0.1","0.0.0.0"]/g' chain33.toml
# wallet
sed -i $sedfix 's/^minerdisable=.*/minerdisable=false/g' chain33.toml
}
function start() {
# remove exsit container
docker-compose -p "${PROJECT_NAME}" -f compose-autotest.yml down --remove-orphans
# create and run docker-compose container
docker-compose -p "${PROJECT_NAME}" -f compose-autotest.yml up --build -d
local SLEEP=60
echo "=========== sleep ${SLEEP}s ============="
sleep ${SLEEP}
# docker-compose ps
docker-compose -p "${PROJECT_NAME}" -f compose-autotest.yml ps
# query node run status
${CLI} block last_header
${CLI} net info
${CLI} net peer_info
peersCount=$(${CLI} net peer_info | jq '.[] | length')
echo "${peersCount}"
if [ "${peersCount}" -lt 2 ]; then
echo "peers error"
exit 1
fi
#echo "=========== # create seed for wallet ============="
#seed=$(${CLI} seed generate -l 0 | jq ".seed")
#if [ -z "${seed}" ]; then
# echo "create seed error"
# exit 1
#fi
echo "=========== # save seed to wallet ============="
result=$(${CLI} seed save -p 1314 -s "tortoise main civil member grace happy century convince father cage beach hip maid merry rib" | jq ".isok")
if [ "${result}" = "false" ]; then
echo "save seed to wallet error seed, result: ${result}"
exit 1
fi
sleep 1
echo "=========== # unlock wallet ============="
result=$(${CLI} wallet unlock -p 1314 -t 0 | jq ".isok")
if [ "${result}" = "false" ]; then
exit 1
fi
echo "=========== # import private key returnAddr ============="
result=$(${CLI} account import_key -k CC38546E9E659D15E6B4893F0AB32A06D103931A8230B0BDE71459D2B27D6944 -l returnAddr | jq ".label")
echo "${result}"
if [ -z "${result}" ]; then
exit 1
fi
echo "=========== # import private key mining ============="
result=$(${CLI} account import_key -k 4257D8692EF7FE13C68B65D6A52F03933DB2FA5CE8FAF210B5B8B80C721CED01 -l minerAddr | jq ".label")
echo "${result}"
if [ -z "${result}" ]; then
exit 1
fi
echo "=========== # import test addr1 ============="
result=$(${CLI} account import_key -k 0x88b2fb90411935872f0501dd13345aba19b5fac9b00eb0dddd7df977d4d5477e -l test_addr1 | jq ".label")
echo "${result}"
if [ -z "${result}" ]; then
exit 1
fi
echo "=========== # import test addr2 ============="
result=$(${CLI} account import_key -k 0xa0c6f46de8d275ce21e935afa5363e9b8a087fe604e05f7a9eef1258dc781c3a -l test_addr2 | jq ".label")
echo "${result}"
if [ -z "${result}" ]; then
exit 1
fi
echo "=========== # import test addr3 ============="
result=$(${CLI} account import_key -k 0x9d4f8ab11361be596468b265cb66946c87873d4a119713fd0c3d8302eae0a8e4 -l test_addr3 | jq ".label")
echo "${result}"
if [ -z "${result}" ]; then
exit 1
fi
echo "=========== # close auto mining ============="
result=$(${CLI} wallet auto_mine -f 0 | jq ".isok")
if [ "${result}" = "false" ]; then
exit 1
fi
echo "=========== sleep ${SLEEP}s ============="
sleep ${SLEEP}
echo "=========== check genesis hash ========== "
${CLI} block hash -t 0
res=$(${CLI} block hash -t 0 | jq ".hash")
count=$(echo "$res" | grep -c "0x67c58d6ba9175313f0468ae4e0ddec946549af7748037c2fdd5d54298afd20b6")
if [ "${count}" != 1 ]; then
echo "genesis hash error!"
exit 1
fi
echo "=========== query height ========== "
${CLI} block last_header
result=$(${CLI} block last_header | jq ".height")
if [ "${result}" -lt 1 ]; then
exit 1
fi
sync_status "${CLI}"
${CLI} wallet status
${CLI} account list
${CLI} mempool list
}
function block_wait() {
if [ "$#" -lt 2 ]; then
echo "wrong block_wait params"
exit 1
fi
cur_height=$(${1} block last_header | jq ".height")
expect=$((cur_height + ${2}))
count=0
while true; do
new_height=$(${1} block last_header | jq ".height")
if [ "${new_height}" -ge "${expect}" ]; then
break
fi
count=$((count + 1))
sleep 1
done
echo "wait new block $count s"
}
function sync_status() {
echo "=========== query sync status========== "
local sync_status
local count=100
local wait_sec=0
while [ $count -gt 0 ]; do
sync_status=$(${1} net is_sync)
if [ "${sync_status}" = "true" ]; then
break
fi
((count--))
wait_sec=$((wait_sec + 1))
sleep 1
done
echo "sync wait ${wait_sec} s"
echo "=========== query clock sync status========== "
sync_status=$(${1} net is_clock_sync)
if [ "${sync_status}" = "false" ]; then
exit 1
fi
}
function sync() {
echo "=========== stop ${NODE2} node========== "
docker stop "${NODE2}"
sleep 20
echo "=========== start ${NODE2} node========== "
docker start "${NODE2}"
sleep 1
sync_status "${CLI2}"
}
function auto_test() {
echo "=========== #run auto test ============="
echo "=========== #transfer to token amdin ============="
hash=$(${CLI} send coins transfer -a 10 -n test -t 1Q8hGLfoGe63efeWa8fJ4Pnukhkngt6poK -k 4257D8692EF7FE13C68B65D6A52F03933DB2FA5CE8FAF210B5B8B80C721CED01)
block_wait "${CLI}" 2
txs=$(${CLI} tx query_hash -s "${hash}" | jq ".txs")
if [ "${txs}" == "null" ]; then
echo "transferTokenAdmin cannot find tx"
exit 1
fi
echo "=========== #config token blacklist ============="
rawData=$(${CLI} config config_tx -k token-blacklist -o add -v BTC)
signData=$(${CLI} wallet sign -d "${rawData}" -k 0xc34b5d9d44ac7b754806f761d3d4d2c4fe5214f6b074c19f069c4f5c2a29c8cc)
hash=$(${CLI} wallet send -d "${signData}")
block_wait "${CLI}" 2
echo "=========== #start auto-test program ============="
docker exec "${NODE3}" /root/autotest
}
function stop() {
echo "=========== #stop docker-compose ============="
docker cp "${NODE3}":/root/autotest.log ./
docker-compose -p "${PROJECT_NAME}" -f compose-autotest.yml down && rm ./chain33* && rm ./*.toml
}
function main() {
echo "==========================================main begin========================================================"
init
start
auto_test
stop
echo "==========================================main end========================================================="
}
# check args
if [ "$#" -ne 1 ]; then
echo "Suggest Usage: $0 build"
exit 1
fi
# run script
main
......@@ -60,7 +60,27 @@ whitelist=["127.0.0.1"]
jrpcFuncWhitelist=["*"]
grpcFuncWhitelist=["*"]
[mempool]
name="timeline"
poolCacheSize=10240
minTxFee=100000
maxTxNumPerAccount=10000
[mempool.sub.timeline]
poolCacheSize=10240
minTxFee=100000
maxTxNumPerAccount=10000
[mempool.sub.score]
poolCacheSize=10240
minTxFee=100000
maxTxNumPerAccount=10000
timeParam=1 #时间占价格比例
priceConstant=1544 #手续费相对于时间的一个合适的常量,取当前unxi时间戳前四位数,排序时手续费高1e-5~=快1s
pricePower=1 #常量比例
[mempool.sub.price]
poolCacheSize=10240
minTxFee=100000
maxTxNumPerAccount=10000
......
This diff is collapsed.
# para
#支持主节点在云端,且允许自由切换,负载均衡
1. 平行链主节点设置在云端作为一个集群,提供统一ip和端口
## 场景
1. 主节点集群同步主网数据,各主节点保持独立
1. 某主节点挂掉,云端自动切换到新的主节点,平行链节点需要检查在新节点获取到的区块和之前的区块hash保持一致,一致指的是新区块是add type,parentHash和之前的
主链hash相同,del type的区块hash和之前主链的hash相同
1. 如果不一致,搜索平行链记录的主节点blockHash在新主节点上的seq作为下一个seq获取tx
1. 如果当前平行链block的mainBlockHash在新节点上找不到,可能是分叉的场景,需要找到分叉处,把以后的平行链block删除,从分叉处下一个seq同步平行链数据
## 测试场景
1. 平行链在blockHeight=1之前主节点切换,平行链重新从seq=startSeq处同步数据(startSeq=0 or 非0场景)
1. 主节点切换,新的主节点seq和blockhash和老的完全一致
1. 主节点切换, 老的blockhash在新的节点上找不到,平行链最后一个节点的mainHash可以找到
1. 主节点切换, 老的blockhash在新的节点上找不到,平行链最后一个节点的mainHash找不到,回退查找到,删除分叉后节点重新同步
1. 主节点切换, 老的blockhash在新的节点上找不到,平行链最后一个节点的mainHash找不到,回退查找到,删除分叉节点中间失败,重新查找同步
1. 主节点切换, 老的blockhash在新的节点上找不到,平行链所有节点都找不到场景,会无限循环查找,直到切换新主节点
1. 系统重启,主节点切换场景
......@@ -19,6 +19,7 @@ import (
var (
Amount = int64(1 * types.Coin)
Title = string("user.p.para.")
Title2 = string("user.p.test.")
)
func TestFilterTxsForPara(t *testing.T) {
......@@ -72,6 +73,10 @@ func TestFilterTxsForPara(t *testing.T) {
txGroupBC, err := createTxsGroup(txBC)
assert.Nil(t, err)
//single para tx
txD, err := createCrossParaTempTx("toB", 10)
assert.Nil(t, err)
txs := []*types.Transaction{tx0}
txs = append(txs, txGroup12...)
txs = append(txs, txGroup34...)
......@@ -79,6 +84,7 @@ func TestFilterTxsForPara(t *testing.T) {
txs = append(txs, txGroup78...)
txs = append(txs, tx9, txA)
txs = append(txs, txGroupBC...)
txs = append(txs, txD)
//for i, tx := range txs {
// t.Log("tx exec name", "i", i, "name", string(tx.Execer))
......@@ -101,8 +107,9 @@ func TestFilterTxsForPara(t *testing.T) {
recptA := &types.ReceiptData{Ty: types.ExecPack}
recptB := &types.ReceiptData{Ty: types.ExecPack}
recptC := &types.ReceiptData{Ty: types.ExecPack}
recptD := &types.ReceiptData{Ty: types.ExecPack}
receipts := []*types.ReceiptData{recpt0, recpt1, recpt2, recpt3, recpt4, recpt5,
recpt6, recpt7, recpt8, recpt9, recptA, recptB, recptC}
recpt6, recpt7, recpt8, recpt9, recptA, recptB, recptC, recptD}
block := &types.Block{Txs: txs}
detail := &types.BlockDetail{
......@@ -187,6 +194,22 @@ func createCrossParaTx(to string, amount int64) (*types.Transaction, error) {
return tx, err
}
func createCrossParaTempTx(to string, amount int64) (*types.Transaction, error) {
param := types.CreateTx{
To: string(to),
Amount: amount,
Fee: 0,
Note: []byte("test asset transfer"),
IsWithdraw: false,
IsToken: false,
TokenSymbol: "",
ExecName: Title2 + pt.ParaX,
}
tx, err := pt.CreateRawAssetTransferTx(&param)
return tx, err
}
func createTxsGroup(txs []*types.Transaction) ([]*types.Transaction, error) {
group, err := types.CreateTxGroup(txs)
......
......@@ -342,14 +342,10 @@ func (client *commitMsgClient) getNodeStatus(start, end int64) ([]*pt.ParacrossN
keys.Keys = append(keys.Keys, key)
}
msg := client.paraClient.GetQueueClient().NewMessage("blockchain", types.EventLocalGet, keys)
client.paraClient.GetQueueClient().Send(msg, true)
resp, err := client.paraClient.GetQueueClient().Wait(msg)
r, err := client.paraClient.GetAPI().LocalGet(keys)
if err != nil {
return nil, err
}
r := resp.GetData().(*types.LocalReplyValue)
if count != int64(len(r.Values)) {
plog.Error("paracommitmsg get node status key", "expect count", count, "actual count", len(r.Values))
return nil, err
......@@ -375,13 +371,10 @@ func (client *commitMsgClient) getNodeStatus(start, end int64) ([]*pt.ParacrossN
}
}
msg = client.paraClient.GetQueueClient().NewMessage("blockchain", types.EventGetBlocks, req)
client.paraClient.GetQueueClient().Send(msg, true)
resp, err = client.paraClient.GetQueueClient().Wait(msg)
v, err := client.paraClient.GetAPI().GetBlocks(req)
if err != nil {
return nil, err
}
v := resp.GetData().(*types.BlockDetails)
if count != int64(len(v.Items)) {
plog.Error("paracommitmsg get node status block", "expect count", count, "actual count", len(v.Items))
return nil, err
......@@ -405,13 +398,10 @@ func (client *commitMsgClient) getNodeStatus(start, end int64) ([]*pt.ParacrossN
func (client *commitMsgClient) getGenesisNodeStatus() (*pt.ParacrossNodeStatus, error) {
var status pt.ParacrossNodeStatus
req := &types.ReqBlocks{Start: 0, End: 0}
msg := client.paraClient.GetQueueClient().NewMessage("blockchain", types.EventGetBlocks, req)
client.paraClient.GetQueueClient().Send(msg, true)
resp, err := client.paraClient.GetQueueClient().Wait(msg)
v, err := client.paraClient.GetAPI().GetBlocks(req)
if err != nil {
return nil, err
}
v := resp.GetData().(*types.BlockDetails)
block := v.Items[0].Block
if block.Height != 0 {
return nil, errors.New("block chain not return 0 height block")
......@@ -543,30 +533,3 @@ out:
}
}
func checkMinerTx(current *types.BlockDetail) error {
//检查第一个笔交易的execs, 以及执行状态
if len(current.Block.Txs) == 0 {
return types.ErrEmptyTx
}
baseTx := current.Block.Txs[0]
//判断交易类型和执行情况
var action paracross.ParacrossAction
err := types.Decode(baseTx.GetPayload(), &action)
if err != nil {
return err
}
if action.GetTy() != paracross.ParacrossActionMiner {
return paracross.ErrParaMinerTxType
}
//判断交易执行是否OK
if action.GetMiner() == nil {
return paracross.ErrParaEmptyMinerTx
}
//判断exec 是否成功
if current.Receipts[0].Ty != types.ExecOk {
return paracross.ErrParaMinerExecErr
}
return nil
}
......@@ -48,7 +48,7 @@ type suiteParaCommitMsg struct {
block *blockchain.BlockChain
exec *executor.Executor
store queue.Module
mem *mempool.Mempool
mem queue.Module
network *p2p.P2p
}
......@@ -72,6 +72,17 @@ func (s *suiteParaCommitMsg) initEnv(cfg *types.Config, sub *types.ConfigSubModu
s.store.SetQueueClient(q.Client())
s.para = New(cfg.Consensus, sub.Consensus["para"]).(*client)
s.grpcCli = &typesmocks.Chain33Client{}
blockHash := &types.BlockSequence{
Hash: []byte("1"),
Type: 1,
}
blockSeqs := &types.BlockSequences{Items: []*types.BlockSequence{blockHash}}
s.grpcCli.On("GetBlockSequences", mock.Anything, mock.Anything).Return(blockSeqs, errors.New("nil"))
block := &types.Block{}
blockDetail := &types.BlockDetail{Block: block}
blockDetails := &types.BlockDetails{Items: []*types.BlockDetail{blockDetail}}
s.grpcCli.On("GetBlockByHashes", mock.Anything, mock.Anything).Return(blockDetails, errors.New("nil"))
//data := &types.Int64{1}
s.grpcCli.On("GetLastBlockSequence", mock.Anything, mock.Anything).Return(nil, errors.New("nil"))
reply := &types.Reply{IsOk: true}
......@@ -84,17 +95,15 @@ func (s *suiteParaCommitMsg) initEnv(cfg *types.Config, sub *types.ConfigSubModu
s.para.grpcClient = s.grpcCli
s.para.SetQueueClient(q.Client())
s.mem = mempool.New(cfg.MemPool)
s.mem = mempool.New(cfg.Mempool, nil)
s.mem.SetQueueClient(q.Client())
s.mem.SetSync(true)
s.mem.WaitPollLastHeader()
s.mem.Wait()
s.network = p2p.New(cfg.P2P)
s.network.SetQueueClient(q.Client())
s.para.wg.Add(1)
go walletProcess(q, s.para)
}
func walletProcess(q queue.Queue, para *client) {
......
// Copyright Fuzamei Corp. 2018 All Rights Reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package para
import (
"testing"
"github.com/33cn/chain33/blockchain"
"github.com/33cn/chain33/common/log"
"github.com/33cn/chain33/executor"
"github.com/33cn/chain33/mempool"
"github.com/33cn/chain33/p2p"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/suite"
//"github.com/33cn/plugin/plugin/dapp/paracross/rpc"
"time"
"github.com/33cn/chain33/queue"
"github.com/33cn/chain33/store"
_ "github.com/33cn/chain33/system"
"github.com/33cn/chain33/types"
typesmocks "github.com/33cn/chain33/types/mocks"
pt "github.com/33cn/plugin/plugin/dapp/paracross/types"
)
func init() {
//types.Init("user.p.para.", nil)
log.SetLogLevel("debug")
}
type suiteParaClient struct {
// Include our basic suite logic.
suite.Suite
para *client
grpcCli *typesmocks.Chain33Client
q queue.Queue
block *blockchain.BlockChain
exec *executor.Executor
store queue.Module
mem queue.Module
network *p2p.P2p
}
func (s *suiteParaClient) initEnv(cfg *types.Config, sub *types.ConfigSubModule) {
q := queue.New("channel")
s.q = q
//api, _ = client.New(q.Client(), nil)
s.block = blockchain.New(cfg.BlockChain)
s.block.SetQueueClient(q.Client())
s.exec = executor.New(cfg.Exec, sub.Exec)
s.exec.SetQueueClient(q.Client())
s.store = store.New(cfg.Store, sub.Store)
s.store.SetQueueClient(q.Client())
cfg.Consensus.StartHeight = 0
cfg.Consensus.EmptyBlockInterval = 1
s.para = New(cfg.Consensus, sub.Consensus["para"]).(*client)
s.grpcCli = &typesmocks.Chain33Client{}
blockHash := &types.BlockSequence{
Hash: []byte("1"),
Type: 1,
}
blockSeqs := &types.BlockSequences{Items: []*types.BlockSequence{blockHash}}
s.grpcCli.On("GetBlockSequences", mock.Anything, mock.Anything).Return(blockSeqs, nil)
block := &types.Block{Height: 0}
blockDetail := &types.BlockDetail{Block: block}
blockDetails := &types.BlockDetails{Items: []*types.BlockDetail{blockDetail}}
s.grpcCli.On("GetBlockByHashes", mock.Anything, mock.Anything).Return(blockDetails, nil).Once()
block = &types.Block{Height: 6, BlockTime: 8888888888}
blockDetail = &types.BlockDetail{Block: block}
blockDetails = &types.BlockDetails{Items: []*types.BlockDetail{blockDetail}}
s.grpcCli.On("GetBlockByHashes", mock.Anything, mock.Anything).Return(blockDetails, nil).Once()
block = &types.Block{Height: 0}
blockDetail = &types.BlockDetail{Block: block}
blockDetails = &types.BlockDetails{Items: []*types.BlockDetail{blockDetail}}
s.grpcCli.On("GetBlockByHashes", mock.Anything, mock.Anything).Return(blockDetails, nil).Once()
block = &types.Block{Height: 0}
blockDetail = &types.BlockDetail{Block: block}
blockDetails = &types.BlockDetails{Items: []*types.BlockDetail{blockDetail}}
s.grpcCli.On("GetBlockByHashes", mock.Anything, mock.Anything).Return(blockDetails, nil)
seq := &types.Int64{Data: 1}
s.grpcCli.On("GetLastBlockSequence", mock.Anything, mock.Anything).Return(seq, nil).Once()
seq = &types.Int64{Data: 2}
s.grpcCli.On("GetLastBlockSequence", mock.Anything, mock.Anything).Return(seq, nil).Once()
seq = &types.Int64{Data: 3}
s.grpcCli.On("GetLastBlockSequence", mock.Anything, mock.Anything).Return(seq, nil)
seq = &types.Int64{Data: 1}
s.grpcCli.On("GetSequenceByHash", mock.Anything, mock.Anything).Return(seq, nil)
reply := &types.Reply{IsOk: true}
s.grpcCli.On("IsSync", mock.Anything, mock.Anything).Return(reply, nil)
result := &pt.ParacrossStatus{Height: -1}
data := types.Encode(result)
ret := &types.Reply{IsOk: true, Msg: data}
s.grpcCli.On("QueryChain", mock.Anything, mock.Anything).Return(ret, nil).Maybe()
s.grpcCli.On("SendTransaction", mock.Anything, mock.Anything).Return(reply, nil).Maybe()
s.para.grpcClient = s.grpcCli
s.para.SetQueueClient(q.Client())
s.mem = mempool.New(cfg.Mempool, nil)
s.mem.SetQueueClient(q.Client())
s.mem.Wait()
s.network = p2p.New(cfg.P2P)
s.network.SetQueueClient(q.Client())
}
func (s *suiteParaClient) TestRun_Test() {
//s.testGetBlock()
lastBlock, err := s.para.RequestLastBlock()
if err != nil {
plog.Error("para test", "err", err.Error())
}
plog.Info("para test---------1", "last height", lastBlock.Height)
s.para.createBlock(lastBlock, nil, 0, getMainBlock(2, lastBlock.BlockTime+1))
lastBlock, err = s.para.RequestLastBlock()
if err != nil {
plog.Error("para test--2", "err", err.Error())
}
plog.Info("para test---------", "last height", lastBlock.Height)
s.para.createBlock(lastBlock, nil, 1, getMainBlock(3, lastBlock.BlockTime+1))
time.Sleep(time.Second * 1)
s.testRunGetMinerTxInfo()
s.testRunRmvBlock()
}
func (s *suiteParaClient) testRunGetMinerTxInfo() {
lastBlock, err := s.para.RequestLastBlock()
s.Nil(err)
plog.Info("para test testRunGetMinerTxInfo", "last height", lastBlock.Height)
s.True(lastBlock.Height > 1)
status, err := getMinerTxInfo(lastBlock)
s.Nil(err)
s.Equal(int64(3), status.MainBlockHeight)
}
func (s *suiteParaClient) testRunRmvBlock() {
lastBlock, err := s.para.RequestLastBlock()
s.Nil(err)
plog.Info("para test testRunGetMinerTxInfo", "last height", lastBlock.Height)
s.True(lastBlock.Height > 1)
s.para.removeBlocks(1)
lastBlock, err = s.para.RequestLastBlock()
s.Nil(err)
plog.Info("para test testRunGetMinerTxInfo", "last height", lastBlock.Height)
s.Equal(int64(1), lastBlock.Height)
}
func (s *suiteParaClient) SetupSuite() {
s.initEnv(types.InitCfg("../../../plugin/dapp/paracross/cmd/build/chain33.para.test.toml"))
}
func TestRunSuiteParaClient(t *testing.T) {
log := new(suiteParaClient)
suite.Run(t, log)
}
func (s *suiteParaClient) TearDownSuite() {
time.Sleep(time.Second * 5)
s.block.Close()
s.para.Close()
s.network.Close()
s.exec.Close()
s.store.Close()
s.mem.Close()
s.q.Close()
}
......@@ -51,6 +51,7 @@ verMix=118
verMax=119
[mempool]
name="timeline"
poolCacheSize=10240
minTxFee=100000
......
......@@ -62,14 +62,14 @@ func TestPbft(t *testing.T) {
clearTestData()
}
func initEnvPbft() (queue.Queue, *blockchain.BlockChain, *p2p.P2p, queue.Module, *mempool.Mempool, queue.Module, queue.Module, queue.Module) {
func initEnvPbft() (queue.Queue, *blockchain.BlockChain, *p2p.P2p, queue.Module, queue.Module, *executor.Executor, queue.Module, queue.Module) {
var q = queue.New("channel")
flag.Parse()
cfg, sub := types.InitCfg("chain33.test.toml")
types.Init(cfg.Title, cfg)
chain := blockchain.New(cfg.BlockChain)
chain.SetQueueClient(q.Client())
mem := mempool.New(cfg.MemPool)
mem := mempool.New(cfg.Mempool, nil)
mem.SetQueueClient(q.Client())
exec := executor.New(cfg.Exec, sub.Exec)
exec.SetQueueClient(q.Client())
......
......@@ -59,6 +59,7 @@ jrpcFuncWhitelist=["*"]
grpcFuncWhitelist=["*"]
[mempool]
name="timeline"
poolCacheSize=10240
minTxFee=100000
......
......@@ -63,7 +63,7 @@ func RaftPerf() {
sendReplyList(q)
}
func initEnvRaft() (queue.Queue, *blockchain.BlockChain, queue.Module, *mempool.Mempool, queue.Module, queue.Module, queue.Module) {
func initEnvRaft() (queue.Queue, *blockchain.BlockChain, queue.Module, queue.Module, *executor.Executor, queue.Module, queue.Module) {
var q = queue.New("channel")
flag.Parse()
cfg, sub := types.InitCfg("chain33.test.toml")
......@@ -80,7 +80,7 @@ func initEnvRaft() (queue.Queue, *blockchain.BlockChain, queue.Module, *mempool.
cs := NewRaftCluster(cfg.Consensus, sub.Consensus["raft"])
cs.SetQueueClient(q.Client())
mem := mempool.New(cfg.MemPool)
mem := mempool.New(cfg.Mempool, nil)
mem.SetQueueClient(q.Client())
network := p2p.New(cfg.P2P)
......
......@@ -60,6 +60,7 @@ jrpcFuncWhitelist=["*"]
grpcFuncWhitelist=["*"]
[mempool]
name="timeline"
poolCacheSize=10240
minTxFee=100000
......
......@@ -76,7 +76,7 @@ func RaftPerf() {
time.Sleep(10 * time.Second)
}
func initEnvTendermint() (queue.Queue, *blockchain.BlockChain, queue.Module, *mempool.Mempool, queue.Module, queue.Module, queue.Module) {
func initEnvTendermint() (queue.Queue, *blockchain.BlockChain, queue.Module, queue.Module, *executor.Executor, queue.Module, queue.Module) {
var q = queue.New("channel")
flag.Parse()
cfg, sub := types.InitCfg("chain33.test.toml")
......@@ -93,7 +93,7 @@ func initEnvTendermint() (queue.Queue, *blockchain.BlockChain, queue.Module, *me
cs := New(cfg.Consensus, sub.Consensus["tendermint"])
cs.SetQueueClient(q.Client())
mem := mempool.New(cfg.MemPool)
mem := mempool.New(cfg.Mempool, nil)
mem.SetQueueClient(q.Client())
network := p2p.New(cfg.P2P)
......
......@@ -60,6 +60,7 @@ jrpcFuncWhitelist=["*"]
grpcFuncWhitelist=["*"]
[mempool]
name="timeline"
poolCacheSize=10240
minTxFee=100000
maxTxNumPerAccount=10000
......
......@@ -201,6 +201,11 @@ func (client *Client) setTicket(tlist *ty.ReplyTicketList, privmap map[string]cr
client.ticketmu.Lock()
defer client.ticketmu.Unlock()
client.ticketsMap = make(map[string]*ty.Ticket)
if tlist == nil || privmap == nil {
client.ticketsMap = nil
client.privmap = nil
return
}
for _, ticket := range tlist.Tickets {
client.ticketsMap[ticket.GetTicketId()] = ticket
}
......@@ -212,12 +217,12 @@ func (client *Client) setTicket(tlist *ty.ReplyTicketList, privmap map[string]cr
func (client *Client) flushTicket() error {
//list accounts
tickets, privs, err := client.getTickets()
if err == types.ErrMinerNotStared {
tlog.Error("flushTicket error", "err", "wallet miner not start")
if err == types.ErrWalletIsLocked {
tlog.Error("flushTicket error", "err", "wallet is locked")
client.setTicket(nil, nil)
return nil
}
if err != nil && err != types.ErrMinerNotStared {
if err != nil {
tlog.Error("flushTicket error", "err", err)
return err
}
......
......@@ -104,11 +104,29 @@ func TestTicketMap(t *testing.T) {
{TicketId: "3333"},
{TicketId: "4444"},
}
privmap := make(map[string]crypto.PrivKey)
//通过privkey生成一个pubkey然后换算成对应的addr
cr, _ := crypto.New("secp256k1")
priv, _ := cr.PrivKeyFromBytes([]byte("2116459C0EC8ED01AA0EEAE35CAC5C96F94473F7816F114873291217303F6989"))
privmap["1111"] = priv
privmap["2222"] = priv
privmap["3333"] = priv
privmap["4444"] = priv
assert.Equal(t, c.getTicketCount(), int64(0))
c.setTicket(ticketList, nil)
c.setTicket(ticketList, privmap)
assert.Equal(t, c.getTicketCount(), int64(4))
c.delTicket("3333")
assert.Equal(t, c.getTicketCount(), int64(3))
c.setTicket(ticketList, nil)
assert.Equal(t, c.getTicketCount(), int64(0))
c.setTicket(nil, privmap)
assert.Equal(t, c.getTicketCount(), int64(0))
c.setTicket(nil, nil)
assert.Equal(t, c.getTicketCount(), int64(0))
}
func TestProcEvent(t *testing.T) {
......
......@@ -131,15 +131,19 @@ func (mdb *MemoryStateDB) GetBalance(addr string) uint64 {
isExec := mdb.Exist(addr)
var ac *types.Account
if isExec {
contract := mdb.GetAccount(addr)
if contract == nil {
return 0
}
creator := contract.GetCreator()
if len(creator) == 0 {
return 0
if types.IsDappFork(mdb.GetBlockHeight(), "evm", evmtypes.ForkEVMFrozen) {
ac = mdb.CoinsAccount.LoadExecAccount(addr, addr)
} else {
contract := mdb.GetAccount(addr)
if contract == nil {
return 0
}
creator := contract.GetCreator()
if len(creator) == 0 {
return 0
}
ac = mdb.CoinsAccount.LoadExecAccount(creator, addr)
}
ac = mdb.CoinsAccount.LoadExecAccount(creator, addr)
} else {
ac = mdb.CoinsAccount.LoadAccount(addr)
}
......@@ -439,6 +443,7 @@ func (mdb *MemoryStateDB) CanTransfer(sender, recipient string, amount uint64) b
case NoNeed:
return true
case ToExec:
// 无论其它账户还是创建者向合约地址转账,都需要检查其当前合约账户活动余额是否充足
accFrom := mdb.CoinsAccount.LoadExecAccount(sender, recipient)
b := accFrom.GetBalance() - value
if b < 0 {
......@@ -452,8 +457,7 @@ func (mdb *MemoryStateDB) CanTransfer(sender, recipient string, amount uint64) b
return false
}
}
func (mdb *MemoryStateDB) checkExecAccount(addr string, value int64) bool {
func (mdb *MemoryStateDB) checkExecAccount(execAddr string, value int64) bool {
var err error
defer func() {
if err != nil {
......@@ -465,7 +469,7 @@ func (mdb *MemoryStateDB) checkExecAccount(addr string, value int64) bool {
err = types.ErrAmount
return false
}
contract := mdb.GetAccount(addr)
contract := mdb.GetAccount(execAddr)
if contract == nil {
err = model.ErrAddrNotExists
return false
......@@ -476,9 +480,16 @@ func (mdb *MemoryStateDB) checkExecAccount(addr string, value int64) bool {
return false
}
accFrom := mdb.CoinsAccount.LoadExecAccount(contract.GetCreator(), addr)
b := accFrom.GetBalance() - value
if b < 0 {
var accFrom *types.Account
if types.IsDappFork(mdb.GetBlockHeight(), "evm", evmtypes.ForkEVMFrozen) {
// 分叉后,需要检查合约地址下的金额是否足够
accFrom = mdb.CoinsAccount.LoadExecAccount(execAddr, execAddr)
} else {
accFrom = mdb.CoinsAccount.LoadExecAccount(creator, execAddr)
}
balance := accFrom.GetBalance()
remain := balance - value
if remain < 0 {
err = types.ErrNoBalance
return false
}
......@@ -600,17 +611,28 @@ func (mdb *MemoryStateDB) transfer2Contract(sender, recipient string, amount int
}
execAddr := recipient
// 从自己的合约账户到创建者的合约账户
// 有可能是外部账户调用自己创建的合约,这种情况下这一步可以省略
ret = &types.Receipt{}
if strings.Compare(sender, creator) != 0 {
rs, err := mdb.CoinsAccount.ExecTransfer(sender, creator, execAddr, amount)
if types.IsDappFork(mdb.GetBlockHeight(), "evm", evmtypes.ForkEVMFrozen) {
// 用户向合约转账时,将钱转到合约地址下execAddr:execAddr
rs, err := mdb.CoinsAccount.ExecTransfer(sender, execAddr, execAddr, amount)
if err != nil {
return nil, err
}
ret.KV = append(ret.KV, rs.KV...)
ret.Logs = append(ret.Logs, rs.Logs...)
} else {
if strings.Compare(sender, creator) != 0 {
// 用户向合约转账时,首先将钱转到创建者合约地址下
rs, err := mdb.CoinsAccount.ExecTransfer(sender, creator, execAddr, amount)
if err != nil {
return nil, err
}
ret.KV = append(ret.KV, rs.KV...)
ret.Logs = append(ret.Logs, rs.Logs...)
}
}
return ret, nil
......@@ -631,24 +653,22 @@ func (mdb *MemoryStateDB) transfer2External(sender, recipient string, amount int
execAddr := sender
// 第一步先从创建者的合约账户到接受者的合约账户
// 如果是自己调用自己创建的合约,这一步也可以省略
if strings.Compare(creator, recipient) != 0 {
ret, err = mdb.CoinsAccount.ExecTransfer(creator, recipient, execAddr, amount)
if types.IsDappFork(mdb.GetBlockHeight(), "evm", evmtypes.ForkEVMFrozen) {
// 合约向用户地址转账时,从合约地址下的钱中转出到用户合约地址
ret, err = mdb.CoinsAccount.ExecTransfer(execAddr, recipient, execAddr, amount)
if err != nil {
return nil, err
}
} else {
// 第一步先从创建者的合约账户到接受者的合约账户
// 如果是自己调用自己创建的合约,这一步也可以省略
if strings.Compare(creator, recipient) != 0 {
ret, err = mdb.CoinsAccount.ExecTransfer(creator, recipient, execAddr, amount)
if err != nil {
return nil, err
}
}
}
// 第二步再从接收者的合约账户取款到接受者账户
// 本操作不允许,需要外部操作coins账户
//rs, err := mdb.CoinsAccount.TransferWithdraw(recipient.String(), sender.String(), amount)
//if err != nil {
// return nil, err
//}
//
//ret = mdb.mergeResult(ret, rs)
return ret, nil
}
......
......@@ -38,6 +38,8 @@ func init() {
types.RegisterDappFork(ExecutorName, ForkEVMKVHash, 1000000)
// EVM合约支持ABI绑定和调用
types.RegisterDappFork(ExecutorName, ForkEVMABI, 1250000)
// EEVM合约用户金额冻结
types.RegisterDappFork(ExecutorName, ForkEVMFrozen, 1300000)
}
// EvmType EVM类型定义
......@@ -52,6 +54,11 @@ func NewType() *EvmType {
return c
}
// GetName 获取执行器名称
func (evm *EvmType) GetName() string {
return ExecutorName
}
// GetPayload 获取消息负载结构
func (evm *EvmType) GetPayload() types.Message {
return &EVMContractAction{}
......
......@@ -38,6 +38,8 @@ const (
ForkEVMKVHash = "ForkEVMKVHash"
// ForkEVMABI EVM合约支持ABI绑定和调用
ForkEVMABI = "ForkEVMABI"
// ForkEVMFrozen EVM合约用户金额冻结
ForkEVMFrozen = "ForkEVMFrozen"
)
var (
......
......@@ -42,6 +42,11 @@ type GameType struct {
types.ExecTypeBase
}
// GetName 获取执行器名称
func (gt *GameType) GetName() string {
return GameX
}
// GetLogMap get log
func (gt *GameType) GetLogMap() map[int64]*types.LogInfo {
return map[int64]*types.LogInfo{
......
/*
* Copyright Fuzamei Corp. 2018 All Rights Reserved.
* Use of this source code is governed by a BSD-style
* license that can be found in the LICENSE file.
*/
package types
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestCreateRawGamePreCreateTx(t *testing.T) {
param := &GamePreCreateTx{
Amount: 100,
HashType: "SHA256",
}
tx, err := CreateRawGamePreCreateTx(param)
assert.Nil(t, err)
assert.NotNil(t, tx)
assert.Equal(t, []byte(GameX), tx.Execer)
assert.NotEqual(t, 0, tx.Fee)
}
func TestCreateRawGamePreMatchTx(t *testing.T) {
param := &GamePreMatchTx{
GameID: "xxxxxxxxxxxxxxxxxxxxxxxxxx",
Guess: 1,
}
tx, err := CreateRawGamePreMatchTx(param)
assert.Nil(t, err)
assert.NotNil(t, tx)
assert.Equal(t, []byte(GameX), tx.Execer)
assert.NotEqual(t, 0, tx.Fee)
}
func TestCreateRawGamePreCloseTx(t *testing.T) {
param := &GamePreCloseTx{
GameID: "xxxxxxxxxxxxxxxxxxxxxxxxxx",
Result: 1,
}
tx, err := CreateRawGamePreCloseTx(param)
assert.Nil(t, err)
assert.NotNil(t, tx)
assert.Equal(t, []byte(GameX), tx.Execer)
assert.NotEqual(t, 0, tx.Fee)
}
func TestCreateRawGamePreCancelTx(t *testing.T) {
param := &GamePreCancelTx{
GameID: "xxxxxxxxxxxxxxxxxxxxxxxxxx",
}
tx, err := CreateRawGamePreCancelTx(param)
assert.Nil(t, err)
assert.NotNil(t, tx)
assert.Equal(t, []byte(GameX), tx.Execer)
assert.NotEqual(t, 0, tx.Fee)
}
// Copyright Fuzamei Corp. 2018 All Rights Reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package rpc_test
import (
"strings"
"testing"
commonlog "github.com/33cn/chain33/common/log"
"github.com/33cn/chain33/rpc/jsonclient"
"github.com/33cn/chain33/types"
"github.com/33cn/chain33/util/testnode"
pty "github.com/33cn/plugin/plugin/dapp/pokerbull/types"
"github.com/stretchr/testify/assert"
_ "github.com/33cn/chain33/system"
_ "github.com/33cn/plugin/plugin"
)
func init() {
commonlog.SetLogLevel("error")
}
func TestJRPCChannel(t *testing.T) {
// 启动RPCmocker
mocker := testnode.New("--notset--", nil)
defer func() {
mocker.Close()
}()
mocker.Listen()
jrpcClient := mocker.GetJsonC()
assert.NotNil(t, jrpcClient)
testCases := []struct {
fn func(*testing.T, *jsonclient.JSONClient) error
}{
{fn: testStartRawTxCmd},
{fn: testContinueRawTxCmd},
{fn: testQuitRawTxCmd},
{fn: testQueryGameById},
{fn: testQueryGameByAddr},
}
for index, testCase := range testCases {
err := testCase.fn(t, jrpcClient)
if err == nil {
continue
}
assert.NotEqualf(t, err, types.ErrActionNotSupport, "test index %d", index)
if strings.Contains(err.Error(), "rpc: can't find") {
assert.FailNowf(t, err.Error(), "test index %d", index)
}
}
}
func testStartRawTxCmd(t *testing.T, jrpc *jsonclient.JSONClient) error {
params := pty.PBStartTxReq{}
var res string
return jrpc.Call("pokerbull.PokerBullStartTx", params, &res)
}
func testContinueRawTxCmd(t *testing.T, jrpc *jsonclient.JSONClient) error {
params := pty.PBContinueTxReq{}
var res string
return jrpc.Call("pokerbull.PokerBullContinueTx", params, &res)
}
func testQuitRawTxCmd(t *testing.T, jrpc *jsonclient.JSONClient) error {
params := pty.PBContinueTxReq{}
var res string
return jrpc.Call("pokerbull.PokerBullQuitTx", params, &res)
}
func testQueryGameById(t *testing.T, jrpc *jsonclient.JSONClient) error {
var rep interface{}
var params types.Query4Cli
req := &pty.QueryPBGameInfo{}
params.Execer = "pokerbull"
params.FuncName = "QueryGameById"
params.Payload = req
rep = &pty.ReplyPBGame{}
return jrpc.Call("Chain33.Query", params, rep)
}
func testQueryGameByAddr(t *testing.T, jrpc *jsonclient.JSONClient) error {
var rep interface{}
var params types.Query4Cli
req := &pty.QueryPBGameInfo{}
params.Execer = "pokerbull"
params.FuncName = "QueryGameByAddr"
params.Payload = req
rep = &pty.PBGameRecords{}
return jrpc.Call("Chain33.Query", params, rep)
}
......@@ -35,6 +35,11 @@ func NewType() *HashlockType {
return c
}
// GetName 获取执行器名称
func (hashlock *HashlockType) GetName() string {
return HashlockX
}
// GetPayload method
func (hashlock *HashlockType) GetPayload() types.Message {
return &HashlockAction{}
......
package init
import (
_ "github.com/33cn/plugin/plugin/dapp/blackwhite"
_ "github.com/33cn/plugin/plugin/dapp/cert"
_ "github.com/33cn/plugin/plugin/dapp/evm"
_ "github.com/33cn/plugin/plugin/dapp/game"
_ "github.com/33cn/plugin/plugin/dapp/guess"
_ "github.com/33cn/plugin/plugin/dapp/hashlock"
_ "github.com/33cn/plugin/plugin/dapp/lottery"
_ "github.com/33cn/plugin/plugin/dapp/norm"
_ "github.com/33cn/plugin/plugin/dapp/paracross"
_ "github.com/33cn/plugin/plugin/dapp/pokerbull"
_ "github.com/33cn/plugin/plugin/dapp/privacy"
_ "github.com/33cn/plugin/plugin/dapp/relay"
_ "github.com/33cn/plugin/plugin/dapp/retrieve"
_ "github.com/33cn/plugin/plugin/dapp/ticket"
_ "github.com/33cn/plugin/plugin/dapp/token"
_ "github.com/33cn/plugin/plugin/dapp/trade"
_ "github.com/33cn/plugin/plugin/dapp/valnode"
_ "github.com/33cn/plugin/plugin/dapp/blackwhite" //auto gen
_ "github.com/33cn/plugin/plugin/dapp/cert" //auto gen
_ "github.com/33cn/plugin/plugin/dapp/evm" //auto gen
_ "github.com/33cn/plugin/plugin/dapp/game" //auto gen
_ "github.com/33cn/plugin/plugin/dapp/guess" //auto gen
_ "github.com/33cn/plugin/plugin/dapp/hashlock" //auto gen
_ "github.com/33cn/plugin/plugin/dapp/lottery" //auto gen
_ "github.com/33cn/plugin/plugin/dapp/multisig" //auto gen
_ "github.com/33cn/plugin/plugin/dapp/norm" //auto gen
_ "github.com/33cn/plugin/plugin/dapp/paracross" //auto gen
_ "github.com/33cn/plugin/plugin/dapp/pokerbull" //auto gen
_ "github.com/33cn/plugin/plugin/dapp/privacy" //auto gen
_ "github.com/33cn/plugin/plugin/dapp/relay" //auto gen
_ "github.com/33cn/plugin/plugin/dapp/retrieve" //auto gen
_ "github.com/33cn/plugin/plugin/dapp/ticket" //auto gen
_ "github.com/33cn/plugin/plugin/dapp/token" //auto gen
_ "github.com/33cn/plugin/plugin/dapp/trade" //auto gen
_ "github.com/33cn/plugin/plugin/dapp/unfreeze" //auto gen
_ "github.com/33cn/plugin/plugin/dapp/valnode" //auto gen
)
......@@ -31,6 +31,8 @@ func (l *Lottery) execDelLocal(tx *types.Transaction, receiptData *types.Receipt
set.KV = append(set.KV, kv...)
kv = l.updateLotteryBuy(&lotterylog, false)
set.KV = append(set.KV, kv...)
kv = l.deleteLotteryGain(&lotterylog)
set.KV = append(set.KV, kv...)
}
}
}
......
......@@ -31,6 +31,8 @@ func (l *Lottery) execLocal(tx *types.Transaction, receipt *types.ReceiptData) (
set.KV = append(set.KV, kv...)
kv = l.updateLotteryBuy(&lotterylog, true)
set.KV = append(set.KV, kv...)
kv = l.saveLotteryGain(&lotterylog)
set.KV = append(set.KV, kv...)
}
}
}
......
......@@ -35,3 +35,13 @@ func calcLotteryKey(lotteryID string, status int32) []byte {
key := fmt.Sprintf("LODB-lottery-:%d:%s", status, lotteryID)
return []byte(key)
}
func calcLotteryGainPrefix(lotteryID string, addr string) []byte {
key := fmt.Sprintf("LODB-lottery-gain:%s:%s", lotteryID, addr)
return []byte(key)
}
func calcLotteryGainKey(lotteryID string, addr string, round int64) []byte {
key := fmt.Sprintf("LODB-lottery-gain:%s:%s:%10d", lotteryID, addr, round)
return []byte(key)
}
......@@ -122,6 +122,25 @@ func (lott *Lottery) findLotteryDrawRecord(key []byte) (*pty.LotteryDrawRecord,
return &record, nil
}
func (lott *Lottery) findLotteryGainRecord(key []byte) (*pty.LotteryGainRecord, error) {
value, err := lott.GetLocalDB().Get(key)
if err != nil && err != types.ErrNotFound {
llog.Error("findLotteryGainRecord", "err", err)
return nil, err
}
if err == types.ErrNotFound {
return nil, nil
}
var record pty.LotteryGainRecord
err = types.Decode(value, &record)
if err != nil {
llog.Error("findLotteryGainRecord", "err", err)
return nil, err
}
return &record, nil
}
func (lott *Lottery) saveLotteryBuy(lotterylog *pty.ReceiptLottery) (kvs []*types.KeyValue) {
key := calcLotteryBuyKey(lotterylog.LotteryId, lotterylog.Addr, lotterylog.Round, lotterylog.Index)
record := &pty.LotteryBuyRecord{Number: lotterylog.Number, Amount: lotterylog.Amount, Round: lotterylog.Round, Type: 0, Way: lotterylog.Way, Index: lotterylog.Index, Time: lotterylog.Time, TxHash: lotterylog.TxHash}
......@@ -180,7 +199,7 @@ func (lott *Lottery) updateLotteryBuy(lotterylog *pty.ReceiptLottery, isAdd bool
func (lott *Lottery) saveLotteryDraw(lotterylog *pty.ReceiptLottery) (kvs []*types.KeyValue) {
key := calcLotteryDrawKey(lotterylog.LotteryId, lotterylog.Round)
record := &pty.LotteryDrawRecord{Number: lotterylog.LuckyNumber, Round: lotterylog.Round, Time: lotterylog.Time, TxHash: lotterylog.TxHash}
record := &pty.LotteryDrawRecord{Number: lotterylog.LuckyNumber, Round: lotterylog.Round, Time: lotterylog.Time, TxHash: lotterylog.TxHash, TotalAddrNum: lotterylog.TotalAddrNum, BuyAmount: lotterylog.BuyAmount}
kv := &types.KeyValue{Key: key, Value: types.Encode(record)}
kvs = append(kvs, kv)
return kvs
......@@ -234,3 +253,27 @@ func (lott *Lottery) GetPayloadValue() types.Message {
func (lott *Lottery) CheckReceiptExecOk() bool {
return true
}
func (lott *Lottery) saveLotteryGain(lotterylog *pty.ReceiptLottery) (kvs []*types.KeyValue) {
for _, gain := range lotterylog.GainInfos.Gains {
key := calcLotteryGainKey(lotterylog.LotteryId, gain.Addr, lotterylog.Round)
record := &pty.LotteryGainRecord{Addr: gain.Addr, BuyAmount: gain.BuyAmount, FundAmount: gain.FundAmount, Round: lotterylog.Round}
kv := &types.KeyValue{Key: key, Value: types.Encode(record)}
kvs = append(kvs, kv)
}
return kvs
}
func (lott *Lottery) deleteLotteryGain(lotterylog *pty.ReceiptLottery) (kvs []*types.KeyValue) {
for _, gain := range lotterylog.GainInfos.Gains {
kv := &types.KeyValue{}
kv.Key = calcLotteryGainKey(lotterylog.LotteryId, gain.Addr, lotterylog.Round)
kv.Value = nil
kvs = append(kvs, kv)
}
return kvs
}
This diff is collapsed.
......@@ -55,7 +55,8 @@ func (l *Lottery) Query_GetLotteryCurrentInfo(param *pty.ReqLotteryInfo) (types.
PurBlockNum: lottery.PurBlockNum,
DrawBlockNum: lottery.DrawBlockNum,
MissingRecords: lottery.MissingRecords,
}
TotalAddrNum: lottery.TotalAddrNum,
BuyAmount: lottery.BuyAmount}
return reply, nil
}
......@@ -98,3 +99,18 @@ func (l *Lottery) Query_GetLotteryBuyRoundInfo(param *pty.ReqLotteryBuyInfo) (ty
}
return record, nil
}
// Query_GetLotteryHistoryGainInfo for all history
func (l *Lottery) Query_GetLotteryHistoryGainInfo(param *pty.ReqLotteryGainHistory) (types.Message, error) {
return ListLotteryGainRecords(l.GetLocalDB(), l.GetStateDB(), param)
}
// Query_GetLotteryRoundGainInfo for each round
func (l *Lottery) Query_GetLotteryRoundGainInfo(param *pty.ReqLotteryGainInfo) (types.Message, error) {
key := calcLotteryGainKey(param.LotteryId, param.Addr, param.Round)
record, err := l.findLotteryGainRecord(key)
if err != nil {
return nil, err
}
return record, nil
}
......@@ -37,6 +37,8 @@ message Lottery {
int64 opRewardRatio = 18;
int64 devRewardRatio = 19;
repeated PurchaseRecords purRecords = 20;
int64 totalAddrNum = 21;
int64 buyAmount = 22;
}
message MissingRecord {
......@@ -76,19 +78,22 @@ message LotteryClose {
}
message ReceiptLottery {
string lotteryId = 1;
int32 status = 2;
int32 prevStatus = 3;
string addr = 4;
int64 round = 5;
int64 number = 6;
int64 amount = 7;
int64 luckyNumber = 8;
int64 time = 9;
string txHash = 10;
LotteryUpdateBuyInfo updateInfo = 11;
int64 way = 12;
int64 index = 13;
string lotteryId = 1;
int32 status = 2;
int32 prevStatus = 3;
string addr = 4;
int64 round = 5;
int64 number = 6;
int64 amount = 7;
int64 luckyNumber = 8;
int64 time = 9;
string txHash = 10;
LotteryUpdateBuyInfo updateInfo = 11;
int64 way = 12;
int64 index = 13;
int64 totalAddrNum = 14;
int64 buyAmount = 15;
LotteryGainInfos gainInfos = 16;
}
message ReqLotteryInfo {
......@@ -144,6 +149,8 @@ message ReplyLotteryCurrentInfo {
int64 purBlockNum = 10;
int64 drawBlockNum = 11;
repeated MissingRecord missingRecords = 12;
int64 totalAddrNum = 13;
int64 buyAmount = 14;
}
message ReplyLotteryHistoryLuckyNumber {
......@@ -176,10 +183,12 @@ message LotteryBuyRecords {
}
message LotteryDrawRecord {
int64 number = 1;
int64 round = 2;
int64 time = 3;
string txHash = 4;
int64 number = 1;
int64 round = 2;
int64 time = 3;
string txHash = 4;
int64 totalAddrNum = 5;
int64 buyAmount = 6;
}
message LotteryDrawRecords {
......@@ -202,3 +211,39 @@ message LotteryUpdateBuyInfo {
message ReplyLotteryPurchaseAddr {
repeated string address = 1;
}
message LotteryGainInfos{
repeated LotteryGainInfo gains = 1;
}
message LotteryGainInfo{
string addr = 1;
int64 buyAmount = 2;
float fundAmount = 3;
}
message LotteryGainRecord{
string addr = 1;
int64 buyAmount = 2;
float fundAmount = 3;
int64 round = 4;
}
message LotteryGainRecords {
repeated LotteryGainRecord records = 1;
}
message ReqLotteryGainHistory {
string lotteryId = 1;
string addr = 2;
int64 round = 3;
int32 count = 4;
int32 direction = 5;
}
message ReqLotteryGainInfo {
string lotteryId = 1;
string addr = 2;
int64 round = 3;
}
......@@ -35,6 +35,11 @@ func NewType() *LotteryType {
return c
}
// GetName 获取执行器名称
func (lottery *LotteryType) GetName() string {
return LotteryX
}
// GetLogMap method
func (lottery *LotteryType) GetLogMap() map[int64]*types.LogInfo {
return map[int64]*types.LogInfo{
......
This diff is collapsed.
This diff is collapsed.
// Copyright Fuzamei Corp. 2018 All Rights Reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package multisig
/*
多重签名合约实现功能:
创建一个多重签名的账户,并指定owner已经权重
账户属性交易:
owner的add/del/modify/replace
资产每日限额的修改
请求权重的修改
账户属性的修改都是一个交易,需要满足权重的要求才能被执行。
账户交易的确认和撤销:当交易提交者的权重不能满足权重要求时,需要其余的owner来一起确认。owner可以撤销自己对某笔交易的确认,但此交易必须是没有被执行。已执行的不应许撤销
多重签名账户的转入和转出:转入时,to地址必须是多重签名地址,from地址必须是非多重签名地址;
转出时,from地址必须是多重签名地址,to地址必须是非多重签名地址; 传出交易需要校验权重
cli 命令行主要分三块:account 账户相关的,owner 相关的以及tx交易相关的
cli multisig
Available Commands:
account multisig account
owner multisig owner
tx multisig tx
cli multisig account
Available Commands:
address get multisig account address
assets get assets of multisig account
count get multisig account count
create Create a multisig account transaction
creator get all multisig accounts created by the address
dailylimit Create a modify assets dailylimit transaction
info get multisig account info
unspent get assets unspent today amount
weight Create a modify required weight transaction
cli multisig owner
Available Commands:
add Create a add owner transaction
del Create a del owner transaction
modify Create a modify owner weight transaction
replace Create a replace owner transaction
cli multisig tx
Available Commands:
confirm Create a confirm transaction
confirmed_weight get the weight of the transaction confirmed.
count get multisig tx count
info get multisig account tx info
transfer_in Create a transfer to multisig account transaction
transfer_out Create a transfer from multisig account transaction
txids get multisig txids
测试步骤如下:
cli seed save -p heyubin -s "voice leisure mechanic tape cluster grunt receive joke nurse between monkey lunch save useful cruise"
cli wallet unlock -p heyubin
cli account import_key -l miner -k CC38546E9E659D15E6B4893F0AB32A06D103931A8230B0BDE71459D2B27D6944
cli account create -l heyubin
cli account create -l heyubin1
cli account create -l heyubin2
cli account create -l heyubin3
cli account create -l heyubin4
cli account create -l heyubin5
cli account create -l heyubin6
cli account create -l heyubin7
cli account create -l heyubin8
cli send bty transfer -a 100 -n test -t 1DkrXbz2bK6XMpY4v9z2YUnhwWTXT6V5jd -k 14KEKbYtKKQm4wMthSK9J4La4nAiidGozt
cli send bty transfer -a 100 -n test -t 1Kkgztjcni3xKw95y2VZHwPpsSHDEH5sXF -k 14KEKbYtKKQm4wMthSK9J4La4nAiidGozt
cli send bty transfer -a 100 -n test -t 1N8LP5gBufZXCEdf3hyViDhWFqeB7WPGdv -k 14KEKbYtKKQm4wMthSK9J4La4nAiidGozt
cli send bty transfer -a 100 -n test -t 1C5xK2ytuoFqxmVGMcyz9XFKFWcDA8T3rK -k 14KEKbYtKKQm4wMthSK9J4La4nAiidGozt
cli send bty transfer -a 100 -n test -t "1LDGrokrZjo1HtSmSnw8ef3oy5Vm1nctbj" -k 14KEKbYtKKQm4wMthSK9J4La4nAiidGozt
cli send bty transfer -a 100 -n test -t "17a5NQTf9M2Dz9qBS8KiQ8VUg8qhoYeQbA" -k 14KEKbYtKKQm4wMthSK9J4La4nAiidGozt
cli send bty transfer -a 100 -n test -t "1DeGvSFX8HAFsuHxhaVkLX56Ke3FzFbdct" -k 14KEKbYtKKQm4wMthSK9J4La4nAiidGozt
cli send bty transfer -a 100 -n test -t "166po3ghRbRu53hu8jBBQzddp7kUJ9Ynyf" -k 14KEKbYtKKQm4wMthSK9J4La4nAiidGozt
cli send bty transfer -a 100 -n test -t "1KHwX7ZadNeQDjBGpnweb4k2dqj2CWtAYo" -k 14KEKbYtKKQm4wMthSK9J4La4nAiidGozt
第一步:1DkrXbz2bK6XMpY4v9z2YUnhwWTXT6V5jd地址创建多重签名的账户,owner:1Kkgztjcni3xKw95y2VZHwPpsSHDEH5sXF 1N8LP5gBufZXCEdf3hyViDhWFqeB7WPGdv
//构建交易
cli send multisig account create -d 10 -e coins -s BTY -a "1C5xK2ytuoFqxmVGMcyz9XFKFWcDA8T3rK 1LDGrokrZjo1HtSmSnw8ef3oy5Vm1nctbj" -w "20 10" -r 15 -k 1DkrXbz2bK6XMpY4v9z2YUnhwWTXT6V5jd
//查看创建的账户个数
cli multisig account count
//通过账户index获取账户地址
cli multisig account address -e 0 -s 0
//通过账户addr获取账户详情
cli multisig account info -a "13q53Ga1kquDCqx7EWF8FU94tLUK18Zd47"
第二步,向multisig合约中转账 1DkrXbz2bK6XMpY4v9z2YUnhwWTXT6V5jd
cli exec addr -e "multisig"
14uBEP6LSHKdFvy97pTYRPVPAqij6bteee
// 转账
cli send bty transfer -a 50 -n test -t 14uBEP6LSHKdFvy97pTYRPVPAqij6bteee -k 1DkrXbz2bK6XMpY4v9z2YUnhwWTXT6V5jd
cli account balance -a 1DkrXbz2bK6XMpY4v9z2YUnhwWTXT6V5jd
第三步:从指定账户转账到多重签名地址 1DkrXbz2bK6XMpY4v9z2YUnhwWTXT6V5jd --》 "13q53Ga1kquDCqx7EWF8FU94tLUK18Zd47"
cli send multisig tx transfer_in -a 40 -e coins -s BTY -t "13q53Ga1kquDCqx7EWF8FU94tLUK18Zd47" -n test -k 1DkrXbz2bK6XMpY4v9z2YUnhwWTXT6V5jd
//查看1DkrXbz2bK6XMpY4v9z2YUnhwWTXT6V5jd地上有40被转出了
cli account balance -a 1DkrXbz2bK6XMpY4v9z2YUnhwWTXT6V5jd
//多重签名地址转入40并冻结
cli account balance -a "13q53Ga1kquDCqx7EWF8FU94tLUK18Zd47"
cli multisig account assets -a "13q53Ga1kquDCqx7EWF8FU94tLUK18Zd47"
第四步:从多重签名账户传出 "13q53Ga1kquDCqx7EWF8FU94tLUK18Zd47" --》1LDGrokrZjo1HtSmSnw8ef3oy5Vm1nctbj owner:1C5xK2ytuoFqxmVGMcyz9XFKFWcDA8T3rK签名
cli send multisig tx transfer_out -a 11 -e coins -s BTY -f "13q53Ga1kquDCqx7EWF8FU94tLUK18Zd47" -t 1LDGrokrZjo1HtSmSnw8ef3oy5Vm1nctbj -n test -k "1C5xK2ytuoFqxmVGMcyz9XFKFWcDA8T3rK"
查询账户信息
cli multisig account info -a "13q53Ga1kquDCqx7EWF8FU94tLUK18Zd47"
cli multisig account assets -a "13q53Ga1kquDCqx7EWF8FU94tLUK18Zd47"
查询接受地址是否收到币
cli multisig account assets -a 1LDGrokrZjo1HtSmSnw8ef3oy5Vm1nctbj
// 查询交易计数
cli multisig tx count -a "13q53Ga1kquDCqx7EWF8FU94tLUK18Zd47"
// 查询交易txid
cli multisig tx txids -a "13q53Ga1kquDCqx7EWF8FU94tLUK18Zd47" -s 0 -e 0
// 查询交易信息
cli multisig tx info -a "13q53Ga1kquDCqx7EWF8FU94tLUK18Zd47" -i 0
//owner "1LDGrokrZjo1HtSmSnw8ef3oy5Vm1nctbj," 转账5个币到1LDGrokrZjo1HtSmSnw8ef3oy5Vm1nctbj owner:1LDGrokrZjo1HtSmSnw8ef3oy5Vm1nctbj签名
cli send multisig tx transfer_out -a 5 -e coins -s BTY -f "13q53Ga1kquDCqx7EWF8FU94tLUK18Zd47" -t 1LDGrokrZjo1HtSmSnw8ef3oy5Vm1nctbj -n test -k "1LDGrokrZjo1HtSmSnw8ef3oy5Vm1nctbj"
第五步:测试add/del owner 使用高权重的owner添加交易 "1C5xK2ytuoFqxmVGMcyz9XFKFWcDA8T3rK", add 1KHwX7ZadNeQDjBGpnweb4k2dqj2CWtAYo
cli send multisig owner add -a "13q53Ga1kquDCqx7EWF8FU94tLUK18Zd47" -o 1KHwX7ZadNeQDjBGpnweb4k2dqj2CWtAYo -w 5 -k "1C5xK2ytuoFqxmVGMcyz9XFKFWcDA8T3rK"
查看owner的添加
cli multisig account info -a 13q53Ga1kquDCqx7EWF8FU94tLUK18Zd47
cli multisig tx info -a "13q53Ga1kquDCqx7EWF8FU94tLUK18Zd47" -i 0
//del owner
cli send multisig owner del -a "13q53Ga1kquDCqx7EWF8FU94tLUK18Zd47" -o "1KHwX7ZadNeQDjBGpnweb4k2dqj2CWtAYo" -k 1C5xK2ytuoFqxmVGMcyz9XFKFWcDA8T3rK
// modify dailylimit
cli send multisig account dailylimit -a "13q53Ga1kquDCqx7EWF8FU94tLUK18Zd47" -e coins -s BTY -d 12 -k 1C5xK2ytuoFqxmVGMcyz9XFKFWcDA8T3rK
// modify weight
cli send multisig account weight -a "13q53Ga1kquDCqx7EWF8FU94tLUK18Zd47" -w 16 -k 1C5xK2ytuoFqxmVGMcyz9XFKFWcDA8T3rK
//replace owner
cli send multisig owner replace -a "13q53Ga1kquDCqx7EWF8FU94tLUK18Zd47" -n 166po3ghRbRu53hu8jBBQzddp7kUJ9Ynyf -o 1LDGrokrZjo1HtSmSnw8ef3oy5Vm1nctbj -k 1C5xK2ytuoFqxmVGMcyz9XFKFWcDA8T3rK
// modify owner
cli send multisig owner modify -a "13q53Ga1kquDCqx7EWF8FU94tLUK18Zd47" -o "166po3ghRbRu53hu8jBBQzddp7kUJ9Ynyf" -w 11 -k 1C5xK2ytuoFqxmVGMcyz9XFKFWcDA8T3rK
//获取指定地址创建的所有多重签名账户
cli multisig account creator -a 1DkrXbz2bK6XMpY4v9z2YUnhwWTXT6V5jd
// 获取指定账户上指定资产的每日余额
cli multisig account unspent -a 13q53Ga1kquDCqx7EWF8FU94tLUK18Zd47 -e coins -s BTY
第五步:测试交易的确认和撤销
//权重低的转账,owner:166po3ghRbRu53hu8jBBQzddp7kUJ9Ynyf
cli send multisig tx transfer_out -a 10 -e coins -s BTY -f "13q53Ga1kquDCqx7EWF8FU94tLUK18Zd47" -t 1LDGrokrZjo1HtSmSnw8ef3oy5Vm1nctbj -n test -k "166po3ghRbRu53hu8jBBQzddp7kUJ9Ynyf"
//撤销对某笔交易的确认
cli send multisig tx confirm -a "13q53Ga1kquDCqx7EWF8FU94tLUK18Zd47" -i 8 -c f -k 166po3ghRbRu53hu8jBBQzddp7kUJ9Ynyf
//确认某笔交易
cli send multisig tx confirm -a "13q53Ga1kquDCqx7EWF8FU94tLUK18Zd47" -i 8 -k "166po3ghRbRu53hu8jBBQzddp7kUJ9Ynyf"
cli send multisig tx confirm -a "13q53Ga1kquDCqx7EWF8FU94tLUK18Zd47" -i 8 -k "1C5xK2ytuoFqxmVGMcyz9XFKFWcDA8T3rK"
*/
This diff is collapsed.
// Copyright Fuzamei Corp. 2018 All Rights Reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package executor
import (
"github.com/33cn/chain33/types"
mty "github.com/33cn/plugin/plugin/dapp/multisig/types"
)
//Exec_MultiSigAccCreate 创建多重签名账户
func (m *MultiSig) Exec_MultiSigAccCreate(payload *mty.MultiSigAccCreate, tx *types.Transaction, index int) (*types.Receipt, error) {
action := newAction(m, tx, int32(index))
return action.MultiSigAccCreate(payload)
}
//Exec_MultiSigOwnerOperate 多重签名账户owner属性的修改:owner的add/del/replace等
func (m *MultiSig) Exec_MultiSigOwnerOperate(payload *mty.MultiSigOwnerOperate, tx *types.Transaction, index int) (*types.Receipt, error) {
action := newAction(m, tx, int32(index))
return action.MultiSigOwnerOperate(payload)
}
//Exec_MultiSigAccOperate 多重签名账户属性的修改:weight权重以及每日限额的修改
func (m *MultiSig) Exec_MultiSigAccOperate(payload *mty.MultiSigAccOperate, tx *types.Transaction, index int) (*types.Receipt, error) {
action := newAction(m, tx, int32(index))
return action.MultiSigAccOperate(payload)
}
//Exec_MultiSigConfirmTx 多重签名账户上交易的确认和撤销
func (m *MultiSig) Exec_MultiSigConfirmTx(payload *mty.MultiSigConfirmTx, tx *types.Transaction, index int) (*types.Receipt, error) {
action := newAction(m, tx, int32(index))
return action.MultiSigConfirmTx(payload)
}
//Exec_MultiSigExecTransferTo 合约中外部账户转账到多重签名账户,Addr --->multiSigAddr
func (m *MultiSig) Exec_MultiSigExecTransferTo(payload *mty.MultiSigExecTransferTo, tx *types.Transaction, index int) (*types.Receipt, error) {
action := newAction(m, tx, int32(index))
return action.MultiSigExecTransferTo(payload)
}
//Exec_MultiSigExecTransferFrom 合约中多重签名账户转账到外部账户,multiSigAddr--->Addr
func (m *MultiSig) Exec_MultiSigExecTransferFrom(payload *mty.MultiSigExecTransferFrom, tx *types.Transaction, index int) (*types.Receipt, error) {
action := newAction(m, tx, int32(index))
return action.MultiSigExecTransferFrom(payload)
}
// Copyright Fuzamei Corp. 2018 All Rights Reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package executor
import (
"github.com/33cn/chain33/types"
mty "github.com/33cn/plugin/plugin/dapp/multisig/types"
)
//ExecDelLocal_MultiSigAccCreate 创建多重签名账户,根据payload和receiptData信息获取相关信息并保存到db中
func (m *MultiSig) ExecDelLocal_MultiSigAccCreate(payload *mty.MultiSigAccCreate, tx *types.Transaction, receiptData *types.ReceiptData, index int) (*types.LocalDBSet, error) {
if receiptData.GetTy() != types.ExecOk {
return &types.LocalDBSet{}, nil
}
kv, err := m.execLocalMultiSigReceipt(receiptData, tx, false)
if err != nil {
return nil, err
}
return &types.LocalDBSet{KV: kv}, nil
}
//ExecDelLocal_MultiSigOwnerOperate 多重签名账户owner属性的修改:owner的add/del/replace/modify等
func (m *MultiSig) ExecDelLocal_MultiSigOwnerOperate(payload *mty.MultiSigOwnerOperate, tx *types.Transaction, receiptData *types.ReceiptData, index int) (*types.LocalDBSet, error) {
if receiptData.GetTy() != types.ExecOk {
return &types.LocalDBSet{}, nil
}
kv, err := m.execLocalMultiSigReceipt(receiptData, tx, false)
if err != nil {
return nil, err
}
return &types.LocalDBSet{KV: kv}, nil
}
//ExecDelLocal_MultiSigAccOperate 多重签名账户属性的修改:weight权重以及每日限额的修改
func (m *MultiSig) ExecDelLocal_MultiSigAccOperate(payload *mty.MultiSigAccOperate, tx *types.Transaction, receiptData *types.ReceiptData, index int) (*types.LocalDBSet, error) {
if receiptData.GetTy() != types.ExecOk {
return &types.LocalDBSet{}, nil
}
kv, err := m.execLocalMultiSigReceipt(receiptData, tx, false)
if err != nil {
return nil, err
}
return &types.LocalDBSet{KV: kv}, nil
}
//ExecDelLocal_MultiSigConfirmTx 多重签名账户上交易的确认和撤销
func (m *MultiSig) ExecDelLocal_MultiSigConfirmTx(payload *mty.MultiSigConfirmTx, tx *types.Transaction, receiptData *types.ReceiptData, index int) (*types.LocalDBSet, error) {
if receiptData.GetTy() != types.ExecOk {
return &types.LocalDBSet{}, nil
}
kv, err := m.execLocalMultiSigReceipt(receiptData, tx, false)
if err != nil {
return nil, err
}
return &types.LocalDBSet{KV: kv}, nil
}
//ExecDelLocal_MultiSigExecTransferTo 合约中外部账户转账到多重签名账户,Addr --->multiSigAddr
func (m *MultiSig) ExecDelLocal_MultiSigExecTransferTo(payload *mty.MultiSigExecTransferTo, tx *types.Transaction, receiptData *types.ReceiptData, index int) (*types.LocalDBSet, error) {
if receiptData.GetTy() != types.ExecOk {
return &types.LocalDBSet{}, nil
}
kv, err := m.saveMultiSigTransfer(tx, mty.IsSubmit, false)
if err != nil {
return nil, err
}
return &types.LocalDBSet{KV: kv}, nil
}
//ExecDelLocal_MultiSigExecTransferFrom 合约中多重签名账户转账到外部账户,multiSigAddr--->Addr
func (m *MultiSig) ExecDelLocal_MultiSigExecTransferFrom(payload *mty.MultiSigExecTransferFrom, tx *types.Transaction, receiptData *types.ReceiptData, index int) (*types.LocalDBSet, error) {
if receiptData.GetTy() != types.ExecOk {
return &types.LocalDBSet{}, nil
}
kv, err := m.execLocalMultiSigReceipt(receiptData, tx, false)
if err != nil {
return nil, err
}
return &types.LocalDBSet{KV: kv}, nil
}
// Copyright Fuzamei Corp. 2018 All Rights Reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package executor
import (
"github.com/33cn/chain33/types"
mty "github.com/33cn/plugin/plugin/dapp/multisig/types"
)
//ExecLocal_MultiSigAccCreate 创建多重签名账户,根据payload和receiptData信息获取相关信息并保存到db中
func (m *MultiSig) ExecLocal_MultiSigAccCreate(payload *mty.MultiSigAccCreate, tx *types.Transaction, receiptData *types.ReceiptData, index int) (*types.LocalDBSet, error) {
if receiptData.GetTy() != types.ExecOk {
return &types.LocalDBSet{}, nil
}
kv, err := m.execLocalMultiSigReceipt(receiptData, tx, true)
if err != nil {
multisiglog.Error("ExecLocal_MultiSigAccCreate", "err", err)
return nil, err
}
return &types.LocalDBSet{KV: kv}, nil
}
//ExecLocal_MultiSigOwnerOperate 多重签名账户owner属性的修改:owner的add/del/replace/modify等
func (m *MultiSig) ExecLocal_MultiSigOwnerOperate(payload *mty.MultiSigOwnerOperate, tx *types.Transaction, receiptData *types.ReceiptData, index int) (*types.LocalDBSet, error) {
if receiptData.GetTy() != types.ExecOk {
return &types.LocalDBSet{}, nil
}
kv, err := m.execLocalMultiSigReceipt(receiptData, tx, true)
if err != nil {
multisiglog.Error("ExecLocal_MultiSigOwnerOperate", "err", err)
return nil, err
}
return &types.LocalDBSet{KV: kv}, nil
}
//ExecLocal_MultiSigAccOperate 多重签名账户属性的修改:weight权重以及每日限额的修改
func (m *MultiSig) ExecLocal_MultiSigAccOperate(payload *mty.MultiSigAccOperate, tx *types.Transaction, receiptData *types.ReceiptData, index int) (*types.LocalDBSet, error) {
if receiptData.GetTy() != types.ExecOk {
return &types.LocalDBSet{}, nil
}
kv, err := m.execLocalMultiSigReceipt(receiptData, tx, true)
if err != nil {
return nil, err
}
return &types.LocalDBSet{KV: kv}, nil
}
//ExecLocal_MultiSigConfirmTx 多重签名账户上交易的确认和撤销
func (m *MultiSig) ExecLocal_MultiSigConfirmTx(payload *mty.MultiSigConfirmTx, tx *types.Transaction, receiptData *types.ReceiptData, index int) (*types.LocalDBSet, error) {
if receiptData.GetTy() != types.ExecOk {
return &types.LocalDBSet{}, nil
}
kv, err := m.execLocalMultiSigReceipt(receiptData, tx, true)
if err != nil {
multisiglog.Error("ExecLocal_MultiSigConfirmTx", "err", err)
return nil, err
}
return &types.LocalDBSet{KV: kv}, nil
}
//ExecLocal_MultiSigExecTransferTo 合约中外部账户转账到多重签名账户,Addr --->multiSigAddr
func (m *MultiSig) ExecLocal_MultiSigExecTransferTo(payload *mty.MultiSigExecTransferTo, tx *types.Transaction, receiptData *types.ReceiptData, index int) (*types.LocalDBSet, error) {
if receiptData.GetTy() != types.ExecOk {
return &types.LocalDBSet{}, nil
}
kv, err := m.saveMultiSigTransfer(tx, mty.IsSubmit, true)
if err != nil {
multisiglog.Error("ExecLocal_MultiSigExecTransferTo", "err", err)
return nil, err
}
return &types.LocalDBSet{KV: kv}, nil
}
//ExecLocal_MultiSigExecTransferFrom 合约中多重签名账户转账到外部账户,multiSigAddr--->Addr
func (m *MultiSig) ExecLocal_MultiSigExecTransferFrom(payload *mty.MultiSigExecTransferFrom, tx *types.Transaction, receiptData *types.ReceiptData, index int) (*types.LocalDBSet, error) {
if receiptData.GetTy() != types.ExecOk {
return &types.LocalDBSet{}, nil
}
kv, err := m.execLocalMultiSigReceipt(receiptData, tx, true)
if err != nil {
multisiglog.Error("ExecLocal_MultiSigExecTransferFrom", "err", err)
return nil, err
}
return &types.LocalDBSet{KV: kv}, nil
}
This diff is collapsed.
// Copyright Fuzamei Corp. 2018 All Rights Reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package executor
import (
"fmt"
)
//数据库存储格式key
const (
//MultiSigPrefix statedb中账户和交易的存储格式
MultiSigPrefix = "mavl-multisig-"
MultiSigTxPrefix = "mavl-multisig-tx-"
//MultiSigLocalPrefix localdb中账户和交易的存储格式multisig account count记录账户个数
MultiSigLocalPrefix = "LODB-multisig-"
MultiSigAccCount = "acccount"
MultiSigAcc = "account"
MultiSigAllAcc = "allacc"
MultiSigTx = "tx"
MultiSigRecvAssets = "assets"
MultiSigAccCreate = "create"
)
//statedb中账户和交易的存储格式
func calcMultiSigAccountKey(multiSigAccAddr string) (key []byte) {
return []byte(fmt.Sprintf(MultiSigPrefix+"%s", multiSigAccAddr))
}
//存储格式:"mavl-multisig-tx-accaddr-000000000000"
func calcMultiSigAccTxKey(multiSigAccAddr string, txid uint64) (key []byte) {
txstr := fmt.Sprintf("%018d", txid)
return []byte(fmt.Sprintf(MultiSigTxPrefix+"%s-%s", multiSigAccAddr, txstr))
}
//localdb中账户相关的存储格式
//记录创建的账户数量,key:Msac value:count。
func calcMultiSigAccCountKey() []byte {
return []byte(fmt.Sprintf(MultiSigLocalPrefix+"%s", MultiSigAccCount))
}
//存储所有的MultiSig账户地址:按顺序存储方便以后分页查找: key:Ms:allacc:index,value:accaddr
func calcMultiSigAllAcc(accindex int64) (key []byte) {
accstr := fmt.Sprintf("%018d", accindex)
return []byte(fmt.Sprintf(MultiSigLocalPrefix+"%s-%s", MultiSigAllAcc, accstr))
}
//记录指定账号地址的信息value:MultiSig。key:Ms:acc
func calcMultiSigAcc(addr string) (key []byte) {
return []byte(fmt.Sprintf(MultiSigLocalPrefix+"%s-%s", MultiSigAcc, addr))
}
//记录某个地址创建的所有多重签名账户。key:Ms:create:createAddr,value:[]string。
func calcMultiSigAccCreateAddr(createAddr string) (key []byte) {
return []byte(fmt.Sprintf(MultiSigLocalPrefix+"%s:-%s", MultiSigAccCreate, createAddr))
}
//localdb中账户相关的存储格式
//记录指定账号地址的信息key:Ms:tx:addr:txid value:MultiSigTx。
func calcMultiSigAccTx(addr string, txid uint64) (key []byte) {
accstr := fmt.Sprintf("%018d", txid)
return []byte(fmt.Sprintf(MultiSigLocalPrefix+"%s-%s-%s", MultiSigTx, addr, accstr))
}
//可以通过前缀查找获取指定账户上收到的所有资产数量
//MultiSig合约中账户收到指定资产的计数key:Ms:assets:addr:execname:symbol value:AccountAssets。
//message AccountAssets {
// string multiSigAddr = 1;
// string execer = 2;
// string symbol = 3;
// int64 amount = 4;
func calcAddrRecvAmountKey(addr, execname, symbol string) []byte {
return []byte(fmt.Sprintf(MultiSigLocalPrefix+"%s-%s-%s-%s", MultiSigRecvAssets, addr, execname, symbol))
}
// 前缀查找某个账户下的所有资产信息
func calcAddrRecvAmountPrefix(addr string) []byte {
return []byte(fmt.Sprintf(MultiSigLocalPrefix+"%s-%s-", MultiSigRecvAssets, addr))
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
package multisig
import (
"github.com/33cn/chain33/pluginmgr"
"github.com/33cn/plugin/plugin/dapp/multisig/commands"
"github.com/33cn/plugin/plugin/dapp/multisig/executor"
"github.com/33cn/plugin/plugin/dapp/multisig/rpc"
mty "github.com/33cn/plugin/plugin/dapp/multisig/types"
)
func init() {
pluginmgr.Register(&pluginmgr.PluginBase{
Name: mty.MultiSigX,
ExecName: executor.GetName(),
Exec: executor.Init,
Cmd: commands.MultiSigCmd,
RPC: rpc.Init,
})
}
all:
./create_protobuf.sh
#!/bin/sh
protoc --go_out=plugins=grpc:../types ./*.proto --proto_path=. --proto_path="../../../../vendor/github.com/33cn/chain33/types/proto/"
This diff is collapsed.
// Copyright Fuzamei Corp. 2018 All Rights Reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package rpc_test
import (
"strings"
"testing"
commonlog "github.com/33cn/chain33/common/log"
"github.com/33cn/chain33/rpc/jsonclient"
"github.com/33cn/chain33/types"
"github.com/33cn/chain33/util/testnode"
mty "github.com/33cn/plugin/plugin/dapp/multisig/types"
"github.com/stretchr/testify/assert"
// 注册system和plugin 包
rpctypes "github.com/33cn/chain33/rpc/types"
_ "github.com/33cn/chain33/system"
_ "github.com/33cn/plugin/plugin"
)
func init() {
commonlog.SetLogLevel("error")
}
func TestJRPCChannel(t *testing.T) {
// 启动RPCmocker
mocker := testnode.New("--notset--", nil)
defer func() {
mocker.Close()
}()
mocker.Listen()
jrpcClient := mocker.GetJSONC()
testCases := []struct {
fn func(*testing.T, *jsonclient.JSONClient) error
}{
{fn: testCreateMultiSigAccCreateCmd},
{fn: testCreateMultiSigAccOwnerAddCmd},
{fn: testCreateMultiSigAccOwnerDelCmd},
{fn: testCreateMultiSigAccOwnerModifyCmd},
{fn: testCreateMultiSigAccOwnerReplaceCmd},
{fn: testCreateMultiSigAccWeightModifyCmd},
{fn: testCreateMultiSigAccDailyLimitModifyCmd},
{fn: testCreateMultiSigConfirmTxCmd},
{fn: testCreateMultiSigAccTransferInCmd},
{fn: testCreateMultiSigAccTransferOutCmd},
{fn: testGetMultiSigAccCountCmd},
{fn: testGetMultiSigAccountsCmd},
{fn: testGetMultiSigAccountInfoCmd},
{fn: testGetMultiSigAccTxCountCmd},
{fn: testGetMultiSigTxidsCmd},
{fn: testGetMultiSigTxInfoCmd},
{fn: testGetGetMultiSigTxConfirmedWeightCmd},
{fn: testGetGetMultiSigAccUnSpentTodayCmd},
{fn: testGetMultiSigAccAssetsCmd},
{fn: testGetMultiSigAccAllAddressCmd},
}
for index, testCase := range testCases {
err := testCase.fn(t, jrpcClient)
if err == nil {
continue
}
assert.NotEqualf(t, err, types.ErrActionNotSupport, "test index %d", index)
if strings.Contains(err.Error(), "rpc: can't find") {
assert.FailNowf(t, err.Error(), "test index %d", index)
}
}
}
//创建交易
func testCreateMultiSigAccCreateCmd(t *testing.T, jrpc *jsonclient.JSONClient) error {
params := &mty.MultiSigAccCreate{}
return jrpc.Call("multisig.MultiSigAccCreateTx", params, nil)
}
func testCreateMultiSigAccOwnerAddCmd(t *testing.T, jrpc *jsonclient.JSONClient) error {
params := &mty.MultiSigOwnerOperate{}
return jrpc.Call("multisig.MultiSigOwnerOperateTx", params, nil)
}
func testCreateMultiSigAccOwnerDelCmd(t *testing.T, jrpc *jsonclient.JSONClient) error {
params := &mty.MultiSigOwnerOperate{}
return jrpc.Call("multisig.MultiSigOwnerOperateTx", params, nil)
}
func testCreateMultiSigAccOwnerModifyCmd(t *testing.T, jrpc *jsonclient.JSONClient) error {
params := &mty.MultiSigOwnerOperate{}
return jrpc.Call("multisig.MultiSigOwnerOperateTx", params, nil)
}
func testCreateMultiSigAccOwnerReplaceCmd(t *testing.T, jrpc *jsonclient.JSONClient) error {
params := &mty.MultiSigOwnerOperate{}
return jrpc.Call("multisig.MultiSigOwnerOperateTx", params, nil)
}
func testCreateMultiSigAccWeightModifyCmd(t *testing.T, jrpc *jsonclient.JSONClient) error {
params := &mty.MultiSigAccOperate{}
return jrpc.Call("multisig.MultiSigAccOperateTx", params, nil)
}
func testCreateMultiSigAccDailyLimitModifyCmd(t *testing.T, jrpc *jsonclient.JSONClient) error {
params := &mty.MultiSigAccOperate{}
return jrpc.Call("multisig.MultiSigAccOperateTx", params, nil)
}
func testCreateMultiSigConfirmTxCmd(t *testing.T, jrpc *jsonclient.JSONClient) error {
params := &mty.MultiSigConfirmTx{}
return jrpc.Call("multisig.MultiSigConfirmTx", params, nil)
}
func testCreateMultiSigAccTransferInCmd(t *testing.T, jrpc *jsonclient.JSONClient) error {
params := &mty.MultiSigExecTransferTo{}
return jrpc.Call("multisig.MultiSigAccTransferInTx", params, nil)
}
func testCreateMultiSigAccTransferOutCmd(t *testing.T, jrpc *jsonclient.JSONClient) error {
params := &mty.MultiSigExecTransferFrom{}
return jrpc.Call("multisig.MultiSigAccTransferOutTx", params, nil)
}
//get 多重签名账户信息
func testGetMultiSigAccCountCmd(t *testing.T, jrpc *jsonclient.JSONClient) error {
params := &rpctypes.Query4Jrpc{
Execer: mty.MultiSigX,
FuncName: "MultiSigAccCount",
Payload: types.MustPBToJSON(&types.ReqNil{}),
}
var res types.Int64
return jrpc.Call("Chain33.Query", params, &res)
}
func testGetMultiSigAccountsCmd(t *testing.T, jrpc *jsonclient.JSONClient) error {
params := &rpctypes.Query4Jrpc{
Execer: mty.MultiSigX,
FuncName: "MultiSigAccounts",
Payload: types.MustPBToJSON(&mty.ReqMultiSigAccs{}),
}
var res mty.ReplyMultiSigAccs
return jrpc.Call("Chain33.Query", params, &res)
}
func testGetMultiSigAccountInfoCmd(t *testing.T, jrpc *jsonclient.JSONClient) error {
params := &rpctypes.Query4Jrpc{
Execer: mty.MultiSigX,
FuncName: "MultiSigAccountInfo",
Payload: types.MustPBToJSON(&mty.ReqMultiSigAccInfo{}),
}
var res mty.MultiSig
return jrpc.Call("Chain33.Query", params, &res)
}
func testGetMultiSigAccTxCountCmd(t *testing.T, jrpc *jsonclient.JSONClient) error {
params := &rpctypes.Query4Jrpc{
Execer: mty.MultiSigX,
FuncName: "MultiSigAccTxCount",
Payload: types.MustPBToJSON(&mty.ReqMultiSigAccInfo{}),
}
var res mty.Uint64
return jrpc.Call("Chain33.Query", params, &res)
}
func testGetMultiSigTxidsCmd(t *testing.T, jrpc *jsonclient.JSONClient) error {
params := &rpctypes.Query4Jrpc{
Execer: mty.MultiSigX,
FuncName: "MultiSigTxids",
Payload: types.MustPBToJSON(&mty.ReqMultiSigTxids{}),
}
var res mty.ReplyMultiSigTxids
return jrpc.Call("Chain33.Query", params, &res)
}
func testGetMultiSigTxInfoCmd(t *testing.T, jrpc *jsonclient.JSONClient) error {
var rep interface{}
var params rpctypes.Query4Jrpc
req := &mty.ReqMultiSigTxInfo{}
params.Execer = mty.MultiSigX
params.FuncName = "MultiSigTxInfo"
params.Payload = types.MustPBToJSON(req)
rep = &mty.MultiSigTx{}
return jrpc.Call("Chain33.Query", &params, rep)
}
func testGetGetMultiSigTxConfirmedWeightCmd(t *testing.T, jrpc *jsonclient.JSONClient) error {
var rep interface{}
var params rpctypes.Query4Jrpc
req := &mty.ReqMultiSigTxInfo{}
params.Execer = mty.MultiSigX
params.FuncName = "MultiSigTxConfirmedWeight"
params.Payload = types.MustPBToJSON(req)
rep = &mty.Uint64{}
return jrpc.Call("Chain33.Query", &params, rep)
}
func testGetGetMultiSigAccUnSpentTodayCmd(t *testing.T, jrpc *jsonclient.JSONClient) error {
var rep interface{}
var params rpctypes.Query4Jrpc
req := &mty.ReqAccAssets{}
req.IsAll = true
params.Execer = mty.MultiSigX
params.FuncName = "MultiSigAccUnSpentToday"
params.Payload = types.MustPBToJSON(req)
rep = &mty.ReplyUnSpentAssets{}
return jrpc.Call("Chain33.Query", &params, rep)
}
func testGetMultiSigAccAssetsCmd(t *testing.T, jrpc *jsonclient.JSONClient) error {
var rep interface{}
var params rpctypes.Query4Jrpc
req := &mty.ReqAccAssets{}
req.IsAll = true
params.Execer = mty.MultiSigX
params.FuncName = "MultiSigAccAssets"
params.Payload = types.MustPBToJSON(req)
rep = &mty.ReplyAccAssets{}
return jrpc.Call("Chain33.Query", &params, rep)
}
func testGetMultiSigAccAllAddressCmd(t *testing.T, jrpc *jsonclient.JSONClient) error {
var rep interface{}
var params rpctypes.Query4Jrpc
req := mty.ReqMultiSigAccInfo{
MultiSigAccAddr: "14jv8WB7CwNQSnh4qo9WDBgRPRBjM5LQo6",
}
params.Execer = mty.MultiSigX
params.FuncName = "MultiSigAccAllAddress"
params.Payload = types.MustPBToJSON(&req)
rep = &mty.AccAddress{}
return jrpc.Call("Chain33.Query", &params, rep)
}
// Copyright Fuzamei Corp. 2018 All Rights Reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package rpc
import (
"encoding/hex"
"github.com/33cn/chain33/types"
mty "github.com/33cn/plugin/plugin/dapp/multisig/types"
)
// MultiSigAccCreateTx :构造创建多重签名账户的交易
func (c *Jrpc) MultiSigAccCreateTx(param *mty.MultiSigAccCreate, result *interface{}) error {
if param == nil {
return types.ErrInvalidParam
}
data, err := types.CallCreateTx(types.ExecName(mty.MultiSigX), "MultiSigAccCreate", param)
if err != nil {
return err
}
*result = hex.EncodeToString(data)
return nil
}
// MultiSigOwnerOperateTx :构造修改多重签名账户owner属性的交易
func (c *Jrpc) MultiSigOwnerOperateTx(param *mty.MultiSigOwnerOperate, result *interface{}) error {
if param == nil {
return types.ErrInvalidParam
}
data, err := types.CallCreateTx(types.ExecName(mty.MultiSigX), "MultiSigOwnerOperate", param)
if err != nil {
return err
}
*result = hex.EncodeToString(data)
return nil
}
// MultiSigAccOperateTx :构造修改多重签名账户属性的交易
func (c *Jrpc) MultiSigAccOperateTx(param *mty.MultiSigAccOperate, result *interface{}) error {
if param == nil {
return types.ErrInvalidParam
}
data, err := types.CallCreateTx(types.ExecName(mty.MultiSigX), "MultiSigAccOperate", param)
if err != nil {
return err
}
*result = hex.EncodeToString(data)
return nil
}
// MultiSigConfirmTx :构造确认多重签名账户的交易
func (c *Jrpc) MultiSigConfirmTx(param *mty.MultiSigConfirmTx, result *interface{}) error {
if param == nil {
return types.ErrInvalidParam
}
data, err := types.CallCreateTx(types.ExecName(mty.MultiSigX), "MultiSigConfirmTx", param)
if err != nil {
return err
}
*result = hex.EncodeToString(data)
return nil
}
// MultiSigAccTransferInTx :构造在多重签名合约中转账到多重签名账户的交易
func (c *Jrpc) MultiSigAccTransferInTx(param *mty.MultiSigExecTransferTo, result *interface{}) error {
if param == nil {
return types.ErrInvalidParam
}
v := *param
data, err := types.CallCreateTx(types.ExecName(mty.MultiSigX), "MultiSigExecTransferTo", &v)
if err != nil {
return err
}
*result = hex.EncodeToString(data)
return nil
}
// MultiSigAccTransferOutTx :构造在多重签名合约中从多重签名账户转账的交易
func (c *Jrpc) MultiSigAccTransferOutTx(param *mty.MultiSigExecTransferFrom, result *interface{}) error {
if param == nil {
return types.ErrInvalidParam
}
v := *param
data, err := types.CallCreateTx(types.ExecName(mty.MultiSigX), "MultiSigExecTransferFrom", &v)
if err != nil {
return err
}
*result = hex.EncodeToString(data)
return nil
}
......@@ -8,12 +8,12 @@ import (
"github.com/33cn/chain33/rpc/types"
)
// Jrpc jrpc句柄
// Jrpc 申明Jrpc结构体
type Jrpc struct {
cli *channelClient
}
// Grpc grpc句柄
// Grpc 申明Grpc结构体
type Grpc struct {
*channelClient
}
......@@ -22,7 +22,7 @@ type channelClient struct {
types.ChannelClient
}
// Init 初始化rpc
// Init 初始化rpc实例
func Init(name string, s types.RPCServer) {
cli := &channelClient{}
grpc := &Grpc{channelClient: cli}
......
// Copyright Fuzamei Corp. 2018 All Rights Reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package types
import (
"strings"
"github.com/33cn/chain33/common/log/log15"
"github.com/33cn/chain33/types"
)
var multisiglog = log15.New("module", "execs.multisig")
// OwnerAdd : 交易操作类型
var (
OwnerAdd uint64 = 1
OwnerDel uint64 = 2
OwnerModify uint64 = 3
OwnerReplace uint64 = 4
//AccWeightOp 账户属性的操作
AccWeightOp = true
AccDailyLimitOp = false
//OwnerOperate 多重签名交易类型:转账,owner操作,account操作
OwnerOperate uint64 = 1
AccountOperate uint64 = 2
TransferOperate uint64 = 3
//IsSubmit :
IsSubmit = true
IsConfirm = false
MultiSigX = "multisig"
OneDaySecond int64 = 24 * 3600
MinOwnersInit = 2
MinOwnersCount = 1 //一个多重签名的账户最少要保留一个owner
MaxOwnersCount = 20 //一个多重签名的账户最多拥有20个owner
Multisiglog = log15.New("module", MultiSigX)
)
// MultiSig 交易的actionid
const (
ActionMultiSigAccCreate = 10000
ActionMultiSigOwnerOperate = 10001
ActionMultiSigAccOperate = 10002
ActionMultiSigConfirmTx = 10003
ActionMultiSigExecTransferTo = 10004
ActionMultiSigExecTransferFrom = 10005
)
//多重签名账户执行输出的logid
const (
TyLogMultiSigAccCreate = 10000 //只输出多重签名的账户地址
TyLogMultiSigOwnerAdd = 10001 //输出add的owner:addr和weight
TyLogMultiSigOwnerDel = 10002 //输出del的owner:addr和weight
TyLogMultiSigOwnerModify = 10003 //输出modify的owner:preweight以及currentweight
TyLogMultiSigOwnerReplace = 10004 //输出old的owner的信息:以及当前的owner信息:addr+weight
TyLogMultiSigAccWeightModify = 10005 //输出修改前后确认权重的值:preReqWeight和curReqWeight
TyLogMultiSigAccDailyLimitAdd = 10006 //输出add的DailyLimit:Symbol和DailyLimit
TyLogMultiSigAccDailyLimitModify = 10007 //输出modify的DailyLimit:preDailyLimit以及currentDailyLimit
TyLogMultiSigConfirmTx = 10008 //对某笔未执行交易的确认
TyLogMultiSigConfirmTxRevoke = 10009 //已经确认交易的撤销只针对还未执行的交易
TyLogDailyLimitUpdate = 10010 //DailyLimit更新,DailyLimit在Submit和Confirm阶段都可能有变化
TyLogMultiSigTx = 10011 //在Submit提交交易阶段才会有更新
TyLogTxCountUpdate = 10012 //txcount只在在Submit阶段提交新的交易是才会增加计数
)
//AccAssetsResult 账户资产cli的显示,主要是amount需要转换成浮点型字符串
type AccAssetsResult struct {
Execer string `json:"execer,omitempty"`
Symbol string `json:"symbol,omitempty"`
Currency int32 `json:"currency,omitempty"`
Balance string `json:"balance,omitempty"`
Frozen string `json:"frozen,omitempty"`
Receiver string `json:"receiver,omitempty"`
Addr string `json:"addr,omitempty"`
}
//DailyLimitResult 每日限额信息的显示cli
type DailyLimitResult struct {
Symbol string `json:"symbol,omitempty"`
Execer string `json:"execer,omitempty"`
DailyLimit string `json:"dailyLimit,omitempty"`
SpentToday string `json:"spent,omitempty"`
LastDay string `json:"lastday,omitempty"`
}
//MultiSigResult 多重签名账户信息的显示cli
type MultiSigResult struct {
CreateAddr string `json:"createAddr,omitempty"`
MultiSigAddr string `json:"multiSigAddr,omitempty"`
Owners []*Owner `json:"owners,omitempty"`
DailyLimits []*DailyLimitResult `json:"dailyLimits,omitempty"`
TxCount uint64 `json:"txCount,omitempty"`
RequiredWeight uint64 `json:"requiredWeight,omitempty"`
}
//UnSpentAssetsResult 每日限额之内未花费额度的显示cli
type UnSpentAssetsResult struct {
Symbol string `json:"symbol,omitempty"`
Execer string `json:"execer,omitempty"`
UnSpent string `json:"unspent,omitempty"`
}
//IsAssetsInvalid 资产的合法性检测,Symbol:必须全部大写,例如:BTY,coins.BTY。exec:必须在types.AllowUserExec中存在
func IsAssetsInvalid(exec, symbol string) error {
//exec检测
allowExeName := types.AllowUserExec
nameLen := len(allowExeName)
execValid := false
for i := 0; i < nameLen; i++ {
if exec == string(allowExeName[i]) {
execValid = true
break
}
}
if !execValid {
multisiglog.Error("IsAssetsInvalid", "exec", exec)
return ErrInvalidExec
}
//Symbol检测
symbolstr := strings.Split(symbol, ".")[len(strings.Split(symbol, "."))-1]
valid := validSymbol([]byte(symbolstr))
if !valid {
multisiglog.Error("IsAssetsInvalid", "symbol", symbol)
return ErrInvalidSymbol
}
return nil
}
func isUpperChar(a byte) bool {
res := (a <= 'Z' && a >= 'A')
return res
}
func validSymbol(cs []byte) bool {
for _, c := range cs {
if !isUpperChar(c) {
return false
}
}
return true
}
// Copyright Fuzamei Corp. 2018 All Rights Reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package types
import "errors"
//multisig 合约的错误码
var (
ErrRequiredweight = errors.New("ErrRequiredweight")
ErrCreatAccountAddr = errors.New("ErrCreatAccountAddr")
ErrOwnerExist = errors.New("ErrOwnerExist")
ErrOwnerNotExist = errors.New("ErrOwnerNotExist")
ErrTotalWeightNotEnough = errors.New("ErrTotalWeightNotEnough")
ErrIsNotOwner = errors.New("ErrIsNotOwner")
ErrDailyLimitIsZero = errors.New("ErrDailyLimitIsZero")
ErrInvalidTxid = errors.New("ErrInvalidTxid")
ErrTxidNotExist = errors.New("ErrTxidNotExist")
ErrTxHasExecuted = errors.New("ErrTxHasExecuted")
ErrDupConfirmed = errors.New("ErrDupConfirmed")
ErrConfirmNotExist = errors.New("ErrConfirmNotExist")
ErrExecerHashNoMatch = errors.New("ErrExecerHashNoMatch")
ErrPayLoadTypeNoMatch = errors.New("ErrPayLoadTypeNoMatch")
ErrTxHashNoMatch = errors.New("ErrTxHashNoMatch")
ErrAccCountNoMatch = errors.New("ErrAccCountNoMatch")
ErrAccountHasExist = errors.New("ErrAccountHasExist")
ErrOwnerNoMatch = errors.New("ErrOwnerNoMatch")
ErrDailyLimitNoMatch = errors.New("ErrDailyLimitNoMatch")
ErrExecutedNoMatch = errors.New("ErrExecutedNoMatch")
ErrActionTyNoMatch = errors.New("ErrActionTyNoMatch")
ErrTxTypeNoMatch = errors.New("ErrTxTypeNoMatch")
ErrTxidHasExist = errors.New("ErrTxidHasExist")
ErrOnlyOneOwner = errors.New("ErrOnlyOneOwner")
ErrOperateType = errors.New("ErrOperateType")
ErrNewOwnerExist = errors.New("ErrNewOwnerExist")
ErrOwnerLessThanTwo = errors.New("ErrOwnerLessThanTwo")
ErrAddrNotSupport = errors.New("ErrAddrNotSupport")
ErrMaxOwnerCount = errors.New("ErrMaxOwnerCount")
ErrInvalidSymbol = errors.New("ErrInvalidSymbol")
ErrInvalidExec = errors.New("ErrInvalidExec")
ErrInvalidWeight = errors.New("ErrInvalidWeight")
ErrInvalidDailyLimit = errors.New("ErrInvalidDailyLimit")
)
This diff is collapsed.
// Copyright Fuzamei Corp. 2018 All Rights Reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package types
import (
"reflect"
"github.com/33cn/chain33/types"
)
func init() {
types.AllowUserExec = append(types.AllowUserExec, []byte(MultiSigX))
types.RegistorExecutor(MultiSigX, NewType())
types.RegisterDappFork(MultiSigX, "Enable", 0)
}
// MultiSigType multisig合约结构体
type MultiSigType struct {
types.ExecTypeBase
}
// NewType new一个新的multisig合约实例
func NewType() *MultiSigType {
c := &MultiSigType{}
c.SetChild(c)
return c
}
//GetPayload 获取交易payload的结构体信息:也就是multisig.pb.go中定义的具体交易类型结构体
func (m *MultiSigType) GetPayload() types.Message {
return &MultiSigAction{}
}
//GetName 获取合约name
func (m *MultiSigType) GetName() string {
return MultiSigX
}
//GetTypeMap 获取处理具体交易的接口函数,也就是exec.go中的函数实现,去掉EXEC_
func (m *MultiSigType) GetTypeMap() map[string]int32 {
return map[string]int32{
"MultiSigAccCreate": ActionMultiSigAccCreate,
"MultiSigOwnerOperate": ActionMultiSigOwnerOperate,
"MultiSigAccOperate": ActionMultiSigAccOperate,
"MultiSigConfirmTx": ActionMultiSigConfirmTx,
"MultiSigExecTransferTo": ActionMultiSigExecTransferTo,
"MultiSigExecTransferFrom": ActionMultiSigExecTransferFrom,
}
}
//GetLogMap 获取具体执行Receiptlog对应的结构体:
func (m *MultiSigType) GetLogMap() map[int64]*types.LogInfo {
return map[int64]*types.LogInfo{
TyLogMultiSigAccCreate: {Ty: reflect.TypeOf(MultiSig{}), Name: "LogMultiSigAccCreate"},
TyLogMultiSigOwnerAdd: {Ty: reflect.TypeOf(ReceiptOwnerAddOrDel{}), Name: "LogMultiSigOwnerAdd"},
TyLogMultiSigOwnerDel: {Ty: reflect.TypeOf(ReceiptOwnerAddOrDel{}), Name: "LogMultiSigOwnerDel"},
TyLogMultiSigOwnerModify: {Ty: reflect.TypeOf(ReceiptOwnerModOrRep{}), Name: "LogMultiSigOwnerModify"},
TyLogMultiSigOwnerReplace: {Ty: reflect.TypeOf(ReceiptOwnerModOrRep{}), Name: "LogMultiSigOwnerReplace"},
TyLogMultiSigAccWeightModify: {Ty: reflect.TypeOf(ReceiptWeightModify{}), Name: "LogMultiSigAccWeightModify"},
TyLogMultiSigAccDailyLimitAdd: {Ty: reflect.TypeOf(ReceiptDailyLimitOperate{}), Name: "LogMultiSigAccDailyLimitAdd"},
TyLogMultiSigAccDailyLimitModify: {Ty: reflect.TypeOf(ReceiptDailyLimitOperate{}), Name: "LogMultiSigAccDailyLimitModify"},
TyLogMultiSigConfirmTx: {Ty: reflect.TypeOf(ReceiptConfirmTx{}), Name: "LogMultiSigConfirmTx"},
TyLogMultiSigConfirmTxRevoke: {Ty: reflect.TypeOf(ReceiptConfirmTx{}), Name: "LogMultiSigConfirmTxRevoke"},
TyLogDailyLimitUpdate: {Ty: reflect.TypeOf(ReceiptAccDailyLimitUpdate{}), Name: "LogAccDailyLimitUpdate"},
TyLogMultiSigTx: {Ty: reflect.TypeOf(ReceiptMultiSigTx{}), Name: "LogMultiSigAccTx"},
TyLogTxCountUpdate: {Ty: reflect.TypeOf(ReceiptTxCountUpdate{}), Name: "LogTxCountUpdate"},
}
}
//DecodePayload 解码交易的Payload信息
func (m MultiSigType) DecodePayload(tx *types.Transaction) (types.Message, error) {
var action MultiSigAction
err := types.Decode(tx.Payload, &action)
if err != nil {
return nil, err
}
return &action, nil
}
//ActionName 获取actionid对应的name
func (m MultiSigType) ActionName(tx *types.Transaction) string {
var g MultiSigAction
err := types.Decode(tx.Payload, &g)
if err != nil {
return "unknown-MultiSig-action-err"
}
if g.Ty == ActionMultiSigAccCreate && g.GetMultiSigAccCreate() != nil {
return "MultiSigAccCreate"
} else if g.Ty == ActionMultiSigOwnerOperate && g.GetMultiSigOwnerOperate() != nil {
return "MultiSigOwnerOperate"
} else if g.Ty == ActionMultiSigAccOperate && g.GetMultiSigAccOperate() != nil {
return "MultiSigAccOperate"
} else if g.Ty == ActionMultiSigConfirmTx && g.GetMultiSigConfirmTx() != nil {
return "MultiSigTxConfirm"
} else if g.Ty == ActionMultiSigExecTransferTo && g.GetMultiSigExecTransferTo() != nil {
return "MultiSigExecTransfer"
} else if g.Ty == ActionMultiSigExecTransferFrom && g.GetMultiSigExecTransferFrom() != nil {
return "MultiSigAccExecTransfer"
}
return "unknown"
}
......@@ -29,6 +29,11 @@ func NewType() *NormType {
return c
}
// GetName 获取执行器名称
func (norm *NormType) GetName() string {
return NormX
}
// GetPayload method
func (norm *NormType) GetPayload() types.Message {
return &NormAction{}
......
......@@ -62,6 +62,7 @@ grpcFuncWhitelist=["*"]
mainnetJrpcAddr= "http://localhost:8801"
[mempool]
name="timeline"
poolCacheSize=10240
minTxFee=100000
maxTxNumPerAccount=10000
......
......@@ -63,6 +63,7 @@ grpcFuncWhitelist=["*"]
mainnetJrpcAddr= "http://localhost:8801"
[mempool]
name="timeline"
poolCacheSize=10240
minTxFee=100000
maxTxNumPerAccount=10000
......@@ -71,7 +72,7 @@ maxTxNumPerAccount=10000
name="para"
genesisBlockTime=1514533394
genesis="14KEKbYtKKQm4wMthSK9J4La4nAiidGozt"
ParaRemoteGrpcClient = "localhost:8802"
ParaRemoteGrpcClient="localhost:8802"
#主链指定高度的区块开始同步
startHeight=345850
#打包时间间隔,单位秒
......@@ -82,6 +83,7 @@ emptyBlockInterval=50
authAccount=""
#等待平行链共识消息在主链上链并成功的块数,超出会重发共识消息,最小是2
waitBlocks4CommitMsg=2
searchHashMatchedBlockDepth=100
[mver.consensus]
......
......@@ -5,6 +5,8 @@ services:
entrypoint: /root/entrypoint.sh
environment:
PARAFILE: "/root/chain33.para33.toml"
expose:
- "8802"
chain32:
entrypoint: /root/entrypoint.sh
......@@ -20,3 +22,16 @@ services:
entrypoint: /root/entrypoint.sh
environment:
PARAFILE: "/root/chain33.para30.toml"
expose:
- "8802"
nginx:
image: nginx:latest
depends_on:
- chain33
- chain30
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf
expose:
- "8803"
#!/usr/bin/env bash
/root/chain33 -f /root/chain33.toml &
# to wait nginx start
sleep 15
/root/chain33 -f "$PARAFILE"
#user nobody;
worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
#tcp_nopush on;
#keepalive_timeout 0;
keepalive_timeout 1000;
#gzip on;
upstream chain33url{
ip_hash;
server chain33:8802 weight=1;
#server chain30:8802 weight=1;
}
server {
listen 8803 http2;
server_name localhost;
#charset koi8-r;
#access_log logs/host.access.log main;
location / {
#proxy_pass http://yankerp;
grpc_pass grpc://chain33url;
}
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}
......@@ -30,13 +30,14 @@ function para_set_toml() {
sed -i $xsedfix 's/^Title.*/Title="user.p.'''$PARANAME'''."/g' "${1}"
sed -i $xsedfix 's/^# TestNet=.*/TestNet=true/g' "${1}"
sed -i $xsedfix 's/^startHeight=.*/startHeight=20/g' "${1}"
sed -i $xsedfix 's/^startHeight=.*/startHeight=0/g' "${1}"
sed -i $xsedfix 's/^emptyBlockInterval=.*/emptyBlockInterval=4/g' "${1}"
# rpc
sed -i $xsedfix 's/^jrpcBindAddr=.*/jrpcBindAddr="0.0.0.0:8901"/g' "${1}"
sed -i $xsedfix 's/^grpcBindAddr=.*/grpcBindAddr="0.0.0.0:8902"/g' "${1}"
sed -i $xsedfix 's/^whitelist=.*/whitelist=["localhost","127.0.0.1","0.0.0.0"]/g' "${1}"
sed -i $xsedfix 's/^ParaRemoteGrpcClient=.*/ParaRemoteGrpcClient="nginx:8803"/g' "${1}"
}
function para_set_wallet() {
......
......@@ -86,7 +86,7 @@ func (e *Paracross) ExecLocal_Miner(payload *pt.ParacrossMinerAction, tx *types.
hash := tx.Hash()
mixTxHashs = append(mixTxHashs, hash)
//跨链交易包含了主链交易,需要过滤出来
if types.IsParaExecName(string(tx.Execer)) {
if types.IsMyParaExecName(string(tx.Execer)) {
paraTxHashs = append(paraTxHashs, hash)
}
}
......@@ -100,7 +100,7 @@ func (e *Paracross) ExecLocal_Miner(payload *pt.ParacrossMinerAction, tx *types.
i = int(end) - 1
continue
}
if types.IsParaExecName(string(tx.Execer)) &&
if types.IsMyParaExecName(string(tx.Execer)) &&
bytes.HasSuffix(tx.Execer, []byte(pt.ParaX)) {
crossTxHashs = append(crossTxHashs, tx.Hash())
}
......
......@@ -87,7 +87,7 @@ func crossTxGroupProc(txs []*types.Transaction, index int) ([]*types.Transaction
//cross asset transfer in tx group
var transfers []*types.Transaction
for i := headIdx; i < endIdx; i++ {
if types.IsParaExecName(string(txs[i].Execer)) &&
if types.IsMyParaExecName(string(txs[i].Execer)) &&
bytes.HasSuffix(txs[i].Execer, []byte(pt.ParaX)) {
transfers = append(transfers, txs[i])
......
......@@ -23,4 +23,8 @@ var (
ErrParaEmptyMinerTx = errors.New("ErrParaEmptyMinerTx")
// ErrParaMinerExecErr miner tx exec error
ErrParaMinerExecErr = errors.New("ErrParaMinerExecErr")
// ErrParaWaitingNewSeq para waiting main node new seq coming
ErrParaWaitingNewSeq = errors.New("ErrParaWaitingNewSeq")
// ErrParaCurHashNotMatch para curr main hash not match with pre, main node may switched
ErrParaCurHashNotMatch = errors.New("ErrParaCurHashNotMatch")
)
......@@ -42,6 +42,11 @@ func NewType() *ParacrossType {
return c
}
// GetName 获取执行器名称
func (p *ParacrossType) GetName() string {
return ParaX
}
// GetLogMap get receipt log map
func (p *ParacrossType) GetLogMap() map[int64]*types.LogInfo {
return map[int64]*types.LogInfo{
......
......@@ -56,19 +56,15 @@ func pokerbullStart(cmd *cobra.Command, args []string) {
rpcLaddr, _ := cmd.Flags().GetString("rpc_laddr")
value, _ := cmd.Flags().GetUint64("value")
playerCount, _ := cmd.Flags().GetUint32("playerCount")
fee, _ := cmd.Flags().GetFloat64("fee")
feeInt64 := int64(fee * 1e4)
amountInt64 := int64(value)
params := &pkt.PBStartTxReq{
Value: amountInt64 * types.Coin,
PlayerNum: int32(playerCount),
Fee: feeInt64,
params := &rpctypes.CreateTxIn{
Execer: types.ExecName(pkt.PokerBullX),
ActionName: pkt.CreateStartTx,
Payload: []byte(fmt.Sprintf("{\"value\":%d,\"playerNum\":%d}", int64(value)*types.Coin, int32(playerCount))),
}
var res string
ctx := jsonrpc.NewRPCCtx(rpcLaddr, "pokerbull.PokerBullStartTx", params, &res)
ctx := jsonrpc.NewRPCCtx(rpcLaddr, "Chain33.CreateTransaction", params, &res)
ctx.RunWithoutMarshal()
}
......@@ -91,17 +87,15 @@ func addPokerbullContinueFlags(cmd *cobra.Command) {
func pokerbullContinue(cmd *cobra.Command, args []string) {
rpcLaddr, _ := cmd.Flags().GetString("rpc_laddr")
gameID, _ := cmd.Flags().GetString("gameID")
fee, _ := cmd.Flags().GetFloat64("fee")
feeInt64 := int64(fee * 1e4)
params := &pkt.PBContinueTxReq{
GameId: gameID,
Fee: feeInt64,
params := &rpctypes.CreateTxIn{
Execer: types.ExecName(pkt.PokerBullX),
ActionName: pkt.CreateContinueTx,
Payload: []byte(fmt.Sprintf("{\"gameId\":\"%s\"}", gameID)),
}
var res string
ctx := jsonrpc.NewRPCCtx(rpcLaddr, "pokerbull.PokerBullContinueTx", params, &res)
ctx := jsonrpc.NewRPCCtx(rpcLaddr, "Chain33.CreateTransaction", params, &res)
ctx.RunWithoutMarshal()
}
......@@ -124,17 +118,15 @@ func addPokerbullQuitFlags(cmd *cobra.Command) {
func pokerbullQuit(cmd *cobra.Command, args []string) {
rpcLaddr, _ := cmd.Flags().GetString("rpc_laddr")
gameID, _ := cmd.Flags().GetString("gameID")
fee, _ := cmd.Flags().GetFloat64("fee")
feeInt64 := int64(fee * 1e4)
params := &pkt.PBContinueTxReq{
GameId: gameID,
Fee: feeInt64,
params := &rpctypes.CreateTxIn{
Execer: types.ExecName(pkt.PokerBullX),
ActionName: pkt.CreatequitTx,
Payload: []byte(fmt.Sprintf("{\"gameId\":\"%s\"}", gameID)),
}
var res string
ctx := jsonrpc.NewRPCCtx(rpcLaddr, "pokerbull.PokerBullQuitTx", params, &res)
ctx := jsonrpc.NewRPCCtx(rpcLaddr, "Chain33.CreateTransaction", params, &res)
ctx.RunWithoutMarshal()
}
......@@ -155,6 +147,7 @@ func addPokerbullQueryFlags(cmd *cobra.Command) {
cmd.Flags().StringP("index", "i", "", "index")
cmd.Flags().StringP("status", "s", "", "status")
cmd.Flags().StringP("gameIDs", "d", "", "gameIDs")
cmd.Flags().StringP("round", "r", "", "round")
}
func pokerbullQuery(cmd *cobra.Command, args []string) {
......@@ -166,6 +159,7 @@ func pokerbullQuery(cmd *cobra.Command, args []string) {
indexstr, _ := cmd.Flags().GetString("index")
index, _ := strconv.ParseInt(indexstr, 10, 64)
gameIDs, _ := cmd.Flags().GetString("gameIDs")
round, _ := cmd.Flags().GetString("round")
var params rpctypes.Query4Jrpc
params.Execer = pkt.PokerBullX
......@@ -177,10 +171,27 @@ func pokerbullQuery(cmd *cobra.Command, args []string) {
}
params.Payload = types.MustPBToJSON(req)
if gameID != "" {
params.FuncName = pkt.FuncNameQueryGameByID
var res pkt.ReplyPBGame
ctx := jsonrpc.NewRPCCtx(rpcLaddr, "Chain33.Query", params, &res)
ctx.Run()
if round == "" {
params.FuncName = pkt.FuncNameQueryGameByID
var res pkt.ReplyPBGame
ctx := jsonrpc.NewRPCCtx(rpcLaddr, "Chain33.Query", params, &res)
ctx.Run()
} else {
params.FuncName = pkt.FuncNameQueryGameByRound
roundInt, err := strconv.ParseInt(round, 10, 32)
if err != nil {
fmt.Println(err)
return
}
req := &pkt.QueryPBGameByRound{
GameId: gameID,
Round: int32(roundInt),
}
params.Payload = types.MustPBToJSON(req)
var res pkt.ReplyPBGameByRound
ctx := jsonrpc.NewRPCCtx(rpcLaddr, "Chain33.Query", params, &res)
ctx.Run()
}
} else if address != "" {
params.FuncName = pkt.FuncNameQueryGameByAddr
var res pkt.PBGameRecords
......
......@@ -70,7 +70,7 @@ func calcPBGameStatusKey(status int32, index int64) []byte {
}
func calcPBGameStatusAndPlayerKey(status, player int32, value, index int64) []byte {
key := fmt.Sprintf("LODB-pokerbull-status:%d:%d:%d:%018d", status, player, value, index)
key := fmt.Sprintf("LODB-pokerbull-status:%d:%d:%015d:%018d", status, player, value, index)
return []byte(key)
}
......@@ -79,7 +79,7 @@ func calcPBGameStatusAndPlayerPrefix(status, player int32, value int64) []byte {
if value == 0 {
key = fmt.Sprintf("LODB-pokerbull-status:%d:%d:", status, player)
} else {
key = fmt.Sprintf("LODB-pokerbull-status:%d:%d:%d", status, player, value)
key = fmt.Sprintf("LODB-pokerbull-status:%d:%d:%015d", status, player, value)
}
return []byte(key)
......
......@@ -29,7 +29,6 @@ func (g *PokerBull) Query_QueryGameByAddr(in *pkt.QueryPBGameInfo) (types.Messag
if err != nil {
return nil, err
}
return gameIds, nil
}
......@@ -42,3 +41,49 @@ func (g *PokerBull) Query_QueryGameByStatus(in *pkt.QueryPBGameInfo) (types.Mess
return gameIds, nil
}
// Query_QueryGameByRound 查询某一回合游戏结果
func (g *PokerBull) Query_QueryGameByRound(in *pkt.QueryPBGameByRound) (types.Message, error) {
game, err := readGame(g.GetStateDB(), in.GetGameId())
if err != nil {
return nil, err
}
if in.Round > game.Round {
return nil, types.ErrInvalidParam
}
var roundPlayers []*pkt.PBPlayer
for _, player := range game.Players {
var isReady bool
if in.Round == game.Round {
isReady = player.Ready
} else {
isReady = false
}
roundPlayer := &pkt.PBPlayer{
Address: player.Address,
Ready: isReady,
}
roundPlayers = append(roundPlayers, roundPlayer)
}
var result *pkt.PBResult
if len(game.Results) < int(in.Round) {
result = nil
} else {
result = game.Results[in.Round-1]
}
gameInfo := &pkt.ReplyPBGameByRound{
GameId: game.GameId,
Status: game.Status,
Result: result,
IsWaiting: game.IsWaiting,
Value: game.Value,
Players: roundPlayers,
Return: (game.Value / types.Coin) * pkt.WinnerReturn,
}
return gameInfo, nil
}
......@@ -8,7 +8,6 @@ import (
"github.com/33cn/chain33/pluginmgr"
"github.com/33cn/plugin/plugin/dapp/pokerbull/commands"
"github.com/33cn/plugin/plugin/dapp/pokerbull/executor"
"github.com/33cn/plugin/plugin/dapp/pokerbull/rpc"
"github.com/33cn/plugin/plugin/dapp/pokerbull/types"
)
......@@ -18,6 +17,5 @@ func init() {
ExecName: executor.GetName(),
Exec: executor.Init,
Cmd: commands.PokerBullCmd,
RPC: rpc.Init,
})
}
syntax = "proto3";
import "transaction.proto";
package types;
//斗牛游戏内容
message PokerBull {
string gameId = 1; //默认是由创建这局游戏的txHash作为gameId
int32 status = 2; // Start 1 -> Continue 2 -> Quit 3
int64 startTime = 3; //开始时间
string startTxHash = 4; //游戏启动交易hash
int64 value = 5; //赌注
PBPoker poker = 6; //扑克牌
repeated PBPlayer players = 7; //玩家历史牌和结果集
int32 playerNum = 8; //玩家数
repeated PBResult results = 9; //游戏结果集
int64 index = 10; //索引
int64 prevIndex = 11; //上级索引
int64 quitTime = 12; //游戏结束时间
string quitTxHash = 13; //游戏结束交易hash
string dealerAddr = 14; //下局庄家地址
bool isWaiting = 15; //游戏是否处于等待状态
int32 preStatus = 16; //上一index的状态
string gameId = 1; //默认是由创建这局游戏的txHash作为gameId
int32 status = 2; // Start 1 -> Continue 2 -> Quit 3
int64 startTime = 3; //开始时间
string startTxHash = 4; //游戏启动交易hash
int64 value = 5; //赌注
PBPoker poker = 6; //扑克牌
repeated PBPlayer players = 7; //玩家历史牌和结果集
int32 playerNum = 8; //玩家数
repeated PBResult results = 9; //游戏结果集
int64 index = 10; //索引
int64 prevIndex = 11; //上级索引
int64 quitTime = 12; //游戏结束时间
string quitTxHash = 13; //游戏结束交易hash
string dealerAddr = 14; //下局庄家地址
bool isWaiting = 15; //游戏是否处于等待状态
int32 preStatus = 16; //上一index的状态
int32 round = 17; //当前游戏回合数
}
//一把牌
......@@ -111,6 +110,10 @@ message PBGameRecords {
repeated PBGameRecord records = 1;
}
message PBGameIndexRecords {
repeated PBGameIndexRecord records = 1;
}
message QueryPBGameInfo {
string gameId = 1;
string addr = 2;
......@@ -130,6 +133,23 @@ message ReplyPBGameList {
repeated PokerBull games = 1;
}
// QueryPBGameByRound 根据gameId和回合数查询某回合的游戏结果
message QueryPBGameByRound {
string gameId = 1;
int32 round = 2;
}
// ReplyPBGameByRound 某一回合游戏结果
message ReplyPBGameByRound {
string gameId = 1;
int32 status = 2;
PBResult result = 3;
bool isWaiting = 4;
int64 value = 5;
repeated PBPlayer players = 6;
int64 return = 7;
}
message ReceiptPBGame {
string gameId = 1;
int32 status = 2;
......@@ -140,7 +160,8 @@ message ReceiptPBGame {
int64 value = 7;
bool isWaiting = 8;
repeated string players = 9;
int32 preStatus = 10;
int32 preStatus = 10;
int32 round = 11;
}
message PBStartTxReq {
......@@ -164,12 +185,3 @@ message PBQueryReq {
int64 fee = 2;
}
// pokerbull 对外提供服务的接口
service pokerbull {
//游戏开始
rpc Start(PBGameStart) returns (UnsignTx) {}
//游戏继续
rpc Continue(PBGameContinue) returns (UnsignTx) {}
//游戏结束
rpc Quit(PBGameQuit) returns (UnsignTx) {}
}
// Copyright Fuzamei Corp. 2018 All Rights Reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package rpc
import (
"context"
"encoding/hex"
"github.com/33cn/chain33/types"
pb "github.com/33cn/plugin/plugin/dapp/pokerbull/types"
)
// PokerBullStartTx 创建游戏开始交易
func (c *Jrpc) PokerBullStartTx(parm *pb.PBStartTxReq, result *interface{}) error {
if parm == nil {
return types.ErrInvalidParam
}
head := &pb.PBGameStart{
Value: parm.Value,
PlayerNum: parm.PlayerNum,
}
reply, err := c.cli.Start(context.Background(), head)
if err != nil {
return err
}
*result = hex.EncodeToString(reply.Data)
return nil
}
// PokerBullContinueTx 创建游戏继续交易
func (c *Jrpc) PokerBullContinueTx(parm *pb.PBContinueTxReq, result *interface{}) error {
if parm == nil {
return types.ErrInvalidParam
}
head := &pb.PBGameContinue{
GameId: parm.GameId,
}
reply, err := c.cli.Continue(context.Background(), head)
if err != nil {
return err
}
*result = hex.EncodeToString(reply.Data)
return nil
}
// PokerBullQuitTx 创建游戏推出交易
func (c *Jrpc) PokerBullQuitTx(parm *pb.PBQuitTxReq, result *interface{}) error {
if parm == nil {
return types.ErrInvalidParam
}
head := &pb.PBGameQuit{
GameId: parm.GameId,
}
reply, err := c.cli.Quit(context.Background(), head)
if err != nil {
return err
}
*result = hex.EncodeToString(reply.Data)
return nil
}
// PokerBullQueryTx 创建游戏查询交易
func (c *Jrpc) PokerBullQueryTx(parm *pb.PBQueryReq, result *interface{}) error {
if parm == nil {
return types.ErrInvalidParam
}
head := &pb.PBGameQuery{
GameId: parm.GameId,
}
reply, err := c.cli.Show(context.Background(), head)
if err != nil {
return err
}
*result = hex.EncodeToString(reply.Data)
return nil
}
......@@ -5,7 +5,7 @@
package rpc_test
import (
"strings"
"fmt"
"testing"
commonlog "github.com/33cn/chain33/common/log"
......@@ -41,45 +41,75 @@ func TestJRPCChannel(t *testing.T) {
{fn: testStartRawTxCmd},
{fn: testContinueRawTxCmd},
{fn: testQuitRawTxCmd},
}
for _, testCase := range testCases {
err := testCase.fn(t, jrpcClient)
assert.Nil(t, err)
}
testCases = []struct {
fn func(*testing.T, *jsonclient.JSONClient) error
}{
{fn: testQueryGameByID},
{fn: testQueryGameByAddr},
{fn: testQueryGameByStatus},
{fn: testQueryGameByRound},
}
for index, testCase := range testCases {
err := testCase.fn(t, jrpcClient)
if err == nil {
continue
}
assert.NotEqualf(t, err, types.ErrActionNotSupport, "test index %d", index)
if strings.Contains(err.Error(), "rpc: can't find") {
assert.FailNowf(t, err.Error(), "test index %d", index)
}
assert.Equal(t, err, types.ErrNotFound, fmt.Sprint(index))
}
testCases = []struct {
fn func(*testing.T, *jsonclient.JSONClient) error
}{
{fn: testQueryGameByIDs},
}
for index, testCase := range testCases {
err := testCase.fn(t, jrpcClient)
assert.Equal(t, err, nil, fmt.Sprint(index))
}
}
func testStartRawTxCmd(t *testing.T, jrpc *jsonclient.JSONClient) error {
params := pty.PBStartTxReq{}
payload := &pty.PBGameStart{Value: 123}
params := &rpctypes.CreateTxIn{
Execer: types.ExecName(pty.PokerBullX),
ActionName: pty.CreateStartTx,
Payload: types.MustPBToJSON(payload),
}
var res string
return jrpc.Call("pokerbull.PokerBullStartTx", params, &res)
return jrpc.Call("Chain33.CreateTransaction", params, &res)
}
func testContinueRawTxCmd(t *testing.T, jrpc *jsonclient.JSONClient) error {
params := pty.PBContinueTxReq{}
payload := &pty.PBGameContinue{GameId: "123"}
params := &rpctypes.CreateTxIn{
Execer: types.ExecName(pty.PokerBullX),
ActionName: pty.CreateContinueTx,
Payload: types.MustPBToJSON(payload),
}
var res string
return jrpc.Call("pokerbull.PokerBullContinueTx", params, &res)
return jrpc.Call("Chain33.CreateTransaction", params, &res)
}
func testQuitRawTxCmd(t *testing.T, jrpc *jsonclient.JSONClient) error {
params := pty.PBContinueTxReq{}
payload := &pty.PBGameQuit{GameId: "123"}
params := &rpctypes.CreateTxIn{
Execer: types.ExecName(pty.PokerBullX),
ActionName: pty.CreatequitTx,
Payload: types.MustPBToJSON(payload),
}
var res string
return jrpc.Call("pokerbull.PokerBullQuitTx", params, &res)
return jrpc.Call("Chain33.CreateTransaction", params, &res)
}
func testQueryGameByID(t *testing.T, jrpc *jsonclient.JSONClient) error {
var rep interface{}
var params rpctypes.Query4Jrpc
req := &pty.QueryPBGameInfo{}
params.Execer = "pokerbull"
params.FuncName = "QueryGameByID"
params.Execer = pty.PokerBullX
params.FuncName = pty.FuncNameQueryGameByID
params.Payload = types.MustPBToJSON(req)
rep = &pty.ReplyPBGame{}
return jrpc.Call("Chain33.Query", params, rep)
......@@ -89,8 +119,41 @@ func testQueryGameByAddr(t *testing.T, jrpc *jsonclient.JSONClient) error {
var rep interface{}
var params rpctypes.Query4Jrpc
req := &pty.QueryPBGameInfo{}
params.Execer = "pokerbull"
params.FuncName = "QueryGameByAddr"
params.Execer = pty.PokerBullX
params.FuncName = pty.FuncNameQueryGameByAddr
params.Payload = types.MustPBToJSON(req)
rep = &pty.PBGameRecords{}
return jrpc.Call("Chain33.Query", params, rep)
}
func testQueryGameByIDs(t *testing.T, jrpc *jsonclient.JSONClient) error {
var rep interface{}
var params rpctypes.Query4Jrpc
req := &pty.QueryPBGameInfos{}
params.Execer = pty.PokerBullX
params.FuncName = pty.FuncNameQueryGameListByIDs
params.Payload = types.MustPBToJSON(req)
rep = &pty.ReplyPBGameList{}
return jrpc.Call("Chain33.Query", params, rep)
}
func testQueryGameByStatus(t *testing.T, jrpc *jsonclient.JSONClient) error {
var rep interface{}
var params rpctypes.Query4Jrpc
req := &pty.QueryPBGameInfo{}
params.Execer = pty.PokerBullX
params.FuncName = pty.FuncNameQueryGameByStatus
params.Payload = types.MustPBToJSON(req)
rep = &pty.PBGameRecords{}
return jrpc.Call("Chain33.Query", params, rep)
}
func testQueryGameByRound(t *testing.T, jrpc *jsonclient.JSONClient) error {
var rep interface{}
var params rpctypes.Query4Jrpc
req := &pty.QueryPBGameByRound{}
params.Execer = pty.PokerBullX
params.FuncName = pty.FuncNameQueryGameByRound
params.Payload = types.MustPBToJSON(req)
rep = &pty.PBGameRecords{}
return jrpc.Call("Chain33.Query", params, rep)
......
// Copyright Fuzamei Corp. 2018 All Rights Reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package rpc
import (
"context"
"github.com/33cn/chain33/types"
"github.com/33cn/plugin/plugin/dapp/pokerbull/executor"
pb "github.com/33cn/plugin/plugin/dapp/pokerbull/types"
"github.com/pkg/errors"
)
func (c *channelClient) Start(ctx context.Context, head *pb.PBGameStart) (*types.UnsignTx, error) {
if head.PlayerNum > executor.MaxPlayerNum {
return nil, errors.New("Player number should be maximum 5")
}
val := &pb.PBGameAction{
Ty: pb.PBGameActionStart,
Value: &pb.PBGameAction_Start{Start: head},
}
tx, err := types.CreateFormatTx(pb.PokerBullX, types.Encode(val))
if err != nil {
return nil, err
}
data := types.Encode(tx)
return &types.UnsignTx{Data: data}, nil
}
func (c *channelClient) Continue(ctx context.Context, head *pb.PBGameContinue) (*types.UnsignTx, error) {
val := &pb.PBGameAction{
Ty: pb.PBGameActionContinue,
Value: &pb.PBGameAction_Continue{Continue: head},
}
tx, err := types.CreateFormatTx(pb.PokerBullX, types.Encode(val))
if err != nil {
return nil, err
}
data := types.Encode(tx)
return &types.UnsignTx{Data: data}, nil
}
func (c *channelClient) Quit(ctx context.Context, head *pb.PBGameQuit) (*types.UnsignTx, error) {
val := &pb.PBGameAction{
Ty: pb.PBGameActionQuit,
Value: &pb.PBGameAction_Quit{Quit: head},
}
tx, err := types.CreateFormatTx(pb.PokerBullX, types.Encode(val))
if err != nil {
return nil, err
}
data := types.Encode(tx)
return &types.UnsignTx{Data: data}, nil
}
func (c *channelClient) Show(ctx context.Context, head *pb.PBGameQuery) (*types.UnsignTx, error) {
val := &pb.PBGameAction{
Ty: pb.PBGameActionQuery,
Value: &pb.PBGameAction_Query{Query: head},
}
tx, err := types.CreateFormatTx(pb.PokerBullX, types.Encode(val))
if err != nil {
return nil, err
}
data := types.Encode(tx)
return &types.UnsignTx{Data: data}, nil
}
......@@ -4,6 +4,8 @@
package types
import "github.com/33cn/chain33/types"
//game action ty
const (
PBGameActionStart = iota + 1
......@@ -48,4 +50,35 @@ const (
FuncNameQueryGameByAddr = "QueryGameByAddr"
// FuncNameQueryGameByStatus 根据status查询game
FuncNameQueryGameByStatus = "QueryGameByStatus"
// FuncNameQueryGameByRound 查询某一回合游戏结果
FuncNameQueryGameByRound = "QueryGameByRound"
// CreateStartTx 创建开始交易
CreateStartTx = "Start"
// CreateContinueTx 创建继续交易
CreateContinueTx = "Continue"
// CreatequitTx 创建退出交易
CreatequitTx = "Quit"
)
const (
// ListDESC 降序
ListDESC = int32(0)
// DefaultCount 默认一次取多少条记录
DefaultCount = int32(20)
// MaxPlayerNum 最大玩家数
MaxPlayerNum = 5
// MinPlayValue 最小赌注
MinPlayValue = 10 * types.Coin
// DefaultStyle 默认游戏类型
DefaultStyle = PlayStyleDefault
// PlatformAddress 平台地址
PlatformAddress = "1PHtChNt3UcfssR7v7trKSk3WJtAWjKjjX"
// PlatformFee 平台佣金
PlatformFee = int64(0.005 * float64(types.Coin))
// DeveloperAddress 开发着地址
DeveloperAddress = "1D6RFZNp2rh6QdbcZ1d7RWuBUz61We6SD7"
// DeveloperFee 开发者佣金
DeveloperFee = int64(0.005 * float64(types.Coin))
// WinnerReturn 赢家回报率
WinnerReturn = types.Coin - DeveloperFee
)
This diff is collapsed.
......@@ -29,6 +29,11 @@ func NewType() *PokerBullType {
return c
}
// GetName 获取执行器名称
func (t *PokerBullType) GetName() string {
return PokerBullX
}
// GetPayload 获取payload
func (t *PokerBullType) GetPayload() types.Message {
return &PBGameAction{}
......
......@@ -100,9 +100,8 @@ func (mock *testDataMock) initMember() {
if mock.mockMempool {
mock.mockMempoolProc(q)
} else {
mempool := mempool.New(cfg.MemPool)
mempool := mempool.New(cfg.Mempool, nil)
mempool.SetQueueClient(q.Client())
mempool.SetMinFee(1e5)
mock.modules = append(mock.modules, mempool)
}
......
......@@ -18,7 +18,7 @@ import (
ty "github.com/33cn/plugin/plugin/dapp/ticket/types"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
context "golang.org/x/net/context"
"golang.org/x/net/context"
"google.golang.org/grpc"
)
......@@ -127,6 +127,8 @@ func TestJrpc_GetTicketCount(t *testing.T) {
func TestRPC_CallTestNode(t *testing.T) {
api := new(mocks.QueueProtocolAPI)
cfg, sub := testnode.GetDefaultConfig()
// 测试环境下,默认配置的共识为solo,需要修改
cfg.Consensus.Name = "ticket"
mock33 := testnode.NewWithConfig(cfg, sub, api)
defer func() {
mock33.Close()
......
......@@ -7,6 +7,7 @@ package wallet
import (
"encoding/hex"
"fmt"
"strings"
"sync"
"sync/atomic"
"time"
......@@ -221,6 +222,7 @@ func (policy *ticketPolicy) SignTransaction(key crypto.PrivKey, req *types.ReqSi
func (policy *ticketPolicy) OnWalletLocked() {
// 钱包锁住时,不允许挖矿
atomic.CompareAndSwapInt32(&policy.isTicketLocked, 0, 1)
FlushTicket(policy.getAPI())
}
//解锁超时处理,需要区分整个钱包的解锁或者只挖矿的解锁
......@@ -768,6 +770,17 @@ func (policy *ticketPolicy) autoMining() {
defer bizlog.Info("End auto mining")
operater := policy.getWalletOperate()
defer operater.GetWaitGroup().Done()
// 只有ticket共识下ticket相关的操作才有效
q := types.Conf("config.consensus")
if q != nil {
cons := q.GStr("name")
if strings.Compare(strings.TrimSpace(cons), ty.TicketX) != 0 {
bizlog.Info("consensus is not ticket, exit mining")
return
}
}
lastHeight := int64(0)
miningTicketTicker := policy.getMingTicketTicker()
for {
......
......@@ -31,6 +31,11 @@ func NewType() *TokenType {
return c
}
// GetName 获取执行器名称
func (t *TokenType) GetName() string {
return TokenX
}
// GetPayload 获取token action
func (t *TokenType) GetPayload() types.Message {
return &TokenAction{}
......
......@@ -5,6 +5,8 @@
package executor
import (
"errors"
"fmt"
"strconv"
"github.com/33cn/chain33/account"
......@@ -412,10 +414,34 @@ func (action *tradeAction) tradeRevokeSell(revoke *pty.TradeForRevokeSell) (*typ
return &types.Receipt{Ty: types.ExecOk, KV: kv, Logs: logs}, nil
}
//不同合约之间查询的需求后面要考虑,现在先重复处理一下,原则上不能直接引用其他合约的代码
//后面可能会有一套查询规则 和 写规则, 合约对其他合约只读
func calcTokenKey(token string) (key []byte) {
tokenCreated := "mavl-token-"
return []byte(fmt.Sprintf(tokenCreated+"%s", token))
}
func checkTokenExist(token string, db dbm.KV) bool {
_, err := db.Get(calcTokenKey(token))
return err == nil
}
func (action *tradeAction) tradeBuyLimit(buy *pty.TradeForBuyLimit) (*types.Receipt, error) {
// ErrTokenNotExist error token symbol not exist
errTokenNotExist := errors.New("ErrTokenSymbolNotExist")
if buy.TotalBoardlot < 0 || buy.PricePerBoardlot < 0 || buy.MinBoardlot < 0 || buy.AmountPerBoardlot < 0 {
return nil, types.ErrInvalidParam
}
// 这个检查会比较鸡肋, 按目前的想法的能支持更多的资产, 各种资产检查不一样
// 可以先让订单成功, 如果不合适, 自己撤单也行
// 或后续跨合约注册一个检测的函数
if buy.AssetExec == "" || buy.AssetExec == defaultAssetExec {
// check token exist
if !checkTokenExist(buy.TokenSymbol, action.db) {
return nil, errTokenNotExist
}
}
if !checkAsset(action.height, buy.AssetExec, buy.TokenSymbol) {
return nil, types.ErrInvalidParam
......
all:
chmod +x ./build.sh
./build.sh $(OUT) $(FLAG)
\ No newline at end of file
#!/usr/bin/env bash
output_dir=${1}
strpwd=$(pwd)
strcmd=${strpwd##*dapp/}
strapp=${strcmd%/cmd*}
OUT_DIR="${output_dir}/$strapp"
[ ! -e "${OUT_DIR}" ] && mkdir -p "${OUT_DIR}"
# shellcheck disable=SC2086
cp ./build/* "${OUT_DIR}"
#!/usr/bin/env bash
CLI="docker exec ${NODE3} /root/chain33-cli"
beneficiary=12qyocayNF7Lv6C9qW4avxs2E7U41fKSfv
beneficiary_key=0x4257d8692ef7fe13c68b65d6a52f03933db2fa5ce8faf210b5b8b80c721ced01
#owner=14KEKbYtKKQm4wMthSK9J4La4nAiidGozt
owner_key=CC38546E9E659D15E6B4893F0AB32A06D103931A8230B0BDE71459D2B27D6944
unfreeze_exec_addr=15YsqAuXeEXVHgm6RVx4oJaAAnhtwqnu3H
function unfreeze_test() {
echo "=========== # unfreeze test ============="
echo "=== 1 check exec addr"
result=$($CLI exec addr -e unfreeze)
if [ "${result}" != "${unfreeze_exec_addr}" ]; then
echo "unfreeze exec addr is not right, expect ${unfreeze_exec_addr} result ${result}"
exit 1
fi
block_wait "${CLI}" 2
echo "=== 2 prepare: transfer bty to unfreeze "
result=$($CLI send coins transfer -a 5 -n test -t ${unfreeze_exec_addr} -k ${owner_key})
echo "${result}"
block_wait "${CLI}" 2
echo "=== 3 create unfreeze tx"
tx_hash=$(${CLI} send unfreeze create fix_amount -a 0.01 -e coins -s bty -b ${beneficiary} -p 20 -t 2 -k ${owner_key})
block_wait "${CLI}" 2
unfreeze_id=$(${CLI} tx query -s "${tx_hash}" | jq ".receipt.logs[2].log.current.unfreezeID")
unfreeze_id2=${unfreeze_id#\"}
uid=${unfreeze_id2%\"}
echo "==== 4 check some message "
sleep 20
withdraw=$(${CLI} unfreeze show_withdraw --id "${uid}" | jq ".availableAmount")
if [ "${withdraw}" = "0" ]; then
echo "create unfreeze failed, expect withdraw shoult >0 "
exit 1
fi
echo "==== 5 withdraw"
${CLI} send unfreeze withdraw --id "${uid}" -k "${beneficiary_key}"
block_wait "${CLI}" 2
remaining=$(${CLI} unfreeze show --id "${uid}" | jq ".remaining")
if [ "${remaining}" = '"200000000"' ]; then
echo "withdraw failed, expect remaining < 200000000, result ${remaining}"
exit 1
fi
echo "==== 6 termenate"
${CLI} send unfreeze terminate --id "${uid}" -k "${owner_key}"
block_wait "${CLI}" 2
remaining=$(${CLI} unfreeze show --id "${uid}" | jq ".remaining")
if [ "${remaining}" != '"0"' ]; then
echo "terminate failed, expect remaining 0, result ${remaining}"
exit 1
fi
echo "==================== unfreeze test end"
}
function unfreeze() {
if [ "${2}" == "init" ]; then
return
elif [ "${2}" == "config" ]; then
return
elif [ "${2}" == "test" ]; then
unfreeze_test "${1}"
fi
}
// Copyright Fuzamei Corp. 2018 All Rights Reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package commands
import (
"bytes"
"encoding/hex"
"encoding/json"
"fmt"
"math"
"os"
"strings"
"github.com/33cn/chain33/rpc/jsonclient"
rpctypes "github.com/33cn/chain33/rpc/types"
"github.com/spf13/cobra"
"github.com/33cn/chain33/types"
pty "github.com/33cn/plugin/plugin/dapp/unfreeze/types"
)
// Cmd unfreeze 客户端主程序
func Cmd() *cobra.Command {
cmd := &cobra.Command{
Use: "unfreeze",
Short: "Unfreeze construct management",
Args: cobra.MinimumNArgs(1),
}
cmd.AddCommand(createCmd())
cmd.AddCommand(withdrawCmd())
cmd.AddCommand(terminateCmd())
cmd.AddCommand(showCmd())
cmd.AddCommand(queryWithdrawCmd())
return cmd
}
func createCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "create",
Short: "create unfreeze construct",
}
cmd.AddCommand(fixAmountCmd())
cmd.AddCommand(leftCmd())
return cmd
}
func createFlag(cmd *cobra.Command) *cobra.Command {
cmd.PersistentFlags().StringP("beneficiary", "b", "", "address of beneficiary")
cmd.MarkFlagRequired("beneficiary")
cmd.PersistentFlags().StringP("asset_exec", "e", "", "asset exec")
cmd.MarkFlagRequired("asset_exec")
cmd.PersistentFlags().StringP("asset_symbol", "s", "", "asset symbol")
cmd.MarkFlagRequired("asset_symbol")
cmd.PersistentFlags().Float64P("total", "t", 0, "total count of asset")
cmd.MarkFlagRequired("total")
cmd.PersistentFlags().Int64P("start_ts", "", 0, "effect, UTC timestamp")
//cmd.MarkFlagRequired("start_ts")
return cmd
}
func checkAmount(amount float64) error {
if amount < 0 || amount > float64(types.MaxCoin/types.Coin) {
return types.ErrAmount
}
return nil
}
func getCreateFlags(cmd *cobra.Command) (*pty.UnfreezeCreate, error) {
beneficiary, _ := cmd.Flags().GetString("beneficiary")
exec, _ := cmd.Flags().GetString("asset_exec")
symbol, _ := cmd.Flags().GetString("asset_symbol")
total, _ := cmd.Flags().GetFloat64("total")
startTs, _ := cmd.Flags().GetInt64("start_ts")
if err := checkAmount(total); err != nil {
return nil, types.ErrAmount
}
totalInt64 := int64(math.Trunc((total+0.0000001)*1e4)) * 1e4
unfreeze := &pty.UnfreezeCreate{
StartTime: startTs,
AssetExec: exec,
AssetSymbol: symbol,
TotalCount: totalInt64,
Beneficiary: beneficiary,
Means: "",
}
return unfreeze, nil
}
func fixAmountCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "fix_amount",
Short: "create fix amount means unfreeze construct",
Run: fixAmount,
}
cmd = createFlag(cmd)
cmd.Flags().Float64P("amount", "a", 0, "amount every period")
cmd.MarkFlagRequired("amount")
cmd.Flags().Int64P("period", "p", 0, "period in second")
cmd.MarkFlagRequired("period")
return cmd
}
func fixAmount(cmd *cobra.Command, args []string) {
create, err := getCreateFlags(cmd)
if err != nil {
fmt.Fprintln(os.Stderr, err)
return
}
amount, _ := cmd.Flags().GetFloat64("amount")
if err = checkAmount(amount); err != nil {
fmt.Fprintln(os.Stderr, err)
return
}
amountInt64 := int64(math.Trunc((amount+0.0000001)*1e4)) * 1e4
period, _ := cmd.Flags().GetInt64("period")
create.Means = pty.FixAmountX
create.MeansOpt = &pty.UnfreezeCreate_FixAmount{FixAmount: &pty.FixAmount{Period: period, Amount: amountInt64}}
paraName, _ := cmd.Flags().GetString("paraName")
tx, err := pty.CreateUnfreezeCreateTx(paraName, create)
if err != nil {
fmt.Printf("Create Tx frailed: %s", err)
return
}
outputTx(tx)
}
func outputTx(tx *types.Transaction) {
txHex := types.Encode(tx)
fmt.Println(hex.EncodeToString(txHex))
}
func leftCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "left_proportion",
Short: "create left proportion means unfreeze construct",
Run: left,
}
cmd = createFlag(cmd)
cmd.Flags().Int64P("ten_thousandth", "", 0, "input/10000 of total")
cmd.MarkFlagRequired("amount")
cmd.Flags().Int64P("period", "p", 0, "period in second")
cmd.MarkFlagRequired("period")
return cmd
}
func left(cmd *cobra.Command, args []string) {
create, err := getCreateFlags(cmd)
if err != nil {
fmt.Fprintln(os.Stderr, err)
return
}
tenThousandth, _ := cmd.Flags().GetInt64("ten_thousandth")
period, _ := cmd.Flags().GetInt64("period")
create.Means = pty.FixAmountX
create.MeansOpt = &pty.UnfreezeCreate_LeftProportion{
LeftProportion: &pty.LeftProportion{Period: period, TenThousandth: tenThousandth}}
paraName, _ := cmd.Flags().GetString("paraName")
tx, err := pty.CreateUnfreezeCreateTx(paraName, create)
if err != nil {
fmt.Printf("Create Tx frailed: %s", err)
return
}
outputTx(tx)
}
func withdrawCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "withdraw",
Short: "withdraw asset from construct",
Run: withdraw,
}
cmd.Flags().StringP("id", "", "", "unfreeze construct id")
cmd.MarkFlagRequired("id")
return cmd
}
func terminateCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "terminate",
Short: "terminate construct",
Run: terminate,
}
cmd.Flags().StringP("id", "", "", "unfreeze construct id")
cmd.MarkFlagRequired("id")
return cmd
}
func showCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "show",
Short: "show construct",
Run: show,
}
cmd.Flags().StringP("id", "", "", "unfreeze construct id")
cmd.MarkFlagRequired("id")
return cmd
}
func queryWithdrawCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "show_withdraw",
Short: "show available withdraw amount of one unfreeze construct",
Run: queryWithdraw,
}
cmd.Flags().StringP("id", "", "", "unfreeze construct id")
cmd.MarkFlagRequired("id")
return cmd
}
func withdraw(cmd *cobra.Command, args []string) {
id, _ := cmd.Flags().GetString("id")
paraName, _ := cmd.Flags().GetString("paraName")
tx, err := pty.CreateUnfreezeWithdrawTx(paraName, &pty.UnfreezeWithdraw{UnfreezeID: id})
if err != nil {
fmt.Printf("Create Tx frailed: %s", err)
return
}
outputTx(tx)
}
func terminate(cmd *cobra.Command, args []string) {
id, _ := cmd.Flags().GetString("id")
paraName, _ := cmd.Flags().GetString("paraName")
tx, err := pty.CreateUnfreezeTerminateTx(paraName, &pty.UnfreezeTerminate{UnfreezeID: id})
if err != nil {
fmt.Printf("Create Tx frailed: %s", err)
return
}
outputTx(tx)
}
func queryWithdraw(cmd *cobra.Command, args []string) {
rpcLaddr, _ := cmd.Flags().GetString("rpc_laddr")
paraName, _ := cmd.Flags().GetString("paraName")
id, _ := cmd.Flags().GetString("id")
cli, err := jsonclient.NewJSONClient(rpcLaddr)
if err != nil {
fmt.Fprintln(os.Stderr, err)
return
}
param := &rpctypes.Query4Jrpc{
Execer: getRealExecName(paraName, pty.UnfreezeX),
FuncName: "GetUnfreezeWithdraw",
Payload: types.MustPBToJSON(&types.ReqString{Data: id}),
}
var resp pty.ReplyQueryUnfreezeWithdraw
err = cli.Call("Chain33.Query", param, &resp)
if err != nil {
fmt.Fprintln(os.Stderr, err)
return
}
jsonOutput(&resp)
}
func show(cmd *cobra.Command, args []string) {
rpcLaddr, _ := cmd.Flags().GetString("rpc_laddr")
paraName, _ := cmd.Flags().GetString("paraName")
id, _ := cmd.Flags().GetString("id")
cli, err := jsonclient.NewJSONClient(rpcLaddr)
if err != nil {
fmt.Fprintln(os.Stderr, err)
return
}
param := &rpctypes.Query4Jrpc{
Execer: getRealExecName(paraName, pty.UnfreezeX),
FuncName: "GetUnfreeze",
Payload: types.MustPBToJSON(&types.ReqString{Data: id}),
}
var resp pty.Unfreeze
err = cli.Call("Chain33.Query", param, &resp)
if err != nil {
fmt.Fprintln(os.Stderr, err)
return
}
jsonOutput(&resp)
}
func getRealExecName(paraName string, name string) string {
if strings.HasPrefix(name, "user.p.") {
return name
}
return paraName + name
}
func jsonOutput(resp types.Message) {
data, err := types.PBToJSON(resp)
if err != nil {
fmt.Fprintln(os.Stderr, err)
return
}
var buf bytes.Buffer
err = json.Indent(&buf, data, "", " ")
if err != nil {
fmt.Fprintln(os.Stderr, err)
return
}
fmt.Println(buf.String())
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment