Commit 423ee4d3 authored by jiangpeng's avatar jiangpeng

merge master

parents 507fc973 98d25c0a
......@@ -121,6 +121,13 @@ docker-compose-down: ## build docker-compose for chain33 run
fi; \
cd ..
metrics:## build docker-compose for chain33 metrics
@cd build && if ! [ -d ci ]; then \
make -C ../ ; \
fi; \
cp chain33* Dockerfile docker-compose.yml docker-compose-metrics.yml influxdb.conf *.sh ci/paracross/testcase.sh metrics/ && ./docker-compose-pre.sh run $(proj) metrics && cd ../..
fork-test: ## build fork-test for chain33 run
@cd build && cp chain33* Dockerfile system-fork-test.sh docker-compose* ci/ && cd ci/ && ./docker-compose-pre.sh forktest $(proj) $(dapp) && cd ../..
......@@ -135,6 +142,7 @@ clean: ## Remove previous build
@rm -rf build/ci
@rm -rf build/system-rpc-test.sh
@rm -rf tool
@cd build/metrics && find * -not -name readme.md | xargs rm -fr && cd ../..
@go clean
proto:protobuf
......
......@@ -2,6 +2,7 @@
RAW_TX_HASH=""
LAST_BLOCK_HASH=""
LAST_BLOCK_HEIGHT=0
CASE_ERR=""
RETURN_RESP=""
......@@ -191,6 +192,13 @@ chain33_LastBlockhash() {
echo -e "######\\n last blockhash is $LAST_BLOCK_HASH \\n######"
}
chain33_LastBlockHeight() {
local MAIN_HTTP=$1
result=$(curl -ksd '{"method":"Chain33.GetLastHeader","params":[{}]}' -H 'content-type:text/plain;' "${MAIN_HTTP}" | jq -r ".result.height")
LAST_BLOCK_HEIGHT=$result
echo -e "######\\n last blockheight is $LAST_BLOCK_HEIGHT \\n######"
}
chain33_applyCoins() {
echo "chain33_getMainChainCoins"
if [ "$#" -lt 3 ]; then
......
version: '3'
services:
chain33:
entrypoint: /root/entrypoint.sh
environment:
PARAFILE: "/root/chain33.para33.toml"
expose:
- "8802"
chain32:
entrypoint: /root/entrypoint.sh
environment:
PARAFILE: "/root/chain33.para32.toml"
chain31:
entrypoint: /root/entrypoint.sh
environment:
PARAFILE: "/root/chain33.para31.toml"
chain30:
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"
influxdb:
image: influxdb:latest
environment:
INFLUXDB_DB: "db"
volumes:
- ./influxdb.conf:/etc/influxdb/influxdb.conf
expose:
- "8089/udp"
- "8086"
grafana:
image: grafana/grafana
expose:
- "3000"
......@@ -37,12 +37,22 @@ function run_dapp() {
local test=$2
echo "============ run dapp=$app start ================="
rm -rf "${app}"-ci && mkdir -p "${app}"-ci && cp ./"${app}"/* ./"${app}"-ci && echo $?
cp -n ./* ./"${app}"-ci/ && echo $?
if [ "$app" == "paracross" ]; then
cp -r dapptest/ "${app}"-ci/ && echo $?
if [ "$app" == "metrics" ]; then
cp ./ci/paracross/* ./metrics && echo $?
cp -n ./* ./metrics/ && echo $?
cp -r ci/dapptest/ metrics/ && echo $?
cd metrics && pwd
rm docker-compose-paracross.yml
mv docker-compose-metrics.yml docker-compose-paracross.yml
app="paracross"
else
rm -rf "${app}"-ci && mkdir -p "${app}"-ci && cp ./"${app}"/* ./"${app}"-ci && echo $?
cp -n ./* ./"${app}"-ci/ && echo $?
if [ "$app" == "paracross" ]; then
cp -r dapptest/ "${app}"-ci/ && echo $?
fi
cd "${app}"-ci/ && pwd
fi
cd "${app}"-ci/ && pwd
if [ "$test" == "$FORKTESTFILE" ]; then
sed -i $sedfix 's/^system_coins_file=.*/system_coins_file="..\/system\/coins\/fork-test.sh"/g' system-fork-test.sh
......
......@@ -112,6 +112,9 @@ function base_init() {
#relay genesis
sed -i $sedfix 's/^genesis="12qyocayNF7.*/genesis="1G5Cjy8LuQex2fuYv3gzb7B8MxAnxLEqt3"/g' chain33.toml
#autonomy
sed -i $sedfix 's/^useBalance=.*/useBalance=true/g' chain33.toml
sed -i $sedfix 's/^total="16htvcBNS.*/total="1Q9sQwothzM1gKSzkVZ8Dt1tqKX1uzSagx"/g' chain33.toml
}
function start() {
......@@ -131,6 +134,14 @@ function start() {
docker-compose ps
set +e
influxdbcontainer=$(docker ps -a | grep build_influxdb_1)
if [ -n "$influxdbcontainer" ]; then
echo "create database chain33metrics in docker container build_influxdb_1"
docker exec build_influxdb_1 influx -execute 'create database chain33metrics'
fi
set -e
# query node run status
check_docker_status
${CLI} block last_header
......@@ -425,6 +436,15 @@ function dapp_test_address() {
# block_wait "${1}" 1
tx_wait "${1}" "${hash}"
#autonomy allocation for rpc test 1Q9sQwothzM1gKSzkVZ8Dt1tqKX1uzSagx
result=$(${1} account import_key -k 1c3e6cac2f887e1ab9180e2d5772dc4ba01accb8d4df434faba097003eb35482 -l autonomytest | jq ".label")
echo "${result}"
if [ -z "${result}" ]; then
exit 1
fi
hash=$(${1} send coins transfer -a 6300 -n transfer -t 1Q9sQwothzM1gKSzkVZ8Dt1tqKX1uzSagx -k 4257D8692EF7FE13C68B65D6A52F03933DB2FA5CE8FAF210B5B8B80C721CED01)
echo "${hash}"
}
function base_config() {
......
reporting-disabled = false
bind-address = "127.0.0.1:8088"
[meta]
dir = "/var/lib/influxdb/meta"
retention-autocreate = true
logging-enabled = true
[data]
dir = "/var/lib/influxdb/data"
index-version = "inmem"
wal-dir = "/var/lib/influxdb/wal"
wal-fsync-delay = "0s"
validate-keys = false
query-log-enabled = true
cache-max-memory-size = 1073741824
cache-snapshot-memory-size = 26214400
cache-snapshot-write-cold-duration = "10m0s"
compact-full-write-cold-duration = "4h0m0s"
compact-throughput = 50331648
compact-throughput-burst = 50331648
max-series-per-database = 1000000
max-values-per-tag = 100000
max-concurrent-compactions = 0
max-index-log-file-size = 1048576
trace-logging-enabled = false
tsm-use-madv-willneed = false
[coordinator]
write-timeout = "10s"
max-concurrent-queries = 0
query-timeout = "0s"
log-queries-after = "0s"
max-select-point = 0
max-select-series = 0
max-select-buckets = 0
[retention]
enabled = true
check-interval = "30m0s"
[shard-precreation]
enabled = true
check-interval = "10m0s"
advance-period = "30m0s"
[monitor]
store-enabled = true
store-database = "_internal"
store-interval = "10s"
[subscriber]
enabled = true
http-timeout = "30s"
insecure-skip-verify = false
ca-certs = ""
write-concurrency = 40
write-buffer-size = 1000
[http]
enabled = true
bind-address = ":8086"
auth-enabled = false
log-enabled = true
suppress-write-log = false
write-tracing = false
flux-enabled = false
pprof-enabled = true
debug-pprof-enabled = false
https-enabled = false
https-certificate = "/etc/ssl/influxdb.pem"
https-private-key = ""
max-row-limit = 0
max-connection-limit = 0
shared-secret = ""
realm = "InfluxDB"
unix-socket-enabled = false
unix-socket-permissions = "0777"
bind-socket = "/var/run/influxdb.sock"
max-body-size = 25000000
access-log-path = ""
max-concurrent-write-limit = 0
max-enqueued-write-limit = 0
enqueued-write-timeout = 30000000000
[logging]
format = "auto"
level = "info"
suppress-logo = false
[[graphite]]
enabled = false
bind-address = ":2003"
database = "graphite"
retention-policy = ""
protocol = "tcp"
batch-size = 5000
batch-pending = 10
batch-timeout = "1s"
consistency-level = "one"
separator = "."
udp-read-buffer = 0
[[collectd]]
enabled = false
bind-address = ":25826"
database = "collectd"
retention-policy = ""
batch-size = 5000
batch-pending = 10
batch-timeout = "10s"
read-buffer = 0
typesdb = "/usr/share/collectd/types.db"
security-level = "none"
auth-file = "/etc/collectd/auth_file"
parse-multivalue-plugin = "split"
[[opentsdb]]
enabled = false
bind-address = ":4242"
database = "opentsdb"
retention-policy = ""
consistency-level = "one"
tls-enabled = false
certificate = "/etc/ssl/influxdb.pem"
batch-size = 1000
batch-pending = 5
batch-timeout = "1s"
log-point-errors = true
[[udp]]
enabled = true
bind-address = ":8089"
database = "db"
retention-policy = ""
batch-size = 1
batch-pending = 1
read-buffer = 0
batch-timeout = "1s"
precision = ""
[continuous_queries]
log-enabled = true
enabled = true
query-stats-enabled = false
run-interval = "1s"
[tls]
min-version = ""
max-version = ""
# Metrics 功能
* 通过make metrics来测试plugin的metrics数据收集功能
* 在容器build_influxdb_1中运行以下语句,查看结果:
```
1.influx 进入influxdb交互界面
```
```
2.use chain33metrics
```
```
3.show field keys
```
```
4.使用select进行查询,如select * from mesurment
```
* 数据的可视化展示可以通过Grafana工具进行展示,只需要访问以下链接:
http://build_grafana_1:3000,更多的操作可以参考以下链接中的使用Grafana工具展示部分
......@@ -312,9 +312,30 @@ Enable=0
[fork.sub.jsvm]
Enable=0
[fork.sub.issuance]
Enable=0
[fork.sub.collateralize]
Enable=0
#对已有的平行链如果不是从0开始同步数据,需要设置这个kvmvccmavl的对应平行链高度的fork,如果从0开始同步,statehash会跟以前mavl的不同
[fork.sub.store-kvmvccmavl]
ForkKvmvccmavl=0
[pprof]
listenAddr = "localhost:6061"
[metrics]
#是否使能发送metrics数据的发送
enableMetrics=true
#数据保存模式
dataEmitMode="influxdb"
[metrics.sub.influxdb]
#以纳秒为单位的发送间隔
duration=1000000000
url="http://influxdb:8086"
database="chain33metrics"
username=""
password=""
namespace=""
......@@ -244,3 +244,18 @@ paraConsensusStopBlocks=30000
[exec.sub.autonomy]
total="16htvcBNSEA7fZhAdLJphDwQRQJaHpyHTp"
useBalance=false
[metrics]
#是否使能发送metrics数据的发送
enableMetrics=true
#数据保存模式
dataEmitMode="influxdb"
[metrics.sub.influxdb]
#以纳秒为单位的发送间隔
duration=1000000000
url="http://influxdb:8086"
database="chain33metrics"
username=""
password=""
namespace=""
\ No newline at end of file
......@@ -2,12 +2,8 @@ module github.com/33cn/plugin
go 1.12
replace github.com/33cn/chain33 => github.com/icehawk-hyb/chain33 v0.0.0-20200110085207-2fa37fd72fba
require (
github.com/33cn/chain33 v0.0.0
//github.com/33cn/chain33 v0.0.0-20200108042336-2dda2dfb7e0e
github.com/33cn/chain33 v0.0.0-20200115085731-38f06ce8411c
github.com/BurntSushi/toml v0.3.1
github.com/NebulousLabs/Sia v1.3.7
github.com/beorn7/perks v1.0.1 // indirect
......
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
github.com/33cn/chain33 v0.0.0-20200108042336-2dda2dfb7e0e h1:FMnJCJUDEsjHURlHv3zqiiftvNCtTbsMSjXSykG7htc=
github.com/33cn/chain33 v0.0.0-20200108042336-2dda2dfb7e0e/go.mod h1:4I8n+Zyf3t0UKM5jjpqJY627Tub62oXkLsdzIv4r6rQ=
github.com/33cn/chain33 v0.0.0-20200115085731-38f06ce8411c h1:ePkHv1GhUGsEubK1mxtrCe0ricOc66QNAN11hOWH6ps=
github.com/33cn/chain33 v0.0.0-20200115085731-38f06ce8411c/go.mod h1:lhZbNbCnCGsiiapxGZcSxfxKdIAdCK0UzHgpp65XMlM=
github.com/AndreasBriese/bbloom v0.0.0-20180913140656-343706a395b7 h1:PqzgE6kAMi81xWQA2QIVxjWkFHptGgC547vchpUbtFo=
github.com/AndreasBriese/bbloom v0.0.0-20180913140656-343706a395b7/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8=
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
......@@ -78,6 +78,7 @@ github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db h1:woRePGFeVFfLKN/pOkfl+p/TAqKOfFu+7KPlMVpok/w=
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/haltingstate/secp256k1-go v0.0.0-20151224084235-572209b26df6 h1:HE4YDtvtpZgjRJ2tCOmaXlcpBTFG2e0jvfNntM5sXOs=
github.com/haltingstate/secp256k1-go v0.0.0-20151224084235-572209b26df6/go.mod h1:73mKQiY8bLnscfGakn57WAJZTzT0eSUAy3qgMQNR/DI=
......@@ -88,10 +89,10 @@ github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpO
github.com/huin/goupnp v1.0.0 h1:wg75sLpL6DZqwHQN6E1Cfk6mtfzS45z8OV+ic+DtHRo=
github.com/huin/goupnp v1.0.0/go.mod h1:n9v9KO1tAxYH82qOn+UTIFQDmx5n1Zxd/ClZDMX7Bnc=
github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o=
github.com/icehawk-hyb/chain33 v0.0.0-20200110085207-2fa37fd72fba h1:NSMqY6aDlckPYQhjQC3EsUfPfPs0wR/nn4Y/8rQWax4=
github.com/icehawk-hyb/chain33 v0.0.0-20200110085207-2fa37fd72fba/go.mod h1:4I8n+Zyf3t0UKM5jjpqJY627Tub62oXkLsdzIv4r6rQ=
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/influxdata/influxdb v1.7.9 h1:uSeBTNO4rBkbp1Be5FKRsAmglM9nlx25TzVQRQt1An4=
github.com/influxdata/influxdb v1.7.9/go.mod h1:qZna6X/4elxqT3yI9iZYdZrWWdeFOOprn86kgg4+IzY=
github.com/jackpal/go-nat-pmp v1.0.1 h1:i0LektDkO1QlrTm/cSuP+PyBCDnYvjPLGl4LdWEMiaA=
github.com/jackpal/go-nat-pmp v1.0.1/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
......@@ -137,6 +138,8 @@ github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R
github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.3 h1:CTwfnzjQ+8dS6MhHHu4YswVAD99sL2wjPqP+VkURmKE=
github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ=
github.com/rcrowley/go-metrics v0.0.0-20190826022208-cac0b30c2563 h1:dY6ETXrvDG7Sa4vE8ZQG4yqWg6UnOcbqTAahkV813vQ=
github.com/rcrowley/go-metrics v0.0.0-20190826022208-cac0b30c2563/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
github.com/robertkrimen/otto v0.0.0-20180617131154-15f95af6e78d h1:1VUlQbCfkoSGv7qP7Y+ro3ap1P1pPZxgdGVqiTVy5C4=
github.com/robertkrimen/otto v0.0.0-20180617131154-15f95af6e78d/go.mod h1:xvqspoSXJTIpemEonrMDFq6XzwHYYgToXWj5eRX1OtY=
github.com/rs/cors v1.6.0 h1:G9tHG9lebljV9mfp9SNPDL36nCDxmo3zTlAf1YgvzmI=
......@@ -163,7 +166,6 @@ github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyC
github.com/valyala/fasthttp v1.5.0 h1:dhq+O9pmNZFF6qAXpasMO1xSm7dL4qEz2ylfZN8BG9w=
github.com/valyala/fasthttp v1.5.0/go.mod h1:eriCz9OhZjKCGfJ185a/IDgNl0bg9IbzfpcslMZXU1c=
github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio=
github.com/vektra/mockery v0.0.0-20181123154057-e78b021dcbb5/go.mod h1:ppEjwdhyy7Y31EnHRDm1JkChoC7LXIJ7Ex0VYLWtZtQ=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5Qo6v2eYzo7kUS51QINcR5jNpbZS8=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
go.uber.org/atomic v1.4.0 h1:cxzIVoETapQEqDhQu3QfnvXAV4AlzcvUCxkVUFw3+EU=
......@@ -183,7 +185,6 @@ golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73r
golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7 h1:fHDIZ2oxGnUZRN6WgWFCbYBjH9uqVPRCUVUDhs0wnbA=
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297 h1:k7pJ2yAPLPgbskkFdhRCsA77k2fySZ1zf2zCjvQCiIM=
......@@ -207,11 +208,8 @@ golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/time v0.0.0-20190921001708-c4c64cad1fd0 h1:xQwXv67TxFo9nC1GJFyab5eq/5B590r6RlnL/G8Sz7w=
golang.org/x/time v0.0.0-20190921001708-c4c64cad1fd0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181112210238-4b1f3b6b1646/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8 h1:Nw54tB0rB7hY/N0NQvRW8DG4Yk3Q6T9cu9RcFQDu1tc=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
......
This diff is collapsed.
......@@ -38,7 +38,7 @@ enableTxQuickIndex=true
seeds=["127.0.0.1:13802"]
enable=false
isSeed=false
serverStart=true
serverStart=false
innerSeedEnable=false
useGithub=false
innerBounds=300
......@@ -108,12 +108,14 @@ peersURL="http://127.0.0.1:9021"
# raft共识用到,指示raft集群中只读节点的IP(只同步日志,不参与raft共识)
readOnlyPeersURL=""
addPeersURL=""
#raft共识用到,默认raft中多少条记录打包一个snapshot(这里为了测试调整小一点)
#raft中多少条记录打包一个snapshot,默认为10000(这里为了测试调整小一点)
defaultSnapCount=2
#raft共识用到,默认raft中写区块时间间隔
#raft中写区块时间间隔,默认为1秒
writeBlockSeconds=1
#raft共识用到,默认raft中leader发送心跳包时间间隔
#raft中leader发送心跳包时间间隔,默认为1秒
heartbeatTick=1
#raft中leader打包空区块的时间间隔,默认为0,表示不打包空区块
emptyBlockInterval=120
# =============== raft共识配置参数 ===========================
[store]
......@@ -134,7 +136,7 @@ dbCache=16
signType="secp256k1"
[wallet.sub.ticket]
minerdisable=false
minerdisable=true
minerwhitelist=["*"]
minerWaitTime="1s"
......
......@@ -19,27 +19,29 @@ var (
rlog = log.New("module", "raft")
genesis string
genesisBlockTime int64
defaultSnapCount uint64 = 1000
snapshotCatchUpEntriesN uint64 = 1000
defaultSnapCount uint64 = 10000
snapshotCatchUpEntriesN uint64 = 10000
writeBlockSeconds int64 = 1
heartbeatTick = 1
isLeader = false
emptyBlockInterval int64
isLeader = false
mux atomic.Value
confChangeC chan raftpb.ConfChange
)
type subConfig struct {
Genesis string `json:"genesis"`
GenesisBlockTime int64 `json:"genesisBlockTime"`
NodeID int64 `json:"nodeID"`
PeersURL string `json:"peersURL"`
RaftAPIPort int64 `json:"raftAPIPort"`
IsNewJoinNode bool `json:"isNewJoinNode"`
ReadOnlyPeersURL string `json:"readOnlyPeersURL"`
AddPeersURL string `json:"addPeersURL"`
DefaultSnapCount int64 `json:"defaultSnapCount"`
WriteBlockSeconds int64 `json:"writeBlockSeconds"`
HeartbeatTick int32 `json:"heartbeatTick"`
Genesis string `json:"genesis"`
GenesisBlockTime int64 `json:"genesisBlockTime"`
NodeID int64 `json:"nodeID"`
PeersURL string `json:"peersURL"`
RaftAPIPort int64 `json:"raftAPIPort"`
IsNewJoinNode bool `json:"isNewJoinNode"`
ReadOnlyPeersURL string `json:"readOnlyPeersURL"`
AddPeersURL string `json:"addPeersURL"`
DefaultSnapCount int64 `json:"defaultSnapCount"`
WriteBlockSeconds int64 `json:"writeBlockSeconds"`
HeartbeatTick int32 `json:"heartbeatTick"`
EmptyBlockInterval int64 `json:"emptyBlockInterval"`
}
func init() {
......@@ -64,7 +66,7 @@ func NewRaftCluster(cfg *types.Consensus, sub []byte) queue.Module {
//TODO 当传入的参数异常时,返回给主函数的是个nil,这时候需要做异常处理
return nil
}
// 默认1000个Entry打一个snapshot
// 默认10000个Entry打一个snapshot
if subcfg.DefaultSnapCount > 0 {
defaultSnapCount = uint64(subcfg.DefaultSnapCount)
snapshotCatchUpEntriesN = uint64(subcfg.DefaultSnapCount)
......@@ -77,6 +79,11 @@ func NewRaftCluster(cfg *types.Consensus, sub []byte) queue.Module {
if subcfg.HeartbeatTick > 0 {
heartbeatTick = int(subcfg.HeartbeatTick)
}
// write empty block interval in second
if subcfg.EmptyBlockInterval > 0 {
emptyBlockInterval = subcfg.EmptyBlockInterval
}
var b *Client
getSnapshot := func() ([]byte, error) { return b.getSnapshot() }
// raft集群的建立,1. 初始化两条channel: propose channel用于客户端和raft底层交互, commit channel用于获取commit消息
......@@ -96,12 +103,13 @@ func NewRaftCluster(cfg *types.Consensus, sub []byte) queue.Module {
//采用context来统一管理所有服务
ctx, stop := context.WithCancel(context.Background())
// propose channel
proposeC := make(chan *types.Block)
proposeC := make(chan BlockInfo)
confChangeC = make(chan raftpb.ConfChange)
commitC, errorC, snapshotterReady, validatorC := NewRaftNode(ctx, int(subcfg.NodeID), subcfg.IsNewJoinNode, peers, readOnlyPeers, addPeers, getSnapshot, proposeC, confChangeC)
node, commitC, errorC, snapshotterReady, validatorC := NewRaftNode(ctx, int(subcfg.NodeID), subcfg.IsNewJoinNode, peers, readOnlyPeers, addPeers, getSnapshot, proposeC, confChangeC)
//启动raft删除节点操作监听
go serveHTTPRaftAPI(ctx, int(subcfg.RaftAPIPort), confChangeC, errorC)
// 监听commit channel,取block
b = NewBlockstore(ctx, cfg, <-snapshotterReady, proposeC, commitC, errorC, validatorC, stop)
node.SetClient(b)
return b
}
......@@ -6,6 +6,7 @@ package raft
import (
"context"
"encoding/json"
"fmt"
"net/http"
"net/url"
......@@ -14,7 +15,6 @@ import (
"sync"
"time"
"github.com/33cn/chain33/types"
"github.com/coreos/etcd/etcdserver/stats"
"github.com/coreos/etcd/pkg/fileutil"
typec "github.com/coreos/etcd/pkg/types"
......@@ -24,7 +24,6 @@ import (
"github.com/coreos/etcd/snap"
"github.com/coreos/etcd/wal"
"github.com/coreos/etcd/wal/walpb"
"github.com/golang/protobuf/proto"
)
var (
......@@ -32,9 +31,10 @@ var (
)
type raftNode struct {
proposeC <-chan *types.Block
client *Client
proposeC <-chan BlockInfo
confChangeC <-chan raftpb.ConfChange
commitC chan<- *types.Block
commitC chan<- *BlockInfo
errorC chan<- error
id int
bootstrapPeers []string
......@@ -65,13 +65,21 @@ type raftNode struct {
restartC chan struct{}
}
type Node struct {
*raftNode
}
func (node *Node) SetClient(client *Client) {
node.client = client
}
// NewRaftNode create raft node
func NewRaftNode(ctx context.Context, id int, join bool, peers []string, readOnlyPeers []string, addPeers []string, getSnapshot func() ([]byte, error), proposeC <-chan *types.Block,
confChangeC <-chan raftpb.ConfChange) (<-chan *types.Block, <-chan error, <-chan *snap.Snapshotter, <-chan bool) {
func NewRaftNode(ctx context.Context, id int, join bool, peers []string, readOnlyPeers []string, addPeers []string, getSnapshot func() ([]byte, error), proposeC <-chan BlockInfo,
confChangeC <-chan raftpb.ConfChange) (*Node, <-chan *BlockInfo, <-chan error, <-chan *snap.Snapshotter, <-chan bool) {
rlog.Info("Enter consensus raft")
// commit channel
commitC := make(chan *types.Block)
commitC := make(chan *BlockInfo)
errorC := make(chan error)
rc := &raftNode{
proposeC: proposeC,
......@@ -94,7 +102,7 @@ func NewRaftNode(ctx context.Context, id int, join bool, peers []string, readOnl
}
go rc.startRaft()
return commitC, errorC, rc.snapshotterReady, rc.validatorC
return &Node{rc}, commitC, errorC, rc.snapshotterReady, rc.validatorC
}
// 启动raft节点
......@@ -224,7 +232,7 @@ func (rc *raftNode) serveChannels() {
if !ok {
rc.proposeC = nil
} else {
out, err := proto.Marshal(prop)
out, err := json.Marshal(prop)
if err != nil {
rlog.Error(fmt.Sprintf("failed to marshal block:%v ", err.Error()))
}
......@@ -257,6 +265,10 @@ func (rc *raftNode) serveChannels() {
case <-ticker.C:
rc.node.Tick()
case rd := <-rc.node.Ready():
if !rc.checkEntries(rd.Entries) || !rc.checkEntries(rd.CommittedEntries) {
rc.stop()
return
}
rc.wal.Save(rd.HardState, rd.Entries)
if !raft.IsEmptySnap(rd.Snapshot) {
rc.saveSnap(rd.Snapshot)
......@@ -283,6 +295,25 @@ func (rc *raftNode) serveChannels() {
}
}
func (rc *raftNode) checkEntries(ents []raftpb.Entry) bool {
for i := range ents {
if ents[i].Type == raftpb.EntryNormal && len(ents[i].Data) != 0 {
info := &BlockInfo{}
if err := json.Unmarshal(ents[i].Data, info); err != nil {
rlog.Error("checkEntries Unmarshal BlockInfo fail", "err", err)
return false
}
if rc.client != nil {
if !rc.client.CheckBlockInfo(info) {
rlog.Error("checkEntries CheckBlockInfo fail")
return false
}
}
}
}
return true
}
func (rc *raftNode) updateValidator() {
//TODO 这块监听后期需要根据场景进行优化?
......@@ -325,6 +356,7 @@ func (rc *raftNode) updateValidator() {
}
}
func (rc *raftNode) Status() raft.Status {
rc.stopMu.RLock()
defer rc.stopMu.RUnlock()
......@@ -383,15 +415,13 @@ func (rc *raftNode) maybeTriggerSnapshot() {
return
}
appliedIndex := rc.appliedIndex
snapshotIndex := rc.snapshotIndex
confState := rc.confState
rlog.Info(fmt.Sprintf("start snapshot [applied index: %d | last snapshot index: %d]", appliedIndex, snapshotIndex))
ents, err := rc.raftStorage.Entries(appliedIndex, appliedIndex+1, 2)
rlog.Info(fmt.Sprintf("start snapshot [applied index: %d | last snapshot index: %d]", rc.appliedIndex, rc.snapshotIndex))
data, err := rc.getSnapshot()
if err != nil {
rlog.Error(fmt.Sprintf("Err happened when get snapshot:%v", err.Error()))
rlog.Error("getSnapshot fail", "err", err)
panic(err)
}
snapShot, err := rc.raftStorage.CreateSnapshot(appliedIndex, &confState, ents[0].Data)
snapShot, err := rc.raftStorage.CreateSnapshot(rc.appliedIndex, &rc.confState, data)
if err != nil {
panic(err)
}
......@@ -400,15 +430,15 @@ func (rc *raftNode) maybeTriggerSnapshot() {
}
compactIndex := uint64(1)
if appliedIndex > snapshotCatchUpEntriesN {
compactIndex = appliedIndex - snapshotCatchUpEntriesN
if rc.appliedIndex > snapshotCatchUpEntriesN {
compactIndex = rc.appliedIndex - snapshotCatchUpEntriesN
}
if err := rc.raftStorage.Compact(compactIndex); err != nil {
panic(err)
}
rlog.Info(fmt.Sprintf("compacted log at index %d", compactIndex))
rc.snapshotIndex = appliedIndex
rc.snapshotIndex = rc.appliedIndex
}
func (rc *raftNode) publishSnapshot(snapshotToSave raftpb.Snapshot) {
......@@ -487,12 +517,13 @@ func (rc *raftNode) publishEntries(ents []raftpb.Entry) bool {
break
}
// 解码
block := &types.Block{}
if err := proto.Unmarshal(ents[i].Data, block); err != nil {
rlog.Error(fmt.Sprintf("failed to unmarshal: %v", err.Error()))
info := &BlockInfo{}
if err := json.Unmarshal(ents[i].Data, info); err != nil {
rlog.Error("Unmarshal BlockInfo fail", "err", err)
break
}
select {
case rc.commitC <- block:
case rc.commitC <- info:
case <-rc.ctx.Done():
return false
}
......
......@@ -5,6 +5,7 @@
package main
import (
"encoding/json"
"flag"
"fmt"
"log"
......@@ -18,7 +19,6 @@ import (
raftsnap "github.com/coreos/etcd/snap"
"github.com/coreos/etcd/wal"
"github.com/coreos/etcd/wal/walpb"
"github.com/golang/protobuf/proto"
)
func main() {
......@@ -94,12 +94,12 @@ func main() {
break
}
// 解码
block := &Block{}
if err := proto.Unmarshal(e.Data, block); err != nil {
info := &BlockInfo{}
if err := json.Unmarshal(e.Data, info); err != nil {
log.Printf("failed to unmarshal: %v", err)
break
}
msg = fmt.Sprintf("%s\t BlockHeight:%d", msg, block.Height)
msg = fmt.Sprintf("%s\tHeight=%d\tHash=%s", msg, info.Height, info.Hash)
case raftpb.EntryConfChange:
msg = fmt.Sprintf("%s\tconf", msg)
var r raftpb.ConfChange
......@@ -133,21 +133,7 @@ func genIDSlice(a []uint64) []types.ID {
return ids
}
// Block struct
type Block struct {
Version int64 `protobuf:"varint,1,opt,name=version" json:"version,omitempty"`
ParentHash []byte `protobuf:"bytes,2,opt,name=parentHash,proto3" json:"parentHash,omitempty"`
TxHash []byte `protobuf:"bytes,3,opt,name=txHash,proto3" json:"txHash,omitempty"`
StateHash []byte `protobuf:"bytes,4,opt,name=stateHash,proto3" json:"stateHash,omitempty"`
Height int64 `protobuf:"varint,5,opt,name=height" json:"height,omitempty"`
BlockTime int64 `protobuf:"varint,6,opt,name=blockTime" json:"blockTime,omitempty"`
//Signature *Signature `protobuf:"bytes,8,opt,name=signature" json:"signature,omitempty"`
//Txs []*Transaction `protobuf:"bytes,7,rep,name=txs" json:"txs,omitempty"`
type BlockInfo struct {
Height int64 `json:"height"`
Hash string `json:"hash"`
}
// Reset method
func (m *Block) Reset() { *m = Block{} }
func (m *Block) String() string { return proto.CompactTextString(m) }
// ProtoMessage method
func (*Block) ProtoMessage() {}
This diff is collapsed.
......@@ -22,6 +22,7 @@ var (
driverName = auty.AutonomyX
autonomyAddr string
subcfg subConfig
ticketName = auty.TicketX
)
// Init 重命名执行器名称
......@@ -30,6 +31,7 @@ func Init(name string, cfg *types.Chain33Config, sub []byte) {
types.MustDecode(sub, &subcfg)
}
autonomyAddr = address.ExecAddress(cfg.ExecName(auty.AutonomyX))
ticketName = cfg.ExecName(auty.TicketX)
drivers.Register(cfg, GetName(), newAutonomy, cfg.GetDappFork(driverName, "Enable"))
InitExecType()
}
......
......@@ -457,7 +457,7 @@ func (a *action) batchGetAddressVotes(addrs []string, height int64) (int32, erro
}
func (a *action) getAddressVotes(addr string, height int64) (int32, error) {
account, err := a.getStartHeightVoteAccount(addr, auty.TicketX, height)
account, err := a.getStartHeightVoteAccount(addr, ticketName, height)
if err != nil {
return 0, err
}
......
all:
chmod +x ./build.sh
./build.sh $(OUT) $(FLAG)
\ No newline at end of file
#!/usr/bin/env bash
strpwd=$(pwd)
strcmd=${strpwd##*dapp/}
strapp=${strcmd%/cmd*}
OUT_TESTDIR="${1}/dapptest/$strapp"
mkdir -p "${OUT_TESTDIR}"
cp ./test/test-rpc.sh "${OUT_TESTDIR}"
#!/usr/bin/env bash
# shellcheck disable=SC2128
set -e
set -o pipefail
# shellcheck source=/dev/null
source ../dapp-test-common.sh
function main() {
echo "Collateralize cases has integrated in Issuance test"
}
chain33_debug_function main "$1"
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 (
log "github.com/33cn/chain33/common/log/log15"
drivers "github.com/33cn/chain33/system/dapp"
"github.com/33cn/chain33/types"
pty "github.com/33cn/plugin/plugin/dapp/collateralize/types"
)
var clog = log.New("module", "execs.collateralize")
var driverName = pty.CollateralizeX
func InitExecType() {
ety := types.LoadExecutorType(driverName)
ety.InitFuncList(types.ListMethod(&Collateralize{}))
}
// Init collateralize
func Init(name string, cfg *types.Chain33Config, sub []byte) {
driverName := GetName()
if name != driverName {
panic("system dapp can't be rename")
}
if sub != nil {
types.MustDecode(sub, &cfg)
}
drivers.Register(cfg, driverName, newCollateralize, cfg.GetDappFork(driverName, "Enable"))
InitExecType()
}
// GetName for Collateralize
func GetName() string {
return newCollateralize().GetName()
}
// Collateralize driver
type Collateralize struct {
drivers.DriverBase
}
func newCollateralize() drivers.Driver {
c := &Collateralize{}
c.SetChild(c)
c.SetExecutorType(types.LoadExecutorType(driverName))
return c
}
// GetDriverName for Collateralize
func (c *Collateralize) GetDriverName() string {
return pty.CollateralizeX
}
// CheckReceiptExecOk return true to check if receipt ty is ok
func (c *Collateralize) CheckReceiptExecOk() bool {
return true
}
// ExecutorOrder 设置localdb的EnableRead
func (c *Collateralize) ExecutorOrder() int64 {
cfg := c.GetAPI().GetConfig()
if cfg.IsFork(c.GetHeight(), "ForkLocalDBAccess") {
return drivers.ExecLocalSameTime
}
return c.DriverBase.ExecutorOrder()
}
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 executor
/*
waiting for update
*/
// 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"
pty "github.com/33cn/plugin/plugin/dapp/collateralize/types"
)
// Exec_Create Action
func (c *Collateralize) Exec_Create(payload *pty.CollateralizeCreate, tx *types.Transaction, index int) (*types.Receipt, error) {
actiondb := NewCollateralizeAction(c, tx, index)
return actiondb.CollateralizeCreate(payload)
}
// Exec_Borrow Action
func (c *Collateralize) Exec_Borrow(payload *pty.CollateralizeBorrow, tx *types.Transaction, index int) (*types.Receipt, error) {
actiondb := NewCollateralizeAction(c, tx, index)
return actiondb.CollateralizeBorrow(payload)
}
// Exec_Repay Action
func (c *Collateralize) Exec_Repay(payload *pty.CollateralizeRepay, tx *types.Transaction, index int) (*types.Receipt, error) {
actiondb := NewCollateralizeAction(c, tx, index)
return actiondb.CollateralizeRepay(payload)
}
// Exec_Repay Action
func (c *Collateralize) Exec_Append(payload *pty.CollateralizeAppend, tx *types.Transaction, index int) (*types.Receipt, error) {
actiondb := NewCollateralizeAction(c, tx, index)
return actiondb.CollateralizeAppend(payload)
}
// Exec_Feed Action
func (c *Collateralize) Exec_Feed(payload *pty.CollateralizeFeed, tx *types.Transaction, index int) (*types.Receipt, error) {
actiondb := NewCollateralizeAction(c, tx, index)
return actiondb.CollateralizeFeed(payload)
}
// Exec_Retrieve Action
func (c *Collateralize) Exec_Retrieve(payload *pty.CollateralizeRetrieve, tx *types.Transaction, index int) (*types.Receipt, error) {
actiondb := NewCollateralizeAction(c, tx, index)
return actiondb.CollateralizeRetrieve(payload)
}
// Exec_Close Action
func (c *Collateralize) Exec_Manage(payload *pty.CollateralizeManage, tx *types.Transaction, index int) (*types.Receipt, error) {
actiondb := NewCollateralizeAction(c, tx, index)
return actiondb.CollateralizeManage(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"
pty "github.com/33cn/plugin/plugin/dapp/collateralize/types"
)
func (c *Collateralize) execDelLocal(tx *types.Transaction, receiptData *types.ReceiptData) (*types.LocalDBSet, error) {
kvs, err := c.DelRollbackKV(tx, tx.Execer)
if err != nil {
return nil, err
}
dbSet := &types.LocalDBSet{}
dbSet.KV = append(dbSet.KV, kvs...)
return dbSet, nil
}
// ExecDelLocal_Create Action
func (c *Collateralize) ExecDelLocal_Create(payload *pty.CollateralizeCreate, tx *types.Transaction, receiptData *types.ReceiptData, index int) (*types.LocalDBSet, error) {
return c.execDelLocal(tx, receiptData)
}
// ExecDelLocal_Borrow Action
func (c *Collateralize) ExecDelLocal_Borrow(payload *pty.CollateralizeBorrow, tx *types.Transaction, receiptData *types.ReceiptData, index int) (*types.LocalDBSet, error) {
return c.execDelLocal(tx, receiptData)
}
// ExecDelLocal_Repay Action
func (c *Collateralize) ExecDelLocal_Repay(payload *pty.CollateralizeRepay, tx *types.Transaction, receiptData *types.ReceiptData, index int) (*types.LocalDBSet, error) {
return c.execDelLocal(tx, receiptData)
}
// ExecDelLocal_Append Action
func (c *Collateralize) ExecDelLocal_Append(payload *pty.CollateralizeAppend, tx *types.Transaction, receiptData *types.ReceiptData, index int) (*types.LocalDBSet, error) {
return c.execDelLocal(tx, receiptData)
}
// ExecDelLocal_Feed Action
func (c *Collateralize) ExecDelLocal_Feed(payload *pty.CollateralizeFeed, tx *types.Transaction, receiptData *types.ReceiptData, index int) (*types.LocalDBSet, error) {
return c.execDelLocal(tx, receiptData)
}
// ExecDelLocal_Retrieve Action
func (c *Collateralize) ExecDelLocal_Retrieve(payload *pty.CollateralizeRetrieve, tx *types.Transaction, receiptData *types.ReceiptData, index int) (*types.LocalDBSet, error) {
return c.execDelLocal(tx, receiptData)
}
// ExecDelLocal_Manage Action
func (c *Collateralize) ExecDelLocal_Manage(payload *pty.CollateralizeManage, tx *types.Transaction, receiptData *types.ReceiptData, index int) (*types.LocalDBSet, error) {
return c.execDelLocal(tx, receiptData)
}
// 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/common/db/table"
//"github.com/33cn/chain33/common"
"github.com/33cn/chain33/types"
pty "github.com/33cn/plugin/plugin/dapp/collateralize/types"
)
func (c *Collateralize) execLocal(tx *types.Transaction, receipt *types.ReceiptData) (*types.LocalDBSet, error) {
set := &types.LocalDBSet{}
var collTable, recordTable *table.Table
for _, item := range receipt.Logs {
if item.Ty >= pty.TyLogCollateralizeCreate && item.Ty <= pty.TyLogCollateralizeRetrieve {
var collateralizeLog pty.ReceiptCollateralize
err := types.Decode(item.Log, &collateralizeLog)
if err != nil {
return nil, err
}
if item.Ty == pty.TyLogCollateralizeCreate || item.Ty == pty.TyLogCollateralizeRetrieve {
collTable = pty.NewCollateralizeTable(c.GetLocalDB())
err = collTable.Replace(&pty.ReceiptCollateralize{CollateralizeId: collateralizeLog.CollateralizeId, Status: collateralizeLog.Status,
AccountAddr: collateralizeLog.AccountAddr})
if err != nil {
return nil, err
}
} else {
recordTable = pty.NewRecordTable(c.GetLocalDB())
err = recordTable.Replace(&pty.ReceiptCollateralize{CollateralizeId: collateralizeLog.CollateralizeId, Status: collateralizeLog.Status,
RecordId: collateralizeLog.RecordId, AccountAddr: collateralizeLog.AccountAddr})
if err != nil {
return nil, err
}
}
}
}
if collTable != nil {
kvs, err := collTable.Save()
if err != nil {
return nil, err
}
set.KV = append(set.KV, kvs...)
}
if recordTable != nil {
kvs, err := recordTable.Save()
if err != nil {
return nil, err
}
set.KV = append(set.KV, kvs...)
}
set.KV = c.AddRollbackKV(tx, []byte(pty.CollateralizeX), set.KV)
return set, nil
}
// ExecLocal_Create Action
func (c *Collateralize) ExecLocal_Create(payload *pty.CollateralizeCreate, tx *types.Transaction, receiptData *types.ReceiptData, index int) (*types.LocalDBSet, error) {
return c.execLocal(tx, receiptData)
}
// ExecLocal_Borrow Action
func (c *Collateralize) ExecLocal_Borrow(payload *pty.CollateralizeBorrow, tx *types.Transaction, receiptData *types.ReceiptData, index int) (*types.LocalDBSet, error) {
return c.execLocal(tx, receiptData)
}
// ExecLocal_Repay Action
func (c *Collateralize) ExecLocal_Repay(payload *pty.CollateralizeRepay, tx *types.Transaction, receiptData *types.ReceiptData, index int) (*types.LocalDBSet, error) {
return c.execLocal(tx, receiptData)
}
// ExecLocal_Repay Action
func (c *Collateralize) ExecLocal_Append(payload *pty.CollateralizeAppend, tx *types.Transaction, receiptData *types.ReceiptData, index int) (*types.LocalDBSet, error) {
return c.execLocal(tx, receiptData)
}
// ExecLocal_Feed Action
func (c *Collateralize) ExecLocal_Feed(payload *pty.CollateralizeFeed, tx *types.Transaction, receiptData *types.ReceiptData, index int) (*types.LocalDBSet, error) {
return c.execLocal(tx, receiptData)
}
// ExecLocal_Retrieve Action
func (c *Collateralize) ExecLocal_Retrieve(payload *pty.CollateralizeRetrieve, tx *types.Transaction, receiptData *types.ReceiptData, index int) (*types.LocalDBSet, error) {
return c.execLocal(tx, receiptData)
}
// ExecLocal_Manage Action
func (c *Collateralize) ExecLocal_Manage(payload *pty.CollateralizeManage, tx *types.Transaction, receiptData *types.ReceiptData, index int) (*types.LocalDBSet, error) {
return c.execLocal(tx, receiptData)
}
// 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"
pty "github.com/33cn/plugin/plugin/dapp/collateralize/types"
)
func (c *Collateralize) Query_CollateralizeInfoByID(req *pty.ReqCollateralizeInfo) (types.Message, error) {
coll, err := queryCollateralizeByID(c.GetStateDB(), req.CollateralizeId)
if err != nil {
clog.Error("Query_CollateralizeInfoByID", "id", req.CollateralizeId, "error", err)
return nil, err
}
info := &pty.RepCollateralizeCurrentInfo{
Status: coll.Status,
TotalBalance: coll.TotalBalance,
DebtCeiling: coll.DebtCeiling,
LiquidationRatio: coll.LiquidationRatio,
StabilityFeeRatio: coll.StabilityFeeRatio,
CreateAddr: coll.CreateAddr,
Balance: coll.Balance,
Period: coll.Period,
CollateralizeId: coll.CollateralizeId,
CollBalance: coll.CollBalance,
}
info.BorrowRecords = append(info.BorrowRecords, coll.BorrowRecords...)
info.BorrowRecords = append(info.BorrowRecords, coll.InvalidRecords...)
return info, nil
}
func (c *Collateralize) Query_CollateralizeInfoByIDs(req *pty.ReqCollateralizeInfos) (types.Message, error) {
infos := &pty.RepCollateralizeCurrentInfos{}
for _, id := range req.CollateralizeIds {
coll, err := queryCollateralizeByID(c.GetStateDB(), id)
if err != nil {
clog.Error("Query_CollateralizeInfoByID", "id", id, "error", err)
return nil, err
}
info := &pty.RepCollateralizeCurrentInfo{
Status: coll.Status,
TotalBalance: coll.TotalBalance,
DebtCeiling: coll.DebtCeiling,
LiquidationRatio: coll.LiquidationRatio,
StabilityFeeRatio: coll.StabilityFeeRatio,
CreateAddr: coll.CreateAddr,
Balance: coll.Balance,
Period: coll.Period,
CollateralizeId: coll.CollateralizeId,
CollBalance: coll.CollBalance,
}
info.BorrowRecords = append(info.BorrowRecords, coll.BorrowRecords...)
info.BorrowRecords = append(info.BorrowRecords, coll.InvalidRecords...)
infos.Infos = append(infos.Infos, info)
}
return infos, nil
}
func (c *Collateralize) Query_CollateralizeByStatus(req *pty.ReqCollateralizeByStatus) (types.Message, error) {
ids := &pty.RepCollateralizeIDs{}
collIDRecords, err := queryCollateralizeByStatus(c.GetLocalDB(), req.Status, req.CollID)
if err != nil {
clog.Error("Query_CollateralizeByStatus", "get collateralize record error", err)
return nil, err
}
ids.IDs = append(ids.IDs, collIDRecords...)
return ids, nil
}
func (c *Collateralize) Query_CollateralizeByAddr(req *pty.ReqCollateralizeByAddr) (types.Message, error) {
ids := &pty.RepCollateralizeIDs{}
collIDRecords, err := queryCollateralizeByAddr(c.GetLocalDB(), req.Addr, req.Status, req.CollID)
if err != nil {
clog.Error("Query_CollateralizeByAddr", "get collateralize record error", err)
return nil, err
}
ids.IDs = append(ids.IDs, collIDRecords...)
return ids, nil
}
func (c *Collateralize) Query_CollateralizeRecordByID(req *pty.ReqCollateralizeRecord) (types.Message, error) {
ret := &pty.RepCollateralizeRecord{}
issuRecord, err := queryCollateralizeRecordByID(c.GetStateDB(), req.CollateralizeId, req.RecordId)
if err != nil {
clog.Error("Query_IssuanceRecordByID", "get collateralize record error", err)
return nil, err
}
ret.Record = issuRecord
return ret, nil
}
func (c *Collateralize) Query_CollateralizeRecordByAddr(req *pty.ReqCollateralizeRecordByAddr) (types.Message, error) {
ret := &pty.RepCollateralizeRecords{}
records, err := queryCollateralizeRecordByAddr(c.GetStateDB(), c.GetLocalDB(), req.Addr, req.Status, req.CollateralizeId, req.RecordId)
if err != nil {
clog.Error("Query_CollateralizeRecordByAddr", "get collateralize record error", err)
return nil, err
}
if req.Status == 0 {
ret.Records = records
} else {
for _, record := range records {
if record.Status == req.Status {
ret.Records = append(ret.Records, record)
}
}
}
return ret, nil
}
func (c *Collateralize) Query_CollateralizeRecordByStatus(req *pty.ReqCollateralizeRecordByStatus) (types.Message, error) {
ret := &pty.RepCollateralizeRecords{}
records, err := queryCollateralizeRecordByStatus(c.GetStateDB(), c.GetLocalDB(), req.Status, req.CollateralizeId, req.RecordId)
if err != nil {
clog.Error("Query_CollateralizeRecordByStatus", "get collateralize record error", err)
return nil, err
}
ret.Records = records
return ret, nil
}
func (c *Collateralize) Query_CollateralizeConfig(req *pty.ReqCollateralizeRecordByAddr) (types.Message, error) {
config, err := getCollateralizeConfig(c.GetStateDB())
if err != nil {
clog.Error("Query_CollateralizeConfig", "get collateralize config error", err)
return nil, err
}
balance, err := getCollBalance(config.TotalBalance, c.GetLocalDB(), c.GetStateDB())
if err != nil {
clog.Error("Query_CollateralizeInfoByID", "error", err)
return nil, err
}
ret := &pty.RepCollateralizeConfig{
TotalBalance: config.TotalBalance,
DebtCeiling: config.DebtCeiling,
LiquidationRatio: config.LiquidationRatio,
StabilityFeeRatio: config.StabilityFeeRatio,
Period: config.Period,
Balance: balance,
CurrentTime: config.CurrentTime,
}
return ret, nil
}
func (c *Collateralize) Query_CollateralizePrice(req *pty.ReqCollateralizeRecordByAddr) (types.Message, error) {
price, err := getLatestPrice(c.GetStateDB())
if err != nil {
clog.Error("Query_CollateralizePrice", "error", err)
return nil, err
}
return &pty.RepCollateralizePrice{Price: price}, nil
}
func (c *Collateralize) Query_CollateralizeUserBalance(req *pty.ReqCollateralizeRecordByAddr) (types.Message, error) {
balance, err := queryCollateralizeUserBalance(c.GetStateDB(), c.GetLocalDB(), req.Addr)
if err != nil {
clog.Error("Query_CollateralizeRecordByAddr", "get collateralize record error", err)
return nil, err
}
return &pty.RepCollateralizeUserBalance{Balance: balance}, 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 collateralize
import (
"github.com/33cn/chain33/pluginmgr"
"github.com/33cn/plugin/plugin/dapp/collateralize/commands"
"github.com/33cn/plugin/plugin/dapp/collateralize/executor"
"github.com/33cn/plugin/plugin/dapp/collateralize/types"
)
func init() {
pluginmgr.Register(&pluginmgr.PluginBase{
Name: types.CollateralizeX,
ExecName: executor.GetName(),
Exec: executor.Init,
Cmd: commands.CollateralizeCmd,
})
}
all:
sh ./create_protobuf.sh
syntax = "proto3";
package types;
// 放贷信息
message Collateralize {
string collateralizeId = 1; //放贷ID,一期放贷对应一个ID
int64 totalBalance = 2; //当期放贷的总金额(ccny)
int64 debtCeiling = 3; //单用户可借出的限额(ccny)
int64 liquidationRatio = 4; //清算比例
int64 stabilityFeeRatio = 5; //稳定费率
string createAddr = 6; //创建人地址
int64 balance = 7; //放贷剩余金额(ccny)
repeated BorrowRecord borrowRecords = 8; //借贷记录
repeated BorrowRecord InvalidRecords = 9; //失效的借贷记录
int32 status = 10;//当期借贷的状态,是否关闭
int64 latestLiquidationPrice = 11;//最高清算价格
int64 period = 12;//借贷最大期限
int64 latestExpireTime = 13;//最近超期时间
int64 collBalance = 14;//抵押bty
int32 preStatus = 15;//上一个状态
}
// 借出记录
message BorrowRecord {
string accountAddr = 1; //借贷人地址
int64 startTime = 2; //借贷时间
int64 collateralValue = 3; //抵押物价值(bty)
int64 collateralPrice = 4; //抵押物价格
int64 debtValue = 5; //债务价值(ccny)
int64 liquidationPrice = 6; //抵押物清算价格
int32 status = 7; //抵押状态,是否被清算
int64 liquidateTime = 8; //清算时间
int64 expireTime = 9; //超时清算时间
int32 preStatus = 10;//上一次抵押状态,用于告警恢复
string recordId = 11;//借贷id,标识一次借出记录
string collateralizeId = 12;//放贷id
}
// 资产价格记录
message AssetPriceRecord {
int64 recordTime = 1; //价格记录时间
int64 btyPrice = 2; //bty价格
int64 btcPrice = 3; //btc价格
int64 ethPrice = 4; //eth价格
}
// action
message CollateralizeAction {
oneof value {
CollateralizeCreate create = 1; //创建一期借贷
CollateralizeBorrow borrow = 2; //借贷
CollateralizeRepay repay = 3; //清算
CollateralizeAppend append = 4; //追加
CollateralizeFeed feed = 5; //喂价
CollateralizeRetrieve retrieve = 6; //收回
CollateralizeManage manage = 7; //全局配置
}
int32 ty = 10;
}
message CollateralizeManage {
int64 debtCeiling = 1; //单用户可借出的限额(ccny)
int64 liquidationRatio = 2; //清算比例
int64 stabilityFeeRatio = 3; //稳定费
int64 period = 4; //合约期限
int64 totalBalance = 5; //放贷总量
int64 currentTime = 6; //设置时间
}
message CollateralizeAddr {
repeated string superAddrs = 1; //大户地址
}
// 创建放贷
message CollateralizeCreate {
int64 totalBalance = 1; //可借贷总金额
}
// 质押借出
message CollateralizeBorrow {
string collateralizeId = 1; //借贷期数ID
int64 value = 2; //借贷价值(ccny)
}
// 质押清算
message CollateralizeRepay {
string collateralizeId = 1; //借贷期数ID
string recordId = 2; //借贷ID
}
// 追加抵押物
message CollateralizeAppend {
string collateralizeId = 1; //借贷期数ID
string recordId = 2; //借贷ID
int64 collateralValue = 3; //追加价值(bty)
}
// 喂价
message CollateralizeFeed {
int32 collType = 1; //抵押物价格类型(1,bty,2,btc,3,eth...)
repeated int64 price = 2; //喂价
repeated int64 volume = 3; //成交量
}
// 收回
message CollateralizeRetrieve {
string collateralizeId = 1; //借贷期数ID
int64 balance = 2; //收回金额
}
// exec_local 放贷信息
message ReceiptCollateralize {
string collateralizeId = 1;
string accountAddr = 3;
string recordId = 4;
int32 status = 5;
}
// exec_local 放贷记录信息列表
message CollateralizeRecords {
repeated ReceiptCollateralize records = 1;
}
// 根据ID查询一期放贷信息
message ReqCollateralizeInfo {
string collateralizeId = 1;
}
// 返回一期放贷信息
message RepCollateralizeCurrentInfo {
int32 status = 1;//当期借贷的状态,是否关闭
int64 totalBalance = 2; //当期可借贷的总金额(ccny)
int64 debtCeiling = 3; //单用户可借出的限额(ccny)
int64 liquidationRatio = 4; //清算比例
int64 stabilityFeeRatio = 5; //稳定费
string createAddr = 6; //创建人地址
int64 balance = 7; //剩余可借贷金额(ccny)
int64 period = 8; //合约期限
string collateralizeId = 9; //放贷ID
int64 collBalance = 10;//抵押bty
repeated BorrowRecord borrowRecords = 11;//借贷记录
}
// 根据ID列表查询多期放贷信息
message ReqCollateralizeInfos {
repeated string collateralizeIds = 1;
}
// 返回多期放贷信息
message RepCollateralizeCurrentInfos {
repeated RepCollateralizeCurrentInfo infos = 1;
}
// 根据放贷状态查询
message ReqCollateralizeByStatus {
int32 status = 1;
string collID = 2;
}
// 根据用户地址查询
message ReqCollateralizeByAddr {
string addr = 1;
int32 status = 2;
string collID = 3;
}
// 返回放贷ID列表
message RepCollateralizeIDs {
repeated string IDs = 1;
}
// 根据地址和借贷ID混合查询具体借贷记录
message ReqCollateralizeRecordByAddr {
string collateralizeId = 1;
string addr = 2;
int32 status = 3;
string recordId = 4;
}
// 根据状态和借贷ID混合查询具体借贷记录
message ReqCollateralizeRecordByStatus {
string collateralizeId = 1;
int32 status = 2;
string recordId = 3;
}
// 返回借贷记录
message RepCollateralizeRecords {
repeated BorrowRecord records = 1;
}
// 精确查找借贷记录
message ReqCollateralizeRecord {
string collateralizeId = 1;
string recordId = 2;
}
// 返回借贷记录
message RepCollateralizeRecord {
BorrowRecord record = 1;
}
// 返回放贷配置
message RepCollateralizeConfig {
int64 debtCeiling = 1; //单用户可借出的限额(ccny)
int64 liquidationRatio = 2; //清算比例
int64 stabilityFeeRatio = 3; //稳定费
int64 period = 4; //合约期限
int64 totalBalance = 5; //放贷总量
int64 balance = 6; //剩余放贷额度
int64 currentTime = 7; //设置时间
}
// 返回最新抵押物价格
message RepCollateralizePrice {
int64 price = 1; //当前抵押物最新价格
}
// 返回用户借贷总额
message RepCollateralizeUserBalance {
int64 balance = 1; //返回用户借贷总额
}
\ No newline at end of file
#!/bin/sh
chain33_path=$(go list -f '{{.Dir}}' "github.com/33cn/chain33")
protoc --go_out=plugins=grpc:../types ./*.proto --proto_path=. --proto_path="${chain33_path}/types/proto/"
## 借贷合约表结构
### 放贷表coller表结构
字段名称|类型|说明
---|---|---
collateralizeId|string|放贷ID,主键
accountAddr|string|大户地址
recordId|string|借贷ID
status|int32|放贷状态(1:已放贷 2:已收回)
### 放贷表coller表索引
索引名|说明
---|---
status|根据放贷状态查询放贷ID
addr|根据大户地址查询放贷ID
addr_status|根据放贷状态和大户地址查询放贷ID
### 借贷表borrow表结构
字段名称|类型|说明
---|---|---
recordId|string|借贷ID,主键
collateralizeId|string|放贷ID
accountAddr|string|用户地址
status|int32|借贷状态(1:已发行 2:价格清算告警 3:价格清算 4:超时清算告警 5:超时清算 6:已清算)
### 放贷表borrow表索引
索引名|说明
---|---
status|根据借贷状态查询借贷ID
addr|根据大户地址查询借贷ID
addr_status|根据借贷状态和用户地址查询借贷ID
id_status|根据放贷ID和借贷状态查询借贷ID
id_addr|根据放贷ID和用户地址查询借贷ID
\ No newline at end of file
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 types
import "errors"
// Errors for lottery
var (
ErrRiskParam = errors.New("ErrRiskParam")
ErrCollateralizeStatus = errors.New("ErrCollateralizeStatus")
ErrCollateralizeExceedDebtCeiling = errors.New("ErrCollateralizeExceedDebtCeiling")
ErrPriceInvalid = errors.New("ErrPriceInvalid")
ErrAssetType = errors.New("ErrAssetType")
ErrRecordNotExist = errors.New("ErrRecordNotExist")
ErrCollateralizeErrCloser = errors.New("ErrCollateralizeErrCloser")
ErrRepayValueInsufficient = errors.New("ErrRepayValueInsufficient")
ErrCollateralizeAccountExist = errors.New("ErrCollateralizeAccountExist")
ErrCollateralizeLowBalance = errors.New("ErrCollateralizeLowBalance")
ErrCollateralizeBalanceInvalid = errors.New("ErrCollateralizeBalanceInvalid")
ErrPermissionDeny = errors.New("ErrPermissionDeny")
ErrCollateralizeRecordNotEmpty = errors.New("ErrCollateralizeRecordNotEmpty")
)
package types
import (
"fmt"
"github.com/33cn/chain33/common/db"
"github.com/33cn/chain33/common/db/table"
"github.com/33cn/chain33/types"
)
var opt = &table.Option{
Prefix: "LODB-collateralize",
Name: "coller",
Primary: "collateralizeid",
Index: []string{"status", "addr", "addr_status"},
}
//NewTable 新建表
func NewCollateralizeTable(kvdb db.KV) *table.Table {
rowmeta := NewCollatetalizeRow()
table, err := table.NewTable(rowmeta, kvdb, opt)
if err != nil {
panic(err)
}
return table
}
//CollatetalizeRow table meta 结构
type CollatetalizeRow struct {
*ReceiptCollateralize
}
//NewIssuanceRow 新建一个meta 结构
func NewCollatetalizeRow() *CollatetalizeRow {
return &CollatetalizeRow{ReceiptCollateralize: &ReceiptCollateralize{}}
}
//CreateRow 新建数据行
func (tx *CollatetalizeRow) CreateRow() *table.Row {
return &table.Row{Data: &ReceiptCollateralize{}}
}
//SetPayload 设置数据
func (tx *CollatetalizeRow) SetPayload(data types.Message) error {
if txdata, ok := data.(*ReceiptCollateralize); ok {
tx.ReceiptCollateralize = txdata
return nil
}
return types.ErrTypeAsset
}
//Get 按照indexName 查询 indexValue
func (tx *CollatetalizeRow) Get(key string) ([]byte, error) {
if key == "collateralizeid" {
return []byte(tx.CollateralizeId), nil
} else if key == "status" {
return []byte(fmt.Sprintf("%2d", tx.Status)), nil
} else if key == "addr" {
return []byte(tx.AccountAddr), nil
} else if key == "addr_status" {
return []byte(fmt.Sprintf("%s:%2d", tx.AccountAddr, tx.Status)), nil
}
return nil, types.ErrNotFound
}
var optRecord = &table.Option{
Prefix: "LODB-collateralize",
Name: "borrow",
Primary: "borrowid",
Index: []string{"status", "addr", "addr_status", "id_status", "id_addr"},
}
// NewRecordTable 借贷记录表
func NewRecordTable(kvdb db.KV) *table.Table {
rowmeta := NewRecordRow()
table, err := table.NewTable(rowmeta, kvdb, optRecord)
if err != nil {
panic(err)
}
return table
}
//CollatetalizeRow table meta 结构
type CollateralizeRecordRow struct {
*ReceiptCollateralize
}
//NewIssuanceRow 新建一个meta 结构
func NewRecordRow() *CollateralizeRecordRow {
return &CollateralizeRecordRow{ReceiptCollateralize: &ReceiptCollateralize{}}
}
//CreateRow 新建数据行
func (tx *CollateralizeRecordRow) CreateRow() *table.Row {
return &table.Row{Data: &ReceiptCollateralize{}}
}
//SetPayload 设置数据
func (tx *CollateralizeRecordRow) SetPayload(data types.Message) error {
if txdata, ok := data.(*ReceiptCollateralize); ok {
tx.ReceiptCollateralize = txdata
return nil
}
return types.ErrTypeAsset
}
//Get 按照indexName 查询 indexValue
func (tx *CollateralizeRecordRow) Get(key string) ([]byte, error) {
if key == "borrowid" {
return []byte(tx.RecordId), nil
} else if key == "status" {
return []byte(fmt.Sprintf("%2d", tx.Status)), nil
} else if key == "addr" {
return []byte(tx.AccountAddr), nil
} else if key == "addr_status" {
return []byte(fmt.Sprintf("%s:%2d", tx.AccountAddr, tx.Status)), nil
} else if key == "id_status" {
return []byte(fmt.Sprintf("%s:%2d", tx.CollateralizeId, tx.Status)), nil
} else if key == "id_addr" {
return []byte(fmt.Sprintf("%s:%s", tx.CollateralizeId, tx.AccountAddr)), nil
}
return nil, types.ErrNotFound
}
// 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
// CollateralizeCreateTx for construction
type CollateralizeCreateTx struct {
TotalBalance float64 `json:"totalBalance"`
Fee int64 `json:"fee"`
}
// CollateralizeBorrowTx for construction
type CollateralizeBorrowTx struct {
CollateralizeID string `json:"collateralizeId"`
Value float64 `json:"value"`
Fee int64 `json:"fee"`
}
// CollateralizeRepayTx for construction
type CollateralizeRepayTx struct {
CollateralizeID string `json:"collateralizeId"`
RecordID string `json:"recordID"`
Fee int64 `json:"fee"`
}
// CollateralizeAppednTx for construction
type CollateralizeAppendTx struct {
CollateralizeID string `json:"collateralizeId"`
RecordID string `json:"recordID"`
Value float64 `json:"value"`
Fee int64 `json:"fee"`
}
// CollateralizeFeedTx for construction
type CollateralizeFeedTx struct {
Price []float64 `json:"price"`
Volume []int64 `json:"volume"`
Fee int64 `json:"fee"`
}
// CollateralizeRetrieveTx for construction
type CollateralizeRetrieveTx struct {
CollateralizeID string `json:"collateralizeId"`
Balance float64 `json:"Balance"`
Fee int64 `json:"fee"`
}
// CollateralizeManageTx for construction
type CollateralizeManageTx struct {
DebtCeiling float64 `json:"debtCeiling"`
LiquidationRatio float64 `json:"liquidationRatio"`
StabilityFeeRatio float64 `json:"stabilityFeeRatio"`
Period int64 `json:"period"`
TotalBalance float64 `json:"totalBalance"`
Fee int64 `json:"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 types
//Collateralize op
const (
CollateralizeActionCreate = 1 + iota
CollateralizeActionBorrow
CollateralizeActionRepay
CollateralizeActionAppend
CollateralizeActionFeed
CollateralizeActionRetrieve
CollateralizeActionManage
//log for Collateralize
TyLogCollateralizeCreate = 731
TyLogCollateralizeBorrow = 732
TyLogCollateralizeRepay = 733
TyLogCollateralizeAppend = 734
TyLogCollateralizeFeed = 735
TyLogCollateralizeRetrieve = 736
)
// Collateralize name
const (
CollateralizeX = "collateralize"
CCNYTokenName = "CCNY"
CollateralizePreLiquidationRatio = 1.1 * 1e4 //TODO 预清算比例,抵押物价值跌到借出ccny价值110%的时候开始清算
)
//Collateralize status
const (
CollateralizeStatusCreated = 1 + iota
CollateralizeStatusClose
)
//暂时只支持bty
//const (
// CollateralizeAssetTypeBty = 1 + iota
// CollateralizeAssetTypeBtc
// CollateralizeAssetTypeEth
//)
const (
CollateralizeUserStatusCreate = 1 + iota
CollateralizeUserStatusWarning
CollateralizeUserStatusSystemLiquidate
CollateralizeUserStatusExpire
CollateralizeUserStatusExpireLiquidate
CollateralizeUserStatusClose
)
......@@ -21,7 +21,7 @@ var driverName = exchangetypes.ExchangeX
// Init register dapp
func Init(name string, cfg *types.Chain33Config, sub []byte) {
drivers.Register(cfg, GetName(), newExchange, cfg.GetDappFork(driverName, "Enable"))
drivers.Register(cfg, GetName(), NewExchange, cfg.GetDappFork(driverName, "Enable"))
InitExecType()
}
......@@ -35,7 +35,7 @@ type exchange struct {
drivers.DriverBase
}
func newExchange() drivers.Driver {
func NewExchange() drivers.Driver {
t := &exchange{}
t.SetChild(t)
t.SetExecutorType(types.LoadExecutorType(driverName))
......@@ -44,7 +44,7 @@ func newExchange() drivers.Driver {
// GetName get driver name
func GetName() string {
return newExchange().GetName()
return NewExchange().GetName()
}
func (e *exchange) GetDriverName() string {
......
This diff is collapsed.
# Title为local,表示此配置文件为本地单节点的配置。此时本地节点所在的链上只有这一个节点,共识模块一般采用solo模式。
Title="local"
TestNet=true
FixTime=false
[log]
# 日志级别,支持debug(dbug)/info/warn/error(eror)/crit
loglevel = "info"
logConsoleLevel = "info"
# 日志文件名,可带目录,所有生成的日志文件都放到此目录下
logFile = "logs/chain33.log"
# 单个日志文件的最大值(单位:兆)
maxFileSize = 300
# 最多保存的历史日志文件个数
maxBackups = 100
# 最多保存的历史日志消息(单位:天)
maxAge = 28
# 日志文件名是否使用本地时间(否则使用UTC时间)
localTime = true
# 历史日志文件是否压缩(压缩格式为gz)
compress = true
# 是否打印调用源文件和行号
callerFile = false
# 是否打印调用方法
callerFunction = false
[blockchain]
# 缓存区块的个数
defCacheSize=128
# 同步区块时一次最多申请获取的区块个数
maxFetchBlockNum=128
# 向对端节点请求同步区块的时间间隔
timeoutSeconds=5
# 使用的数据库类型
driver="leveldb"
# 数据库文件目录
dbPath="datadir"
# 数据库缓存大小
dbCache=64
# 是否为单节点
singleMode=true
# 同步区块批量写数据库时,是否需要立即写磁盘,非固态硬盘的电脑可以设置为false,以提高性能
batchsync=false
# 是否记录添加或者删除区块的序列,若节点作为主链节点,为平行链节点提供服务,需要设置为true
isRecordBlockSequence=true
# 是否为平行链节点
isParaChain=false
# 是否开启交易快速查询索引
enableTxQuickIndex=false
[p2p]
# P2P服务监听端口号
port=13802
# 种子节点,格式为ip:port,多个节点以逗号分隔,如seeds=["10.0.0.1:13802","10.0.0.2:13802","10.0.0.3:13802"]
seeds=[]
# 是否启动P2P服务
enable=true
# 是否为种子节点
isSeed=false
# 是否作为服务端,对外提供服务
serverStart=true
# 是否使用内置的种子节点
innerSeedEnable=false
# 是否使用Github获取种子节点
useGithub=false
# 最多的接入节点个数
innerBounds=300
# 使用的数据库类型
driver="leveldb"
# 数据库文件目录
dbPath="datadir/addrbook"
# 数据库缓存大小
dbCache=4
# GRPC请求日志文件
grpcLogFile="grpc33.log"
# p2p版本号,不同的测试网络选用不同的version
version=200
verMix=200
verMax=200
[rpc]
# jrpc绑定地址
jrpcBindAddr="localhost:8801"
# grpc绑定地址
grpcBindAddr="localhost:8802"
# 白名单列表,允许访问的IP地址,默认是“*”,允许所有IP访问
whitelist=["127.0.0.1"]
# jrpc方法请求白名单,默认是“*”,允许访问所有RPC方法
jrpcFuncWhitelist=["*"]
# jrpc方法请求黑名单,禁止调用黑名单里配置的rpc方法,一般和白名单配合使用,默认是空
# jrpcFuncBlacklist=["xxxx"]
# grpc方法请求白名单,默认是“*”,允许访问所有RPC方法
grpcFuncWhitelist=["*"]
# grpc方法请求黑名单,禁止调用黑名单里配置的rpc方法,一般和白名单配合使用,默认是空
# grpcFuncBlacklist=["xxx"]
# 是否开启https
enableTLS=false
# 证书文件,证书和私钥文件可以用cli工具生成
certFile="cert.pem"
# 私钥文件
keyFile="key.pem"
[mempool]
# mempool队列名称,可配,timeline,score,price
name="timeline"
# mempool缓存容量大小,默认10240
poolCacheSize=10240
# 最小得交易手续费用,这个没有默认值,必填,一般是100000
minTxFee=100000
# 每个账户在mempool中得最大交易数量,默认100
maxTxNumPerAccount=10000
# timeline 是默认的先来先进的按时间排序
[mempool.sub.timeline]
# mempool缓存容量大小,默认10240
poolCacheSize=10240
# 最小得交易手续费用,这个没有默认值,必填,一般是100000
minTxFee=100000
# 每个账户在mempool中得最大交易数量,默认100
maxTxNumPerAccount=10000
# score是分数队列模式(分数=常量a*手续费/交易字节数-常量b*时间*定量c,按分数排队,高的优先,常量a,b和定量c可配置),按分数来排序
[mempool.sub.score]
# mempool缓存容量大小,默认10240
poolCacheSize=10240
# 最小得交易手续费用,这个没有默认值,必填,一般是100000
minTxFee=100000
# 每个账户在mempool中得最大交易数量,默认100
maxTxNumPerAccount=10000
# 时间占价格比例
timeParam=1
# 手续费相对于时间的一个合适的常量,取当前unix时间戳前四位数,排队时手续费高1e-5的分数~=快1s的分数
priceConstant=1544
# 常量比例
pricePower=1
# price是价格队列模式(价格=手续费/交易字节数,价格高者优先,同价则时间早优先)
[mempool.sub.price]
# mempool缓存容量大小,默认10240
poolCacheSize=10240
# 最小得交易手续费用,这个没有默认值,必填,一般是100000
minTxFee=100000
# 每个账户在mempool中得最大交易数量,默认100
maxTxNumPerAccount=10000
[consensus]
#共识名,可选项有solo,ticket,raft,tendermint,para
name="solo"
#是否开启挖矿,开启挖矿才能创建区块
minerstart=true
#创世区块时间(UTC时间)
genesisBlockTime=1514533394
#创世交易地址
genesis="1CbEVT9RnM5oZhWMj4fxUrJX94VtRotzvs"
[mver.consensus]
#基金账户地址
fundKeyAddr = "1BQXS6TxaYYG5mADaWij4AxhZZUTpw95a5"
#用户回报
coinReward = 18
#发展基金回报
coinDevFund = 12
#ticket价格
ticketPrice = 10000
#挖矿难度
powLimitBits = "0x1f00ffff"
#每次调整难度的最大的范围,如果设置成 4 的话,范围是 (1/4 - 4),一次不能增加 4倍以上的难度,或者难度减少为 原来的 1/4 ,这个参数,是为了难度不会突然爆增加或者减少
retargetAdjustmentFactor = 4
#表示如果区块时间大于当前时间 16s ,那么区块就会判定为无效区块。
futureBlockTime = 16
#ticket冻结时长
ticketFrozenTime = 5 #5s only for test
ticketWithdrawTime = 10 #10s only for test
ticketMinerWaitTime = 2 #2s only for test
#区块包含最多交易数
maxTxNumber = 1600 #160
#调整挖矿难度的间隔,(ps:难度不是每个区块都调整的,而是每隔 targetTimespan / targetTimePerBlock 块调整一次)
targetTimespan = 2304
#每个区块打包的目标时间
targetTimePerBlock = 16
# 仅保留这一项,其他consensus相关的配置全部删除
[consensus.sub.solo]
#创世交易地址
genesis="1CbEVT9RnM5oZhWMj4fxUrJX94VtRotzvs"
#创世区块时间(UTC时间)
genesisBlockTime=1514533394
#获取交易间隔时长,单位纳秒
waitTxMs=10
[store]
# 数据存储格式名称,目前支持mavl,kvdb,kvmvcc,mpt
name="mavl"
# 数据存储驱动类别,目前支持leveldb,goleveldb,memdb,gobadgerdb,ssdb,pegasus
driver="leveldb"
# 数据文件存储路径
dbPath="datadir/mavltree"
# Cache大小
dbCache=128
# 数据库版本
localdbVersion="1.0.0"
[store.sub.mavl]
# 是否使能mavl加前缀
enableMavlPrefix=false
# 是否使能MVCC,如果mavl中enableMVCC为true此处必须为true
enableMVCC=false
# 是否使能mavl数据裁剪
enableMavlPrune=false
# 裁剪高度间隔
pruneHeight=10000
[wallet]
# 交易发送最低手续费,单位0.00000001BTY(1e-8),默认100000,即0.001BTY
minFee=100000
# walletdb驱动名,支持leveldb/memdb/gobadgerdb/ssdb/pegasus
driver="leveldb"
# walletdb路径
dbPath="wallet"
# walletdb缓存大小
dbCache=16
# 钱包发送交易签名方式
signType="secp256k1"
[wallet.sub.ticket]
# 是否关闭ticket自动挖矿,默认false
minerdisable=false
# 允许购买ticket挖矿的白名单地址,默认配置“*”,允许所有地址购买
minerwhitelist=["*"]
[exec]
#执行器执行是否免费
isFree=false
#执行器执行所需最小费用,低于Mempool和Wallet设置的MinFee,在minExecFee = 0 的情况下,isFree = true才会生效
minExecFee=100000
#是否开启stat插件
enableStat=false
#是否开启MVCC插件
enableMVCC=false
alias=["token1:token","token2:token","token3:token"]
[exec.sub.token]
#是否保存token交易信息
saveTokenTxList=true
#token审批人地址
tokenApprs = [
"1CbEVT9RnM5oZhWMj4fxUrJX94VtRotzvs",
"1Q8hGLfoGe63efeWa8fJ4Pnukhkngt6poK",
"1LY8GFia5EiyoTodMLfkB5PHNNpXRqxhyB",
"1GCzJDS6HbgTQ2emade7mEJGGWFfA15pS9",
"1JYB8sxi4He5pZWHCd3Zi2nypQ4JMB6AxN",
"12qyocayNF7Lv6C9qW4avxs2E7U41fKSfv",
]
[exec.sub.cert]
# 是否启用证书验证和签名
enable=false
# 加密文件路径
cryptoPath="authdir/crypto"
# 带证书签名类型,支持"auth_ecdsa", "auth_sm2"
signType="auth_ecdsa"
[exec.sub.relay]
#relay执行器保存BTC头执行权限地址
genesis="1CbEVT9RnM5oZhWMj4fxUrJX94VtRotzvs"
[exec.sub.manage]
#manage执行器超级管理员地址
superManager=[
"1CbEVT9RnM5oZhWMj4fxUrJX94VtRotzvs",
"12qyocayNF7Lv6C9qW4avxs2E7U41fKSfv",
"1Q8hGLfoGe63efeWa8fJ4Pnukhkngt6poK"
]
package test
import (
"github.com/33cn/chain33/types"
"github.com/golang/protobuf/proto"
)
type Cli interface {
Send(tx *types.Transaction, hexKey string) ([]*types.ReceiptLog, error)
Query(fn string, msg proto.Message) ([]byte, error)
GetExecAccount(addr string, exec string, symbol string) (*types.Account, error) // 获取 addr 在本合约中 exec 执行器下面的 symbol 子账户
}
package main
import (
"fmt"
"github.com/33cn/chain33/types"
"github.com/33cn/plugin/plugin/dapp/exchange/test"
et "github.com/33cn/plugin/plugin/dapp/exchange/types"
)
var (
cli *test.GRPCCli
PrivKeyA = "0x6da92a632ab7deb67d38c0f6560bcfed28167998f6496db64c258d5e8393a81b" // 1KSBd17H7ZK8iT37aJztFB22XGwsPTdwE4
PrivKeyB = "0x19c069234f9d3e61135fefbeb7791b149cdf6af536f26bebb310d4cd22c3fee4" // 1JRNjdEqp4LJ5fqycUBm9ayCKSeeskgMKR
)
// 批量测试前,先确保测试账户有足够的币和钱
func main() {
cli = test.NewGRPCCli("localhost:8802")
go buy()
go sell()
select {}
}
func sell() {
req := &et.LimitOrder{
LeftAsset: &et.Asset{Symbol: "bty", Execer: "coins"},
RightAsset: &et.Asset{Execer: "token", Symbol: "CCNY"},
Price: 1,
Amount: types.Coin,
Op: et.OpSell,
}
ety := types.LoadExecutorType(et.ExchangeX)
// 卖 2000 次,需 2000*1=2000 个 bty
for i := 0; i < 2000; i++ {
fmt.Println("sell ", i)
tx, err := ety.Create("LimitOrder", req)
if err != nil {
panic(err)
}
go cli.SendTx(tx, PrivKeyA)
}
}
func buy() {
req := &et.LimitOrder{
LeftAsset: &et.Asset{Symbol: "bty", Execer: "coins"},
RightAsset: &et.Asset{Execer: "token", Symbol: "CCNY"},
Price: 1,
Amount: types.Coin,
Op: et.OpBuy,
}
ety := types.LoadExecutorType(et.ExchangeX)
// 买 2000 次,需 2000*1=2000 个 ccny
for i := 0; i < 2000; i++ {
fmt.Println("buy ", i)
tx, err := ety.Create("LimitOrder", req)
if err != nil {
panic(err)
}
go cli.SendTx(tx, PrivKeyB)
}
}
This diff is collapsed.
package test
import (
"fmt"
"log"
"time"
"github.com/33cn/chain33/common/db"
"github.com/33cn/plugin/plugin/dapp/exchange/executor"
"github.com/golang/protobuf/proto"
"github.com/33cn/chain33/account"
"github.com/33cn/chain33/common/address"
"github.com/33cn/chain33/types"
"github.com/33cn/chain33/util"
"github.com/33cn/chain33/client"
"github.com/33cn/chain33/common"
"github.com/33cn/chain33/common/crypto"
"github.com/33cn/chain33/queue"
et "github.com/33cn/plugin/plugin/dapp/exchange/types"
)
type ExecCli struct {
ldb db.KVDB
sdb db.DB
height int64
blockTime int64
difficulty uint64
q queue.Queue
cfg *types.Chain33Config
execAddr string
accA *account.DB //exec account
accA1 *account.DB //exec token account
accB *account.DB
accB1 *account.DB
accC *account.DB
accC1 *account.DB
accD *account.DB
accD1 *account.DB
}
var (
Nodes = []string{
"1KSBd17H7ZK8iT37aJztFB22XGwsPTdwE4",
"1JRNjdEqp4LJ5fqycUBm9ayCKSeeskgMKR",
"1NLHPEcbTWWxxU3dGUZBhayjrCHD3psX7k",
"1MCftFynyvG2F4ED5mdHYgziDxx6vDrScs",
}
)
func NewExecCli() *ExecCli {
dir, sdb, ldb := util.CreateTestDB()
log.Println(dir)
cfg := types.NewChain33Config(types.GetDefaultCfgstring())
cfg.SetTitleOnlyForTest("chain33")
executor.Init(et.ExchangeX, cfg, nil)
total := 100000000 * types.Coin
accountA := &types.Account{
Balance: total,
Frozen: 0,
Addr: Nodes[0],
}
accountB := &types.Account{
Balance: total,
Frozen: 0,
Addr: Nodes[1],
}
accountC := &types.Account{
Balance: total,
Frozen: 0,
Addr: Nodes[2],
}
accountD := &types.Account{
Balance: total,
Frozen: 0,
Addr: Nodes[3],
}
execAddr := address.ExecAddress(et.ExchangeX)
accA, _ := account.NewAccountDB(cfg, "coins", "bty", sdb)
accA.SaveExecAccount(execAddr, accountA)
accB, _ := account.NewAccountDB(cfg, "coins", "bty", sdb)
accB.SaveExecAccount(execAddr, accountB)
accC, _ := account.NewAccountDB(cfg, "coins", "bty", sdb)
accC.SaveExecAccount(execAddr, accountC)
accD, _ := account.NewAccountDB(cfg, "coins", "bty", sdb)
accD.SaveExecAccount(execAddr, accountD)
accA1, _ := account.NewAccountDB(cfg, "token", "CCNY", sdb)
accA1.SaveExecAccount(execAddr, accountA)
accB1, _ := account.NewAccountDB(cfg, "token", "CCNY", sdb)
accB1.SaveExecAccount(execAddr, accountB)
accC1, _ := account.NewAccountDB(cfg, "token", "CCNY", sdb)
accC1.SaveExecAccount(execAddr, accountC)
accD1, _ := account.NewAccountDB(cfg, "token", "CCNY", sdb)
accD1.SaveExecAccount(execAddr, accountD)
q := queue.New("channel")
q.SetConfig(cfg)
return &ExecCli{
ldb: ldb,
sdb: sdb,
height: 1,
blockTime: time.Now().Unix(),
difficulty: 1539918074,
q: q,
cfg: cfg,
execAddr: execAddr,
accA: accA,
accA1: accA1,
accB: accB,
accB1: accB1,
accC: accC,
accC1: accC1,
accD: accD,
accD1: accD1,
}
}
func (c *ExecCli) Send(tx *types.Transaction, hexKey string) ([]*types.ReceiptLog, error) {
var err error
tx, err = types.FormatTx(c.cfg, et.ExchangeX, tx)
if err != nil {
return nil, err
}
tx, err = signTx(tx, hexKey)
if err != nil {
return nil, err
}
exec := executor.NewExchange()
if err := exec.CheckTx(tx, int(1)); err != nil {
return nil, err
}
c.height++
c.blockTime += 10
c.difficulty++
api, _ := client.New(c.q.Client(), nil)
exec.SetAPI(api)
exec.SetStateDB(c.sdb)
exec.SetLocalDB(c.ldb)
exec.SetEnv(c.height, c.blockTime, c.difficulty)
receipt, err := exec.Exec(tx, int(1))
if err != nil {
return nil, err
}
for _, kv := range receipt.KV {
c.sdb.Set(kv.Key, kv.Value)
}
receiptDate := &types.ReceiptData{Ty: receipt.Ty, Logs: receipt.Logs}
set, err := exec.ExecLocal(tx, receiptDate, int(1))
if err != nil {
return nil, err
}
for _, kv := range set.KV {
c.ldb.Set(kv.Key, kv.Value)
}
//save to database
util.SaveKVList(c.sdb, set.KV)
return receipt.Logs, nil
}
func (c *ExecCli) Query(fn string, msg proto.Message) ([]byte, error) {
api, _ := client.New(c.q.Client(), nil)
exec := executor.NewExchange()
exec.SetAPI(api)
exec.SetStateDB(c.sdb)
exec.SetLocalDB(c.ldb)
exec.SetEnv(c.height, c.blockTime, c.difficulty)
r, err := exec.Query(fn, types.Encode(msg))
if err != nil {
return nil, err
}
return types.Encode(r), nil
}
func signTx(tx *types.Transaction, hexPrivKey string) (*types.Transaction, error) {
signType := types.SECP256K1
c, err := crypto.New(types.GetSignName("", signType))
if err != nil {
return tx, err
}
bytes, err := common.FromHex(hexPrivKey[:])
if err != nil {
return tx, err
}
privKey, err := c.PrivKeyFromBytes(bytes)
if err != nil {
return tx, err
}
tx.Sign(int32(signType), privKey)
return tx, nil
}
func (c *ExecCli) GetExecAccount(addr string, exec string, symbol string) (*types.Account, error) {
//mavl-{coins}-{bty}-exec-{26htvcBNSEA7fZhAdLJphDwQRQJaHpyHTp}:{1JmFaA6unrCFYEWPGRi7uuXY1KthTJxJEP}
//mavl-{token}-{ccny}-exec-{26htvcBNSEA7fZhAdLJphDwQRQJaHpyHTp}:{1JmFaA6unrCFYEWPGRi7uuXY1KthTJxJEP}
key := []byte(fmt.Sprintf("mavl-%s-%s-exec-%s:%s", exec, symbol, c.execAddr, addr))
bytes, err := c.sdb.Get(key)
if err != nil {
return nil, err
}
var acc types.Account
err = types.Decode(bytes, &acc)
if err != nil {
return nil, err
}
return &acc, nil
}
package test
import (
"context"
"errors"
"fmt"
"strings"
"time"
"github.com/33cn/chain33/common"
"github.com/33cn/chain33/types"
"github.com/33cn/plugin/plugin/dapp/exchange/executor"
et "github.com/33cn/plugin/plugin/dapp/exchange/types"
tt "github.com/33cn/plugin/plugin/dapp/token/types"
"github.com/golang/protobuf/proto"
"google.golang.org/grpc"
)
type GRPCCli struct {
client types.Chain33Client
}
func NewGRPCCli(grpcAddr string) *GRPCCli {
conn, err := grpc.Dial(grpcAddr, grpc.WithInsecure())
if err != nil {
panic(err)
}
client := types.NewChain33Client(conn)
cfg := types.NewChain33Config(types.GetDefaultCfgstring())
cfg.SetTitleOnlyForTest("chain33")
executor.Init(et.ExchangeX, cfg, nil)
return &GRPCCli{
client: client,
}
}
func (c *GRPCCli) Send(tx *types.Transaction, hexKey string) ([]*types.ReceiptLog, error) {
txHash, logs, err := c.sendAndWaitReceipt(tx, hexKey)
if txHash != nil {
fmt.Println("txHash: ", common.ToHex(txHash))
}
if err != nil {
return nil, parseError(err)
}
for _, l := range logs {
if l.Ty == types.TyLogErr {
return nil, errors.New(string(l.Log))
}
}
return logs, nil
}
func (c *GRPCCli) Query(fn string, msg proto.Message) ([]byte, error) {
ss := strings.Split(fn, ".")
var in types.ChainExecutor
if len(ss) == 2 {
in.Driver = ss[0]
in.FuncName = ss[1]
} else {
in.Driver = et.ExchangeX
in.FuncName = fn
}
in.Param = types.Encode(msg)
r, err := c.client.QueryChain(context.Background(), &in)
if err != nil {
return nil, err
}
if !r.IsOk {
return nil, errors.New(string(r.Msg))
}
return r.Msg, nil
}
func (c *GRPCCli) GetExecAccount(addr string, exec string, symbol string) (*types.Account, error) {
if exec == "coins" {
// bty
var addrs []string
addrs = append(addrs, addr)
params := &types.ReqBalance{
Addresses: addrs,
Execer: et.ExchangeX,
}
accs, err := c.client.GetBalance(context.Background(), params)
if err != nil {
return nil, err
}
return accs.Acc[0], nil
}
// token: ccny
param := &tt.ReqAccountTokenAssets{
Address: addr,
Execer: et.ExchangeX,
}
msg, err := c.Query("token.GetAccountTokenAssets", param)
if err != nil {
return nil, err
}
var resp tt.ReplyAccountTokenAssets
err = types.Decode(msg, &resp)
if err != nil {
return nil, err
}
for _, v := range resp.TokenAssets {
if v.Symbol == symbol {
return v.Account, nil
}
}
return nil, types.ErrNotFound
}
// 发送交易并等待执行结果
// 如果交易非法,返回错误信息
// 如果交易执行成功,返回 交易哈希、回报
func (c *GRPCCli) sendAndWaitReceipt(tx *types.Transaction, hexKey string) (txHash []byte, logs []*types.ReceiptLog, err error) {
r, err := c.SendTx(tx, hexKey)
if err != nil {
// rpc error: code = Unknown desc = ErrNotBank
return nil, nil, err
}
if !r.IsOk {
return nil, nil, errors.New(string(r.Msg))
}
time.Sleep(time.Second)
d, _ := c.client.QueryTransaction(context.Background(), &types.ReqHash{Hash: r.Msg})
return r.Msg, d.Receipt.Logs, nil
}
func (c *GRPCCli) SendTx(tx *types.Transaction, hexKey string) (reply *types.Reply, err error) {
cfg := types.NewChain33Config(types.GetDefaultCfgstring())
cfg.SetTitleOnlyForTest("chain33")
tx, err = types.FormatTx(cfg, et.ExchangeX, tx)
if err != nil {
return nil, err
}
tx, err = signTx(tx, hexKey)
if err != nil {
return nil, err
}
return c.client.SendTransaction(context.Background(), tx)
}
func parseError(err error) error {
// rpc error: code = Unknown desc = ErrNotBank
str := err.Error()
sep := "desc = "
i := strings.Index(str, sep)
if i != -1 {
return errors.New(str[i+len(sep):])
}
return err
}
#!/usr/bin/env bash
BUILD=$(cd "$(dirname "$0")" && cd ../../../../build && pwd)
echo "$BUILD"
cd "$BUILD" || return
seed=$(./chain33-cli seed generate -l 0)
echo "$seed"
./chain33-cli seed save -p bty123456 -s "$seed"
sleep 1
./chain33-cli wallet unlock -p bty123456
sleep 1
./chain33-cli account list
## account
#genesis -- 1CbEVT9RnM5oZhWMj4fxUrJX94VtRotzvs
./chain33-cli account import_key -k 3990969DF92A5914F7B71EEB9A4E58D6E255F32BF042FEA5318FC8B3D50EE6E8 -l genesis
#A -- 1KSBd17H7ZK8iT37aJztFB22XGwsPTdwE4
./chain33-cli account import_key -k 0x6da92a632ab7deb67d38c0f6560bcfed28167998f6496db64c258d5e8393a81b -l A
#B -- 1JRNjdEqp4LJ5fqycUBm9ayCKSeeskgMKR
./chain33-cli account import_key -k 0x19c069234f9d3e61135fefbeb7791b149cdf6af536f26bebb310d4cd22c3fee4 -l B
#C -- 1NLHPEcbTWWxxU3dGUZBhayjrCHD3psX7k
./chain33-cli account import_key -k 0x7a80a1f75d7360c6123c32a78ecf978c1ac55636f87892df38d8b85a9aeff115 -l C
#D -- 1MCftFynyvG2F4ED5mdHYgziDxx6vDrScs
./chain33-cli account import_key -k 0xcacb1f5d51700aea07fca2246ab43b0917d70405c65edea9b5063d72eb5c6b71 -l D
## config token
./chain33-cli send config config_tx -c token-finisher -o add -v 1CbEVT9RnM5oZhWMj4fxUrJX94VtRotzvs -k 1CbEVT9RnM5oZhWMj4fxUrJX94VtRotzvs
sleep 1
./chain33-cli config query -k token-finisher
./chain33-cli send config config_tx -c token-blacklist -o add -v BTY -k 1CbEVT9RnM5oZhWMj4fxUrJX94VtRotzvs
sleep 1
./chain33-cli config query -k token-blacklist
## 10亿
./chain33-cli send token precreate -f 0.001 -i "test ccny" -n "ccny" -a 1CbEVT9RnM5oZhWMj4fxUrJX94VtRotzvs -p 0 -s CCNY -t 1000000000 -k 1CbEVT9RnM5oZhWMj4fxUrJX94VtRotzvs
sleep 1
./chain33-cli token precreated
./chain33-cli send token finish -s CCNY -f 0.001 -a 1CbEVT9RnM5oZhWMj4fxUrJX94VtRotzvs -k 1CbEVT9RnM5oZhWMj4fxUrJX94VtRotzvs
sleep 1
./chain33-cli token created
./chain33-cli token balance -a 1CbEVT9RnM5oZhWMj4fxUrJX94VtRotzvs -s CCNY -e token
## transfer bty
./chain33-cli send coins transfer -a 10000 -t 1KSBd17H7ZK8iT37aJztFB22XGwsPTdwE4 -k 1CbEVT9RnM5oZhWMj4fxUrJX94VtRotzvs
./chain33-cli send coins transfer -a 10000 -t 1JRNjdEqp4LJ5fqycUBm9ayCKSeeskgMKR -k 1CbEVT9RnM5oZhWMj4fxUrJX94VtRotzvs
./chain33-cli send coins transfer -a 10000 -t 1NLHPEcbTWWxxU3dGUZBhayjrCHD3psX7k -k 1CbEVT9RnM5oZhWMj4fxUrJX94VtRotzvs
./chain33-cli send coins transfer -a 10000 -t 1MCftFynyvG2F4ED5mdHYgziDxx6vDrScs -k 1CbEVT9RnM5oZhWMj4fxUrJX94VtRotzvs
./chain33-cli account list
## send bty to execer, 每人10000 bty
./chain33-cli send coins send_exec -e exchange -a 10000 -k 1KSBd17H7ZK8iT37aJztFB22XGwsPTdwE4
./chain33-cli send coins send_exec -e exchange -a 10000 -k 1JRNjdEqp4LJ5fqycUBm9ayCKSeeskgMKR
./chain33-cli send coins send_exec -e exchange -a 10000 -k 1NLHPEcbTWWxxU3dGUZBhayjrCHD3psX7k
./chain33-cli send coins send_exec -e exchange -a 10000 -k 1MCftFynyvG2F4ED5mdHYgziDxx6vDrScs
echo "account balance in execer"
./chain33-cli account balance -e exchange -a 1KSBd17H7ZK8iT37aJztFB22XGwsPTdwE4
./chain33-cli account balance -e exchange -a 1JRNjdEqp4LJ5fqycUBm9ayCKSeeskgMKR
./chain33-cli account balance -e exchange -a 1NLHPEcbTWWxxU3dGUZBhayjrCHD3psX7k
./chain33-cli account balance -e exchange -a 1MCftFynyvG2F4ED5mdHYgziDxx6vDrScs
##transfer token,每人2亿 ccny
./chain33-cli send token transfer -a 200000000 -s CCNY -t 1KSBd17H7ZK8iT37aJztFB22XGwsPTdwE4 -k 1CbEVT9RnM5oZhWMj4fxUrJX94VtRotzvs
./chain33-cli send token transfer -a 200000000 -s CCNY -t 1JRNjdEqp4LJ5fqycUBm9ayCKSeeskgMKR -k 1CbEVT9RnM5oZhWMj4fxUrJX94VtRotzvs
./chain33-cli send token transfer -a 200000000 -s CCNY -t 1NLHPEcbTWWxxU3dGUZBhayjrCHD3psX7k -k 1CbEVT9RnM5oZhWMj4fxUrJX94VtRotzvs
./chain33-cli send token transfer -a 200000000 -s CCNY -t 1MCftFynyvG2F4ED5mdHYgziDxx6vDrScs -k 1CbEVT9RnM5oZhWMj4fxUrJX94VtRotzvs
## send token to excer
./chain33-cli send token send_exec -a 200000000 -e exchange -s CCNY -k 1KSBd17H7ZK8iT37aJztFB22XGwsPTdwE4
./chain33-cli send token send_exec -a 200000000 -e exchange -s CCNY -k 1JRNjdEqp4LJ5fqycUBm9ayCKSeeskgMKR
./chain33-cli send token send_exec -a 200000000 -e exchange -s CCNY -k 1NLHPEcbTWWxxU3dGUZBhayjrCHD3psX7k
./chain33-cli send token send_exec -a 200000000 -e exchange -s CCNY -k 1MCftFynyvG2F4ED5mdHYgziDxx6vDrScs
echo "token balance in execer"
./chain33-cli token balance -e exchange -s CCNY -a "1KSBd17H7ZK8iT37aJztFB22XGwsPTdwE4 1JRNjdEqp4LJ5fqycUBm9ayCKSeeskgMKR 1NLHPEcbTWWxxU3dGUZBhayjrCHD3psX7k 1MCftFynyvG2F4ED5mdHYgziDxx6vDrScs"
package init
import (
_ "github.com/33cn/plugin/plugin/dapp/autonomy" //auto gen
_ "github.com/33cn/plugin/plugin/dapp/blackwhite" //auto gen
_ "github.com/33cn/plugin/plugin/dapp/cert" //auto gen
_ "github.com/33cn/plugin/plugin/dapp/dposvote" //auto gen
_ "github.com/33cn/plugin/plugin/dapp/echo" //auto gen
_ "github.com/33cn/plugin/plugin/dapp/evm" //auto gen
_ "github.com/33cn/plugin/plugin/dapp/exchange" //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/js" //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/oracle" //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/storage" //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
_ "github.com/33cn/plugin/plugin/dapp/autonomy" //auto gen
_ "github.com/33cn/plugin/plugin/dapp/blackwhite" //auto gen
_ "github.com/33cn/plugin/plugin/dapp/cert" //auto gen
_ "github.com/33cn/plugin/plugin/dapp/collateralize" //auto gen
_ "github.com/33cn/plugin/plugin/dapp/dposvote" //auto gen
_ "github.com/33cn/plugin/plugin/dapp/echo" //auto gen
_ "github.com/33cn/plugin/plugin/dapp/evm" //auto gen
_ "github.com/33cn/plugin/plugin/dapp/exchange" //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/issuance" //auto gen
_ "github.com/33cn/plugin/plugin/dapp/js" //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/oracle" //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/storage" //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
)
all:
chmod +x ./build.sh
./build.sh $(OUT) $(FLAG)
\ No newline at end of file
#!/usr/bin/env bash
strpwd=$(pwd)
strcmd=${strpwd##*dapp/}
strapp=${strcmd%/cmd*}
OUT_TESTDIR="${1}/dapptest/$strapp"
mkdir -p "${OUT_TESTDIR}"
cp ./test/test-rpc.sh "${OUT_TESTDIR}"
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 executor
/*
waiting for update
*/
// 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"
pty "github.com/33cn/plugin/plugin/dapp/issuance/types"
)
// Exec_Create Action
func (c *Issuance) Exec_Create(payload *pty.IssuanceCreate, tx *types.Transaction, index int) (*types.Receipt, error) {
actiondb := NewIssuanceAction(c, tx, index)
return actiondb.IssuanceCreate(payload)
}
// Exec_Borrow Action
func (c *Issuance) Exec_Debt(payload *pty.IssuanceDebt, tx *types.Transaction, index int) (*types.Receipt, error) {
actiondb := NewIssuanceAction(c, tx, index)
return actiondb.IssuanceDebt(payload)
}
// Exec_Repay Action
func (c *Issuance) Exec_Repay(payload *pty.IssuanceRepay, tx *types.Transaction, index int) (*types.Receipt, error) {
actiondb := NewIssuanceAction(c, tx, index)
return actiondb.IssuanceRepay(payload)
}
// Exec_Feed Action
func (c *Issuance) Exec_Feed(payload *pty.IssuanceFeed, tx *types.Transaction, index int) (*types.Receipt, error) {
actiondb := NewIssuanceAction(c, tx, index)
return actiondb.IssuanceFeed(payload)
}
// Exec_Close Action
func (c *Issuance) Exec_Close(payload *pty.IssuanceClose, tx *types.Transaction, index int) (*types.Receipt, error) {
actiondb := NewIssuanceAction(c, tx, index)
return actiondb.IssuanceClose(payload)
}
// Exec_Manage Action
func (c *Issuance) Exec_Manage(payload *pty.IssuanceManage, tx *types.Transaction, index int) (*types.Receipt, error) {
actiondb := NewIssuanceAction(c, tx, index)
return actiondb.IssuanceManage(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"
pty "github.com/33cn/plugin/plugin/dapp/issuance/types"
)
func (c *Issuance) execDelLocal(tx *types.Transaction, receiptData *types.ReceiptData) (*types.LocalDBSet, error) {
kvs, err := c.DelRollbackKV(tx, tx.Execer)
if err != nil {
return nil, err
}
dbSet := &types.LocalDBSet{}
dbSet.KV = append(dbSet.KV, kvs...)
return dbSet, nil
}
// ExecDelLocal_Create Action
func (c *Issuance) ExecDelLocal_Create(payload *pty.IssuanceCreate, tx *types.Transaction, receiptData *types.ReceiptData, index int) (*types.LocalDBSet, error) {
return c.execDelLocal(tx, receiptData)
}
// ExecDelLocal_Debt Action
func (c *Issuance) ExecDelLocal_Debt(payload *pty.IssuanceDebt, tx *types.Transaction, receiptData *types.ReceiptData, index int) (*types.LocalDBSet, error) {
return c.execDelLocal(tx, receiptData)
}
// ExecDelLocal_Repay Action
func (c *Issuance) ExecDelLocal_Repay(payload *pty.IssuanceRepay, tx *types.Transaction, receiptData *types.ReceiptData, index int) (*types.LocalDBSet, error) {
return c.execDelLocal(tx, receiptData)
}
// ExecDelLocal_Feed Action
func (c *Issuance) ExecDelLocal_Feed(payload *pty.IssuanceFeed, tx *types.Transaction, receiptData *types.ReceiptData, index int) (*types.LocalDBSet, error) {
return c.execDelLocal(tx, receiptData)
}
// ExecDelLocal_Close Action
func (c *Issuance) ExecDelLocal_Close(payload *pty.IssuanceClose, tx *types.Transaction, receiptData *types.ReceiptData, index int) (*types.LocalDBSet, error) {
return c.execDelLocal(tx, receiptData)
}
// ExecDelLocal_Manage Action
func (c *Issuance) ExecDelLocal_Manage(payload *pty.IssuanceManage, tx *types.Transaction, receiptData *types.ReceiptData, index int) (*types.LocalDBSet, error) {
return c.execDelLocal(tx, receiptData)
}
// 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/common/db/table"
//"github.com/33cn/chain33/common"
"github.com/33cn/chain33/types"
pty "github.com/33cn/plugin/plugin/dapp/issuance/types"
)
func (c *Issuance) execLocal(tx *types.Transaction, receipt *types.ReceiptData) (*types.LocalDBSet, error) {
set := &types.LocalDBSet{}
var IDtable, recordTable *table.Table
for _, item := range receipt.Logs {
if item.Ty >= pty.TyLogIssuanceCreate && item.Ty <= pty.TyLogIssuanceClose {
var issuanceLog pty.ReceiptIssuance
err := types.Decode(item.Log, &issuanceLog)
if err != nil {
return nil, err
}
if item.Ty == pty.TyLogIssuanceCreate || item.Ty == pty.TyLogIssuanceClose {
IDtable = pty.NewIssuanceTable(c.GetLocalDB())
err = IDtable.Replace(&pty.ReceiptIssuanceID{IssuanceId: issuanceLog.IssuanceId, Status: issuanceLog.Status})
if err != nil {
return nil, err
}
} else {
recordTable = pty.NewRecordTable(c.GetLocalDB())
err = recordTable.Replace(&pty.ReceiptIssuance{IssuanceId: issuanceLog.IssuanceId, Status: issuanceLog.Status,
DebtId: issuanceLog.DebtId, AccountAddr: issuanceLog.AccountAddr})
if err != nil {
return nil, err
}
}
}
}
if IDtable != nil {
kvs, err := IDtable.Save()
if err != nil {
return nil, err
}
set.KV = append(set.KV, kvs...)
}
if recordTable != nil {
kvs, err := recordTable.Save()
if err != nil {
return nil, err
}
set.KV = append(set.KV, kvs...)
}
set.KV = c.AddRollbackKV(tx, []byte(pty.IssuanceX), set.KV)
return set, nil
}
// ExecLocal_Create Action
func (c *Issuance) ExecLocal_Create(payload *pty.IssuanceCreate, tx *types.Transaction, receiptData *types.ReceiptData, index int) (*types.LocalDBSet, error) {
return c.execLocal(tx, receiptData)
}
// ExecLocal_Debt Action
func (c *Issuance) ExecLocal_Debt(payload *pty.IssuanceDebt, tx *types.Transaction, receiptData *types.ReceiptData, index int) (*types.LocalDBSet, error) {
return c.execLocal(tx, receiptData)
}
// ExecLocal_Repay Action
func (c *Issuance) ExecLocal_Repay(payload *pty.IssuanceRepay, tx *types.Transaction, receiptData *types.ReceiptData, index int) (*types.LocalDBSet, error) {
return c.execLocal(tx, receiptData)
}
// ExecLocal_Feed Action
func (c *Issuance) ExecLocal_Feed(payload *pty.IssuanceFeed, tx *types.Transaction, receiptData *types.ReceiptData, index int) (*types.LocalDBSet, error) {
return c.execLocal(tx, receiptData)
}
// ExecLocal_Close Action
func (c *Issuance) ExecLocal_Close(payload *pty.IssuanceClose, tx *types.Transaction, receiptData *types.ReceiptData, index int) (*types.LocalDBSet, error) {
return c.execLocal(tx, receiptData)
}
// ExecLocal_Manage Action
func (c *Issuance) ExecLocal_Manage(payload *pty.IssuanceManage, tx *types.Transaction, receiptData *types.ReceiptData, index int) (*types.LocalDBSet, error) {
return c.execLocal(tx, receiptData)
}
// 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 (
log "github.com/33cn/chain33/common/log/log15"
drivers "github.com/33cn/chain33/system/dapp"
"github.com/33cn/chain33/types"
pty "github.com/33cn/plugin/plugin/dapp/issuance/types"
)
var clog = log.New("module", "execs.issuance")
var driverName = pty.IssuanceX
func InitExecType() {
ety := types.LoadExecutorType(driverName)
ety.InitFuncList(types.ListMethod(&Issuance{}))
}
// Init issuance
func Init(name string, cfg *types.Chain33Config, sub []byte) {
driverName := GetName()
if name != driverName {
panic("system dapp can't be rename")
}
if sub != nil {
types.MustDecode(sub, &cfg)
}
drivers.Register(cfg, driverName, newIssuance, cfg.GetDappFork(driverName, "Enable"))
InitExecType()
}
// GetName for Issuance
func GetName() string {
return newIssuance().GetName()
}
// Issuance driver
type Issuance struct {
drivers.DriverBase
}
func newIssuance() drivers.Driver {
c := &Issuance{}
c.SetChild(c)
c.SetExecutorType(types.LoadExecutorType(driverName))
return c
}
// GetDriverName for Issuance
func (c *Issuance) GetDriverName() string {
return pty.IssuanceX
}
// CheckReceiptExecOk return true to check if receipt ty is ok
func (c *Issuance) CheckReceiptExecOk() bool {
return true
}
// ExecutorOrder 设置localdb的EnableRead
func (c *Issuance) ExecutorOrder() int64 {
cfg := c.GetAPI().GetConfig()
if cfg.IsFork(c.GetHeight(), "ForkLocalDBAccess") {
return drivers.ExecLocalSameTime
}
return c.DriverBase.ExecutorOrder()
}
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 executor
import (
"github.com/33cn/chain33/types"
pty "github.com/33cn/plugin/plugin/dapp/issuance/types"
)
func (c *Issuance) Query_IssuanceInfoByID(req *pty.ReqIssuanceInfo) (types.Message, error) {
issu, err := queryIssuanceByID(c.GetStateDB(), req.IssuanceId)
if err != nil {
clog.Error("Query_IssuanceInfoByID", "id", req.IssuanceId, "error", err)
return nil, err
}
return &pty.RepIssuanceCurrentInfo{
Status: issu.Status,
TotalBalance: issu.TotalBalance,
DebtCeiling: issu.DebtCeiling,
LiquidationRatio: issu.LiquidationRatio,
Balance: issu.Balance,
CollateralValue: issu.CollateralValue,
DebtValue: issu.DebtValue,
Period: issu.Period,
IssuId: issu.IssuanceId,
CreateTime: issu.CreateTime,
}, nil
}
func (c *Issuance) Query_IssuanceInfoByIDs(req *pty.ReqIssuanceInfos) (types.Message, error) {
infos := &pty.RepIssuanceCurrentInfos{}
for _, id := range req.IssuanceIds {
issu, err := queryIssuanceByID(c.GetStateDB(), id)
if err != nil {
clog.Error("Query_IssuanceInfoByID", "id", id, "error", err)
return nil, err
}
infos.Infos = append(infos.Infos, &pty.RepIssuanceCurrentInfo{
Status: issu.Status,
TotalBalance: issu.TotalBalance,
DebtCeiling: issu.DebtCeiling,
LiquidationRatio: issu.LiquidationRatio,
Balance: issu.Balance,
CollateralValue: issu.CollateralValue,
DebtValue: issu.DebtValue,
Period: issu.Period,
IssuId: issu.IssuanceId,
CreateTime: issu.CreateTime,
})
}
return infos, nil
}
func (c *Issuance) Query_IssuanceByStatus(req *pty.ReqIssuanceByStatus) (types.Message, error) {
ids := &pty.RepIssuanceIDs{}
issuIDs, err := queryIssuanceByStatus(c.GetLocalDB(), req.Status, req.IssuanceId)
if err != nil {
clog.Error("Query_IssuanceByStatus", "get issuance error", err)
return nil, err
}
ids.IDs = append(ids.IDs, issuIDs...)
return ids, nil
}
func (c *Issuance) Query_IssuanceRecordByID(req *pty.ReqIssuanceRecords) (types.Message, error) {
ret := &pty.RepIssuanceDebtInfo{}
issuRecord, err := queryIssuanceRecordByID(c.GetStateDB(), req.IssuanceId, req.DebtId)
if err != nil {
clog.Error("Query_IssuanceRecordByID", "get issuance record error", err)
return nil, err
}
ret.Record = issuRecord
return ret, nil
}
func (c *Issuance) Query_IssuanceRecordsByAddr(req *pty.ReqIssuanceRecords) (types.Message, error) {
ret := &pty.RepIssuanceRecords{}
records, err := queryIssuanceRecordByAddr(c.GetStateDB(), c.GetLocalDB(), req.Addr, req.Status, req.DebtId)
if err != nil {
clog.Error("Query_IssuanceDebtInfoByAddr", "get issuance record error", err)
return nil, err
}
if req.Status == 0 {
ret.Records = records
} else {
for _, record := range records {
if record.Status == req.Status {
ret.Records = append(ret.Records, record)
}
}
}
return ret, nil
}
func (c *Issuance) Query_IssuanceRecordsByStatus(req *pty.ReqIssuanceRecords) (types.Message, error) {
ret := &pty.RepIssuanceRecords{}
records, err := queryIssuanceRecordsByStatus(c.GetStateDB(), c.GetLocalDB(), req.Status, req.DebtId)
if err != nil {
clog.Error("Query_IssuanceDebtInfoByStatus", "get issuance record error", err)
return nil, err
}
ret.Records = append(ret.Records, records...)
return ret, nil
}
func (c *Issuance) Query_IssuancePrice(req *pty.ReqIssuanceRecords) (types.Message, error) {
price, err := getLatestPrice(c.GetStateDB())
if err != nil {
clog.Error("Query_IssuancePrice", "error", err)
return nil, err
}
return &pty.RepIssuancePrice{Price: price}, nil
}
func (c *Issuance) Query_IssuanceUserBalance(req *pty.ReqIssuanceRecords) (types.Message, error) {
balance, err := queryIssuanceUserBalance(c.GetStateDB(), c.GetLocalDB(), req.Addr)
if err != nil {
clog.Error("Query_IssuanceRecordByAddr", "get issuance record error", err)
return nil, err
}
return &pty.RepIssuanceUserBalance{Balance: balance}, 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 issuance
import (
"github.com/33cn/chain33/pluginmgr"
"github.com/33cn/plugin/plugin/dapp/issuance/commands"
"github.com/33cn/plugin/plugin/dapp/issuance/executor"
"github.com/33cn/plugin/plugin/dapp/issuance/types"
)
func init() {
pluginmgr.Register(&pluginmgr.PluginBase{
Name: types.IssuanceX,
ExecName: executor.GetName(),
Exec: executor.Init,
Cmd: commands.IssuanceCmd,
})
}
all:
sh ./create_protobuf.sh
#!/bin/sh
chain33_path=$(go list -f '{{.Dir}}' "github.com/33cn/chain33")
protoc --go_out=plugins=grpc:../types ./*.proto --proto_path=. --proto_path="${chain33_path}/types/proto/"
syntax = "proto3";
package types;
// 发行信息
message Issuance {
string issuanceId = 1; //发行ID,一期发行对应一个ID
int64 totalBalance = 2; //当期发行的总金额(ccny)
int64 debtCeiling = 3; //单用户可借出的限额(ccny)
int64 liquidationRatio = 4; //清算比例
int64 collateralValue = 5; //抵押物总数量(bty)
int64 debtValue = 6; //产生的ccny数量
repeated DebtRecord debtRecords = 7; //大户抵押记录
repeated DebtRecord invalidRecords = 8; //大户抵押记录
int32 status = 9; //当期发行的状态,是否关闭
int64 latestLiquidationPrice = 10;//最高清算价格
int64 period = 11;//发行最大期限
int64 latestExpireTime = 12;//最近超期时间
int64 createTime = 13;//创建时间
int64 balance = 14;//剩余可发行ccny
string issuerAddr = 15;//发行地址
}
// 抵押记录
message DebtRecord {
string accountAddr = 1; //抵押人地址
int64 startTime = 2; //抵押时间
int64 collateralValue = 3; //抵押物价值(bty)
int64 collateralPrice = 4; //抵押物价格
int64 debtValue = 5; //债务价值(ccny)
int64 liquidationPrice = 6; //抵押物清算价格
int32 status = 7; //抵押状态,是否被清算
int64 liquidateTime = 8; //清算时间
int64 expireTime = 9; //超时清算时间
int32 preStatus = 10;//上一次抵押状态,用于告警恢复
string debtId = 11;//借贷id
string issuId = 12;//发行id
}
// 资产价格记录
message IssuanceAssetPriceRecord {
int64 recordTime = 1; //价格记录时间
int64 btyPrice = 2; //bty价格
}
// action
message IssuanceAction {
oneof value {
IssuanceCreate create = 1; //创建一期发行
IssuanceDebt debt = 2; //抵押
IssuanceRepay repay = 3; //清算
IssuanceFeed feed = 4; //喂价
IssuanceClose close = 5; //关闭
IssuanceManage manage = 6; //全局配置
}
int32 ty = 10;
}
message IssuanceManage {
repeated string superAddrs = 1; //大户地址
}
// 创建发行
message IssuanceCreate {
int64 totalBalance = 1; //发行总金额
int64 debtCeiling = 2; //单用户可借出的限额(ccny)
int64 liquidationRatio = 3; //清算比例
int64 period = 4; //发行最大期限
}
// 抵押
message IssuanceDebt {
string issuanceId = 1; //发行ID
int64 value = 2; //借贷金额(ccny)
}
// 质押清算
message IssuanceRepay {
string issuanceId = 1; //发行ID
string debtId = 2; //抵押ID
}
// 喂价
message IssuanceFeed {
int32 collType = 1; //抵押物价格类型(1,bty,2,btc,3,eth...)
repeated int64 price = 2; //喂价
repeated int64 volume = 3; //成交量
}
// 借贷关闭
message IssuanceClose {
string issuanceId = 1; //发行ID
}
// exec_local 发行信息
message ReceiptIssuance {
string issuanceId = 1;
string accountAddr = 2;
string debtId = 3;
int32 status = 4;
}
// exec_local issuid记录信息
message ReceiptIssuanceID {
string issuanceId = 1;
int32 status = 2;
}
// exec_local 抵押记录信息列表
message IssuanceRecords {
repeated ReceiptIssuance records = 1;
}
// 根据ID查询发行信息
message ReqIssuanceInfo {
string issuanceId = 1;
}
// 返回一期发行信息
message RepIssuanceCurrentInfo {
int32 status = 1; //当期发行的状态,是否关闭
int64 totalBalance = 2; //当期发行总金额(ccny)
int64 debtCeiling = 3; //单用户可借出的限额(ccny)
int64 liquidationRatio = 4; //清算比例
int64 balance = 5; //剩余可借贷金额(ccny)
int64 collateralValue = 6; //抵押物总数量(bty)
int64 debtValue = 7; //产生的ccny数量
int64 period = 8; //发行最大期限
string issuId = 9; //发行ID
int64 createTime = 10;//创建时间
}
// 根据ID列表查询多期发行信息
message ReqIssuanceInfos {
repeated string issuanceIds = 1;
}
// 返回多期发行信息
message RepIssuanceCurrentInfos {
repeated RepIssuanceCurrentInfo infos = 1;
}
// 根据发行状态查询
message ReqIssuanceByStatus {
int32 status = 1;
string issuanceId = 2;
}
// 返回发行ID列表
message RepIssuanceIDs {
repeated string IDs = 1;
}
// 根据用户地址查询抵押记录
message ReqIssuanceRecords {
string issuanceId = 1;
string addr = 2;
int32 status = 3;
string debtId = 4;
}
// 返回记录列表
message RepIssuanceRecords {
repeated DebtRecord records = 1;
}
// 返回记录
message RepIssuanceDebtInfo {
DebtRecord record = 1;
}
// 返回最新抵押物价格
message RepIssuancePrice {
int64 price = 1; //当前抵押物最新价格
}
// 返回用户发行总额
message RepIssuanceUserBalance {
int64 balance = 1; //返回用户发行总额
}
\ No newline at end of file
## 发行合约表结构
### 总发行表issuer表结构
字段名称|类型|说明
---|---|---
issuanceId|string|总发行ID,主键
status|int32|发行状态(1:已发行 2:已下线)
### 总发行表issuer表索引
索引名|说明
---|---
status|根据发行状态查询总发行ID
### 大户发行表debt表结构
字段名称|类型|说明
---|---|---
debtId|string|大户发行ID,主键
issuanceId|string|总发行ID
accountAddr|string|用户地址
status|int32|发行状态(1:已发行 2:价格清算告警 3:价格清算 4:超时清算告警 5:超时清算 6:关闭)
### 大户发行表debt表索引
索引名|说明
---|---
status|根据大户发行状态查询大户发行ID
addr|根据大户地址查询大户发行ID
addr_status|根据发行状态和大户地址查询大户发行ID
// 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"
// Errors for lottery
var (
ErrRiskParam = errors.New("ErrRiskParam")
ErrIssuanceRepeatHash = errors.New("ErrIssuanceRepeatHash")
ErrIssuanceStatus = errors.New("ErrIssuanceStatus")
ErrIssuanceExceedDebtCeiling = errors.New("ErrIssuanceExceedDebtCeiling")
ErrPriceInvalid = errors.New("ErrPriceInvalid")
ErrAssetType = errors.New("ErrAssetType")
ErrRecordNotExist = errors.New("ErrRecordNotExist")
ErrIssuanceErrCloser = errors.New("ErrIssuanceErrCloser")
ErrRepayValueInsufficient = errors.New("ErrRepayValueInsufficient")
ErrIssuanceAccountExist = errors.New("ErrIssuanceAccountExist")
ErrIssuanceLowBalance = errors.New("ErrIssuanceLowBalance")
ErrIssuanceBalanceInvalid = errors.New("ErrIssuanceBalanceInvalid")
ErrPermissionDeny = errors.New("ErrPermissionDeny")
ErrIssuanceRecordNotEmpty = errors.New("ErrIssuanceRecordNotEmpty")
)
// 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 (
"encoding/json"
"math"
"reflect"
"github.com/33cn/chain33/common/address"
log "github.com/33cn/chain33/common/log/log15"
"github.com/33cn/chain33/types"
)
var (
llog = log.New("module", "exectype."+IssuanceX)
)
func init() {
types.AllowUserExec = append(types.AllowUserExec, []byte(IssuanceX))
types.RegFork(IssuanceX, InitFork)
types.RegExec(IssuanceX, InitExecutor)
}
func InitFork(cfg *types.Chain33Config) {
cfg.RegisterDappFork(IssuanceX, "Enable", 0)
}
func InitExecutor(cfg *types.Chain33Config) {
types.RegistorExecutor(IssuanceX, NewType(cfg))
}
// IssuanceType def
type IssuanceType struct {
types.ExecTypeBase
}
// NewType method
func NewType(cfg *types.Chain33Config) *IssuanceType {
c := &IssuanceType{}
c.SetChild(c)
c.SetConfig(cfg)
return c
}
// GetName 获取执行器名称
func (issuance *IssuanceType) GetName() string {
return IssuanceX
}
// GetLogMap method
func (issuance *IssuanceType) GetLogMap() map[int64]*types.LogInfo {
return map[int64]*types.LogInfo{
TyLogIssuanceCreate: {Ty: reflect.TypeOf(ReceiptIssuance{}), Name: "LogIssuanceCreate"},
TyLogIssuanceDebt: {Ty: reflect.TypeOf(ReceiptIssuance{}), Name: "LogIssuanceDebt"},
TyLogIssuanceRepay: {Ty: reflect.TypeOf(ReceiptIssuance{}), Name: "LogIssuanceRepay"},
TyLogIssuanceFeed: {Ty: reflect.TypeOf(ReceiptIssuance{}), Name: "LogIssuanceFeed"},
TyLogIssuanceClose: {Ty: reflect.TypeOf(ReceiptIssuance{}), Name: "LogIssuanceClose"},
}
}
// GetPayload method
func (issuance *IssuanceType) GetPayload() types.Message {
return &IssuanceAction{}
}
// CreateTx method
func (issuance IssuanceType) CreateTx(action string, message json.RawMessage) (*types.Transaction, error) {
llog.Debug("Issuance.CreateTx", "action", action)
cfg := issuance.GetConfig()
if action == "IssuanceCreate" {
var param IssuanceCreateTx
err := json.Unmarshal(message, &param)
if err != nil {
llog.Error("CreateTx", "Error", err)
return nil, types.ErrInvalidParam
}
return CreateRawIssuanceCreateTx(cfg, &param)
} else if action == "IssuanceDebt" {
var param IssuanceDebtTx
err := json.Unmarshal(message, &param)
if err != nil {
llog.Error("CreateTx", "Error", err)
return nil, types.ErrInvalidParam
}
return CreateRawIssuanceDebtTx(cfg, &param)
} else if action == "IssuanceRepay" {
var param IssuanceRepayTx
err := json.Unmarshal(message, &param)
if err != nil {
llog.Error("CreateTx", "Error", err)
return nil, types.ErrInvalidParam
}
return CreateRawIssuanceRepayTx(cfg, &param)
} else if action == "IssuancePriceFeed" {
var param IssuanceFeedTx
err := json.Unmarshal(message, &param)
if err != nil {
llog.Error("CreateTx", "Error", err)
return nil, types.ErrInvalidParam
}
return CreateRawIssuanceFeedTx(cfg, &param)
} else if action == "IssuanceClose" {
var param IssuanceCloseTx
err := json.Unmarshal(message, &param)
if err != nil {
llog.Error("CreateTx", "Error", err)
return nil, types.ErrInvalidParam
}
return CreateRawIssuanceCloseTx(cfg, &param)
} else if action == "IssuanceManage" {
var param IssuanceManageTx
err := json.Unmarshal(message, &param)
if err != nil {
llog.Error("CreateTx", "Error", err)
return nil, types.ErrInvalidParam
}
return CreateRawIssuanceManageTx(cfg, &param)
} else {
return nil, types.ErrNotSupport
}
}
// GetTypeMap method
func (issuance IssuanceType) GetTypeMap() map[string]int32 {
return map[string]int32{
"Create": IssuanceActionCreate,
"Debt": IssuanceActionDebt,
"Repay": IssuanceActionRepay,
"Feed": IssuanceActionFeed,
"Close": IssuanceActionClose,
"Manage": IssuanceActionManage,
}
}
// CreateRawIssuanceCreateTx method
func CreateRawIssuanceCreateTx(cfg *types.Chain33Config, parm *IssuanceCreateTx) (*types.Transaction, error) {
if parm == nil {
llog.Error("CreateRawIssuanceCreateTx", "parm", parm)
return nil, types.ErrInvalidParam
}
v := &IssuanceCreate{
TotalBalance: int64(math.Trunc((parm.TotalBalance+0.0000001)*1e4)) * 1e4,
DebtCeiling: int64(math.Trunc((parm.DebtCeiling+0.0000001)*1e4)) * 1e4,
LiquidationRatio: int64(math.Trunc((parm.LiquidationRatio + 0.0000001) * 1e4)),
Period: parm.Period,
}
create := &IssuanceAction{
Ty: IssuanceActionCreate,
Value: &IssuanceAction_Create{v},
}
tx := &types.Transaction{
Execer: []byte(cfg.ExecName(IssuanceX)),
Payload: types.Encode(create),
Fee: parm.Fee,
To: address.ExecAddress(cfg.ExecName(IssuanceX)),
}
name := cfg.ExecName(IssuanceX)
tx, err := types.FormatTx(cfg, name, tx)
if err != nil {
return nil, err
}
return tx, nil
}
// CreateRawIssuanceDebtTx method
func CreateRawIssuanceDebtTx(cfg *types.Chain33Config, parm *IssuanceDebtTx) (*types.Transaction, error) {
if parm == nil {
llog.Error("CreateRawIssuanceBorrowTx", "parm", parm)
return nil, types.ErrInvalidParam
}
v := &IssuanceDebt{
IssuanceId: parm.IssuanceID,
Value: int64(math.Trunc((parm.Value+0.0000001)*1e4)) * 1e4,
}
debt := &IssuanceAction{
Ty: IssuanceActionDebt,
Value: &IssuanceAction_Debt{v},
}
tx := &types.Transaction{
Execer: []byte(cfg.ExecName(IssuanceX)),
Payload: types.Encode(debt),
Fee: parm.Fee,
To: address.ExecAddress(cfg.ExecName(IssuanceX)),
}
name := cfg.ExecName(IssuanceX)
tx, err := types.FormatTx(cfg, name, tx)
if err != nil {
return nil, err
}
return tx, nil
}
// CreateRawIssuanceRepayTx method
func CreateRawIssuanceRepayTx(cfg *types.Chain33Config, parm *IssuanceRepayTx) (*types.Transaction, error) {
if parm == nil {
llog.Error("CreateRawIssuanceRepayTx", "parm", parm)
return nil, types.ErrInvalidParam
}
v := &IssuanceRepay{
IssuanceId: parm.IssuanceID,
DebtId: parm.DebtID,
}
repay := &IssuanceAction{
Ty: IssuanceActionRepay,
Value: &IssuanceAction_Repay{v},
}
tx := &types.Transaction{
Execer: []byte(cfg.ExecName(IssuanceX)),
Payload: types.Encode(repay),
Fee: parm.Fee,
To: address.ExecAddress(cfg.ExecName(IssuanceX)),
}
name := cfg.ExecName(IssuanceX)
tx, err := types.FormatTx(cfg, name, tx)
if err != nil {
return nil, err
}
return tx, nil
}
// CreateRawIssuanceFeedTx method
func CreateRawIssuanceFeedTx(cfg *types.Chain33Config, parm *IssuanceFeedTx) (*types.Transaction, error) {
if parm == nil {
llog.Error("CreateRawIssuancePriceFeedTx", "parm", parm)
return nil, types.ErrInvalidParam
}
v := &IssuanceFeed{
Volume: parm.Volume,
}
for _, r := range parm.Price {
v.Price = append(v.Price, int64(math.Trunc(r*1e4)))
}
feed := &IssuanceAction{
Ty: IssuanceActionFeed,
Value: &IssuanceAction_Feed{v},
}
tx := &types.Transaction{
Execer: []byte(cfg.ExecName(IssuanceX)),
Payload: types.Encode(feed),
Fee: parm.Fee,
To: address.ExecAddress(cfg.ExecName(IssuanceX)),
}
name := cfg.ExecName(IssuanceX)
tx, err := types.FormatTx(cfg, name, tx)
if err != nil {
return nil, err
}
return tx, nil
}
// CreateRawIssuanceCloseTx method
func CreateRawIssuanceCloseTx(cfg *types.Chain33Config, parm *IssuanceCloseTx) (*types.Transaction, error) {
if parm == nil {
llog.Error("CreateRawIssuanceCloseTx", "parm", parm)
return nil, types.ErrInvalidParam
}
v := &IssuanceClose{
IssuanceId: parm.IssuanceID,
}
close := &IssuanceAction{
Ty: IssuanceActionClose,
Value: &IssuanceAction_Close{v},
}
tx := &types.Transaction{
Execer: []byte(cfg.ExecName(IssuanceX)),
Payload: types.Encode(close),
Fee: parm.Fee,
To: address.ExecAddress(cfg.ExecName(IssuanceX)),
}
name := cfg.ExecName(IssuanceX)
tx, err := types.FormatTx(cfg, name, tx)
if err != nil {
return nil, err
}
return tx, nil
}
// CreateRawIssuanceManageTx method
func CreateRawIssuanceManageTx(cfg *types.Chain33Config, parm *IssuanceManageTx) (*types.Transaction, error) {
if parm == nil {
llog.Error("CreateRawIssuanceManageTx", "parm", parm)
return nil, types.ErrInvalidParam
}
v := &IssuanceManage{SuperAddrs: parm.Addr}
manage := &IssuanceAction{
Ty: IssuanceActionManage,
Value: &IssuanceAction_Manage{v},
}
tx := &types.Transaction{
Execer: []byte(cfg.ExecName(IssuanceX)),
Payload: types.Encode(manage),
Fee: parm.Fee,
To: address.ExecAddress(cfg.ExecName(IssuanceX)),
}
name := cfg.ExecName(IssuanceX)
tx, err := types.FormatTx(cfg, name, tx)
if err != nil {
return nil, err
}
return tx, nil
}
This diff is collapsed.
package types
import (
"fmt"
"github.com/33cn/chain33/common/db"
"github.com/33cn/chain33/common/db/table"
"github.com/33cn/chain33/types"
)
var opt = &table.Option{
Prefix: "LODB-issuance",
Name: "issuer",
Primary: "issuanceid",
Index: []string{"status"},
}
//NewTable 新建表
func NewIssuanceTable(kvdb db.KV) *table.Table {
rowmeta := NewIssuanceRow()
table, err := table.NewTable(rowmeta, kvdb, opt)
if err != nil {
panic(err)
}
return table
}
//IssuanceRow table meta 结构
type IssuanceRow struct {
*ReceiptIssuanceID
}
//NewIssuanceRow 新建一个meta 结构
func NewIssuanceRow() *IssuanceRow {
return &IssuanceRow{ReceiptIssuanceID: &ReceiptIssuanceID{}}
}
//CreateRow 新建数据行
func (tx *IssuanceRow) CreateRow() *table.Row {
return &table.Row{Data: &ReceiptIssuanceID{}}
}
//SetPayload 设置数据
func (tx *IssuanceRow) SetPayload(data types.Message) error {
if txdata, ok := data.(*ReceiptIssuanceID); ok {
tx.ReceiptIssuanceID = txdata
return nil
}
return types.ErrTypeAsset
}
//Get 按照indexName 查询 indexValue
func (tx *IssuanceRow) Get(key string) ([]byte, error) {
if key == "issuanceid" {
return []byte(tx.IssuanceId), nil
} else if key == "status" {
return []byte(fmt.Sprintf("%2d", tx.Status)), nil
}
return nil, types.ErrNotFound
}
var optRecord = &table.Option{
Prefix: "LODB-issuance",
Name: "debt",
Primary: "debtid",
Index: []string{"status", "addr", "addr_status"},
}
// NewRecordTable 大户发行记录表
func NewRecordTable(kvdb db.KV) *table.Table {
rowmeta := NewRecordRow()
table, err := table.NewTable(rowmeta, kvdb, optRecord)
if err != nil {
panic(err)
}
return table
}
//IssuanceRow table meta 结构
type IssuanceRecordRow struct {
*ReceiptIssuance
}
//NewIssuanceRow 新建一个meta 结构
func NewRecordRow() *IssuanceRecordRow {
return &IssuanceRecordRow{ReceiptIssuance: &ReceiptIssuance{}}
}
//CreateRow 新建数据行
func (tx *IssuanceRecordRow) CreateRow() *table.Row {
return &table.Row{Data: &ReceiptIssuance{}}
}
//SetPayload 设置数据
func (tx *IssuanceRecordRow) SetPayload(data types.Message) error {
if txdata, ok := data.(*ReceiptIssuance); ok {
tx.ReceiptIssuance = txdata
return nil
}
return types.ErrTypeAsset
}
//Get 按照indexName 查询 indexValue
func (tx *IssuanceRecordRow) Get(key string) ([]byte, error) {
if key == "debtid" {
return []byte(tx.DebtId), nil
} else if key == "status" {
return []byte(fmt.Sprintf("%2d", tx.Status)), nil
} else if key == "addr" {
return []byte(tx.AccountAddr), nil
} else if key == "addr_status" {
return []byte(fmt.Sprintf("%s:%2d", tx.AccountAddr, tx.Status)), nil
}
return nil, types.ErrNotFound
}
// 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
// IssuanceCreateTx for construction
type IssuanceCreateTx struct {
DebtCeiling float64 `json:"debtCeiling"`
LiquidationRatio float64 `json:"liquidationRatio"`
Period int64 `json:"period"`
TotalBalance float64 `json:"totalBalance"`
Fee int64 `json:"fee"`
}
// IssuanceDebtTx for construction
type IssuanceDebtTx struct {
IssuanceID string `json:"issuanceId"`
Value float64 `json:"value"`
Fee int64 `json:"fee"`
}
// IssuanceRepayTx for construction
type IssuanceRepayTx struct {
IssuanceID string `json:"issuanceId"`
DebtID string `json:"debtId"`
Fee int64 `json:"fee"`
}
// IssuanceFeedTx for construction
type IssuanceFeedTx struct {
Price []float64 `json:"price"`
Volume []int64 `json:"volume"`
Fee int64 `json:"fee"`
}
// IssuanceCloseTx for construction
type IssuanceCloseTx struct {
IssuanceID string `json:"issuanceId"`
Fee int64 `json:"fee"`
}
// IssuanceManageTx for construction
type IssuanceManageTx struct {
Addr []string `json:"addr"`
Fee int64 `json:"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 types
//Issuance op
const (
IssuanceActionCreate = 1 + iota // 创建借贷
IssuanceActionDebt // 大户抵押
IssuanceActionRepay // 大户清算
IssuanceActionFeed // 发行合约喂价
IssuanceActionClose // 关闭借贷
IssuanceActionManage // 借贷管理
//log for Issuance
TyLogIssuanceCreate = 741
TyLogIssuanceDebt = 742
TyLogIssuanceRepay = 743
TyLogIssuanceFeed = 745
TyLogIssuanceClose = 746
)
// Issuance name
const (
IssuanceX = "issuance"
CCNYTokenName = "CCNY"
IssuancePreLiquidationRatio = 11000 //TODO 预清算比例,抵押物价值跌到借出ccny价值110%的时候开始清算
)
//Issuance status
const (
IssuanceStatusCreated = 1 + iota
IssuanceStatusClose
)
const (
IssuanceUserStatusCreate = 1 + iota
IssuanceUserStatusWarning
IssuanceUserStatusSystemLiquidate
IssuanceUserStatusExpire
IssuanceUserStatusExpireLiquidate
IssuanceUserStatusClose
)
const (
PriceFeedKey = "issuance-price-feed"
GuarantorKey = "issuance-guarantor"
ManageKey = "issuance-manage"
)
......@@ -61,7 +61,9 @@ function para_set_toml() {
"1GCzJDS6HbgTQ2emade7mEJGGWFfA15pS9",\
"1JYB8sxi4He5pZWHCd3Zi2nypQ4JMB6AxN",\
"12qyocayNF7Lv6C9qW4avxs2E7U41fKSfv",]/g' "${1}"
#autonomy
sed -i $xsedfix 's/^useBalance=.*/useBalance=true/g' "${1}"
sed -i $xsedfix 's/^total="16htvcBNS.*/total="1EZrEKPPC36SLRoLQBwLDjzcheiLRZJg49"/g' "${1}"
}
function para_set_wallet() {
......
// 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 (
"testing"
"github.com/33cn/chain33/types"
"github.com/33cn/chain33/util"
pty "github.com/33cn/plugin/plugin/dapp/privacy/types"
"github.com/stretchr/testify/assert"
)
const (
testStateCheck = iota + 1
testStateExec
testStateExecLocal
testStateExecDelLocal
)
func testExec(mock *testExecMock, tcArr []*testcase, priv string, t *testing.T) {
exec := mock.exec
for i, tc := range tcArr {
signPriv := priv
if tc.priv != "" {
signPriv = tc.priv
}
tx, err := createTx(mock, tc.payload, signPriv, tc.systemCreate)
assert.NoErrorf(t, err, "createTxErr, testIndex=%d", tc.index)
if err != nil {
continue
}
if len(tc.testSign) > 0 {
tx.Signature.Signature = append([]byte(""), tc.testSign...)
}
if tc.testFee > 0 {
tx.Fee = tc.testFee
}
err = exec.CheckTx(tx, i)
assert.Equalf(t, tc.expectCheckErr, err, "checkTx err index %d", tc.index)
if tc.testState == testStateCheck {
continue
}
recp, err := exec.Exec(tx, i)
recpData := &types.ReceiptData{
Ty: recp.GetTy(),
Logs: recp.GetLogs(),
}
if err == nil && len(recp.GetKV()) > 0 {
util.SaveKVList(mock.stateDB, recp.KV)
mock.addBlockTx(tx, recpData)
}
assert.Equalf(t, tc.expectExecErr, err, "execTx err index %d", tc.index)
if tc.testState == testStateExec {
continue
}
kvSet, err := exec.ExecLocal(tx, recpData, i)
for _, kv := range kvSet.GetKV() {
err := mock.localDB.Set(kv.Key, kv.Value)
assert.Nil(t, err)
}
assert.Equalf(t, tc.expectExecLocalErr, err, "execLocalTx err index %d", tc.index)
if tc.testState == testStateExecLocal {
continue
}
kvSet, err = exec.ExecDelLocal(tx, recpData, i)
for _, kv := range kvSet.GetKV() {
err := mock.localDB.Set(kv.Key, kv.Value)
assert.Nil(t, err)
}
assert.Equalf(t, tc.expectExecDelErr, err, "execDelLocalTx err index %d", tc.index)
}
}
func TestPrivacy_CheckTx(t *testing.T) {
mock := &testExecMock{}
mock.InitEnv()
defer mock.FreeEnv()
//用于测试双花
testKeyImage := []byte("testKeyImage")
mock.stateDB.Set(calcPrivacyKeyImageKey("coins", "bty", testKeyImage), []byte("testval"))
tcArr := []*testcase{
{
index: 1,
payload: &pty.Public2Privacy{},
expectCheckErr: types.ErrInvalidParam,
},
{
index: 2,
payload: &pty.Public2Privacy{Tokenname: "bty"},
},
{
index: 4,
payload: &pty.Privacy2Public{Tokenname: "bty", Input: &pty.PrivacyInput{Keyinput: []*pty.KeyInput{}}},
expectCheckErr: pty.ErrNilUtxoInput,
},
{
index: 5,
payload: &pty.Privacy2Privacy{Tokenname: "bty", Input: &pty.PrivacyInput{Keyinput: []*pty.KeyInput{{}}}},
expectCheckErr: pty.ErrNilUtxoOutput,
},
{
index: 6,
payload: &pty.Privacy2Public{Tokenname: "bty", Input: &pty.PrivacyInput{Keyinput: []*pty.KeyInput{{}}}},
expectCheckErr: pty.ErrRingSign,
},
{
index: 7,
payload: &pty.Privacy2Public{Tokenname: "bty", Input: &pty.PrivacyInput{Keyinput: []*pty.KeyInput{{KeyImage: testKeyImage}}}},
expectCheckErr: pty.ErrDoubleSpendOccur,
testSign: types.Encode(&types.RingSignature{Items: []*types.RingSignatureItem{{Pubkey: [][]byte{[]byte("test")}}}}),
},
{
index: 8,
payload: &pty.Privacy2Public{Tokenname: "bty", Input: &pty.PrivacyInput{Keyinput: []*pty.KeyInput{{UtxoGlobalIndex: []*pty.UTXOGlobalIndex{{}}}}}},
expectCheckErr: pty.ErrPubkeysOfUTXO,
testSign: types.Encode(&types.RingSignature{Items: []*types.RingSignatureItem{{Pubkey: [][]byte{[]byte("test")}}}}),
},
{
index: 9,
payload: &pty.Privacy2Public{Tokenname: "bty", Input: &pty.PrivacyInput{Keyinput: []*pty.KeyInput{{}}}},
expectCheckErr: pty.ErrPrivacyTxFeeNotEnough,
testSign: types.Encode(&types.RingSignature{Items: []*types.RingSignatureItem{{Pubkey: [][]byte{[]byte("test")}}}}),
},
{
index: 10,
payload: &pty.Privacy2Public{Tokenname: "bty", Input: &pty.PrivacyInput{Keyinput: []*pty.KeyInput{{}}}},
expectCheckErr: pty.ErrPrivacyTxFeeNotEnough,
testSign: types.Encode(&types.RingSignature{Items: []*types.RingSignatureItem{{Pubkey: [][]byte{[]byte("test")}}}}),
testFee: pty.PrivacyTxFee,
},
}
for _, tc := range tcArr {
tc.systemCreate = true
tc.testState = testStateCheck
}
testExec(mock, tcArr, testPrivateKeys[0], t)
}
func TestPrivacy_Exec_Public2Privacy(t *testing.T) {
mock := &testExecMock{}
mock.InitEnv()
defer mock.FreeEnv()
tcArr := []*testcase{
{
index: 1,
payload: &pty.ReqCreatePrivacyTx{
AssetExec: "btc-coins",
Tokenname: "btc",
Amount: types.Coin,
Pubkeypair: testPubkeyPairs[0],
},
expectExecErr: types.ErrExecNameNotAllow,
},
{
index: 2,
payload: &pty.ReqCreatePrivacyTx{
Amount: types.Coin * 10001,
Pubkeypair: testPubkeyPairs[0],
},
expectExecErr: types.ErrNoBalance,
},
{
index: 2,
payload: &pty.ReqCreatePrivacyTx{
Amount: types.Coin,
Pubkeypair: testPubkeyPairs[0],
},
},
}
for _, tc := range tcArr {
req := tc.payload.(*pty.ReqCreatePrivacyTx)
req.Type = types.PrivacyTypePublic2Privacy
tc.testState = testStateExec
}
testExec(mock, tcArr, testPrivateKeys[0], t)
}
func TestPrivacy_Exec_Privacy2Privacy(t *testing.T) {
mock := &testExecMock{}
mock.InitEnv()
defer mock.FreeEnv()
tcArr := []*testcase{
{
index: 1,
payload: &pty.ReqCreatePrivacyTx{
Type: types.PrivacyTypePublic2Privacy,
Amount: types.Coin * 9,
Pubkeypair: testPubkeyPairs[0],
},
},
{
index: 2,
payload: &pty.ReqCreatePrivacyTx{
Amount: types.Coin,
Pubkeypair: testPubkeyPairs[1],
From: testAddrs[0],
},
},
}
for _, tc := range tcArr {
req := tc.payload.(*pty.ReqCreatePrivacyTx)
if req.Type == 0 {
req.Type = types.PrivacyTypePrivacy2Privacy
}
tc.testState = testStateExec
}
testExec(mock, tcArr, testPrivateKeys[0], t)
}
func TestPrivacy_Exec_Privacy2Public(t *testing.T) {
mock := &testExecMock{}
mock.InitEnv()
defer mock.FreeEnv()
tcArr := []*testcase{
{
index: 1,
payload: &pty.ReqCreatePrivacyTx{
Type: types.PrivacyTypePublic2Privacy,
Amount: types.Coin * 9,
Pubkeypair: testPubkeyPairs[0],
},
},
{
index: 2,
payload: &pty.ReqCreatePrivacyTx{
Amount: types.Coin,
Pubkeypair: testPubkeyPairs[1],
From: testAddrs[0],
To: testAddrs[1],
},
},
}
for _, tc := range tcArr {
req := tc.payload.(*pty.ReqCreatePrivacyTx)
if req.Type == 0 {
req.Type = types.PrivacyTypePrivacy2Public
}
tc.testState = testStateExec
}
testExec(mock, tcArr, testPrivateKeys[0], t)
}
func TestPrivacy_ExecLocal(t *testing.T) {
mock := &testExecMock{}
mock.InitEnv()
defer mock.FreeEnv()
tcArr := []*testcase{
{
index: 1,
payload: &pty.ReqCreatePrivacyTx{
Type: types.PrivacyTypePublic2Privacy,
Amount: types.Coin * 9,
Pubkeypair: testPubkeyPairs[0],
},
},
{
index: 2,
payload: &pty.ReqCreatePrivacyTx{
Type: types.PrivacyTypePrivacy2Privacy,
Amount: types.Coin,
Pubkeypair: testPubkeyPairs[1],
From: testAddrs[0],
},
},
{
index: 3,
payload: &pty.ReqCreatePrivacyTx{
Type: types.PrivacyTypePrivacy2Public,
Amount: types.Coin,
Pubkeypair: testPubkeyPairs[1],
From: testAddrs[0],
To: testAddrs[1],
},
},
}
for _, tc := range tcArr {
tc.testState = testStateExecLocal
}
testExec(mock, tcArr, testPrivateKeys[0], t)
}
func TestPrivacy_ExecDelLocal(t *testing.T) {
mock := &testExecMock{}
mock.InitEnv()
defer mock.FreeEnv()
tcArr := []*testcase{
{
index: 1,
payload: &pty.ReqCreatePrivacyTx{
Type: types.PrivacyTypePublic2Privacy,
Amount: types.Coin * 9,
Pubkeypair: testPubkeyPairs[0],
},
},
{
index: 2,
payload: &pty.ReqCreatePrivacyTx{
Type: types.PrivacyTypePrivacy2Privacy,
Amount: types.Coin,
Pubkeypair: testPubkeyPairs[1],
From: testAddrs[0],
},
},
{
index: 3,
payload: &pty.ReqCreatePrivacyTx{
Type: types.PrivacyTypePrivacy2Public,
Amount: types.Coin,
Pubkeypair: testPubkeyPairs[1],
From: testAddrs[0],
To: testAddrs[1],
},
},
}
for _, tc := range tcArr {
tc.testState = testStateExecDelLocal
}
testExec(mock, tcArr, testPrivateKeys[0], t)
}
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