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=
......
......@@ -6,21 +6,18 @@ package raft
import (
"context"
"encoding/json"
"fmt"
"sync"
"time"
"github.com/33cn/chain33/common"
"github.com/33cn/chain33/common/merkle"
"github.com/33cn/chain33/queue"
drivers "github.com/33cn/chain33/system/consensus"
cty "github.com/33cn/chain33/system/dapp/coins/types"
"github.com/33cn/chain33/types"
"github.com/coreos/etcd/snap"
"github.com/golang/protobuf/proto"
)
var (
zeroHash [32]byte
)
func init() {
......@@ -31,18 +28,20 @@ func init() {
// Client Raft implementation
type Client struct {
*drivers.BaseClient
proposeC chan<- *types.Block
commitC <-chan *types.Block
proposeC chan<- BlockInfo
commitC <-chan *BlockInfo
errorC <-chan error
snapshotter *snap.Snapshotter
validatorC <-chan bool
ctx context.Context
cancel context.CancelFunc
once sync.Once
blockInfo *BlockInfo
mtx sync.Mutex
}
// NewBlockstore create Raft Client
func NewBlockstore(ctx context.Context, cfg *types.Consensus, snapshotter *snap.Snapshotter, proposeC chan<- *types.Block, commitC <-chan *types.Block, errorC <-chan error, validatorC <-chan bool, cancel context.CancelFunc) *Client {
func NewBlockstore(ctx context.Context, cfg *types.Consensus, snapshotter *snap.Snapshotter, proposeC chan<- BlockInfo, commitC <-chan *BlockInfo, errorC <-chan error, validatorC <-chan bool, cancel context.CancelFunc) *Client {
c := drivers.NewBaseClient(cfg)
client := &Client{BaseClient: c, proposeC: proposeC, snapshotter: snapshotter, validatorC: validatorC, commitC: commitC, errorC: errorC, ctx: ctx, cancel: cancel}
c.SetChild(client)
......@@ -75,20 +74,23 @@ func (client *Client) ProcEvent(msg *queue.Message) bool {
// CheckBlock method
func (client *Client) CheckBlock(parent *types.Block, current *types.BlockDetail) error {
cfg := client.GetAPI().GetConfig()
if current.Block.Difficulty != cfg.GetP(0).PowLimitBits {
return types.ErrBlockHeaderDifficulty
}
return nil
}
func (client *Client) getSnapshot() ([]byte, error) {
//这里可能导致死锁
return proto.Marshal(client.GetCurrentBlock())
return json.Marshal(client.GetCurrentInfo())
}
func (client *Client) recoverFromSnapshot(snapshot []byte) error {
var block types.Block
if err := proto.Unmarshal(snapshot, &block); err != nil {
var info *BlockInfo
if err := json.Unmarshal(snapshot, info); err != nil {
return err
}
client.SetCurrentBlock(&block)
client.SetCurrentInfo(info)
return nil
}
......@@ -110,10 +112,8 @@ func (client *Client) Close() {
// CreateBlock method
func (client *Client) CreateBlock() {
issleep := true
retry := 0
infoflag := 0
count := 0
count := int64(0)
cfg := client.GetAPI().GetConfig()
//打包区块前先同步到最大高度
for {
......@@ -124,62 +124,59 @@ func (client *Client) CreateBlock() {
time.Sleep(time.Second)
retry++
if retry >= 600 {
panic("This node encounter problem, exit.")
panic("Leader encounter problem, exit.")
}
}
ticker := time.NewTicker(50 * time.Millisecond)
curBlock, err := client.RequestLastBlock()
if err != nil {
rlog.Error("Leader RequestLastBlock fail", "err", err)
panic(err)
}
curInfo := &BlockInfo{
Height: curBlock.Height,
Hash: common.ToHex(curBlock.Hash(cfg)),
}
client.SetCurrentInfo(curInfo)
ticker := time.NewTicker(time.Duration(writeBlockSeconds) * time.Second)
hint := time.NewTicker(30 * time.Second)
defer ticker.Stop()
defer hint.Stop()
for {
select {
case <-client.ctx.Done():
return
case <-hint.C:
rlog.Info("==================This is Leader node=====================")
case <-ticker.C:
//如果leader节点突然挂了,不是打包节点,需要退出
if !mux.Load().(bool) {
rlog.Warn("I'm not the validator node anymore, exit.=============================")
break
}
infoflag++
if infoflag >= 3 {
rlog.Info("==================This is Leader node=====================")
infoflag = 0
rlog.Warn("Not the Leader node anymore")
return
}
if issleep {
time.Sleep(10 * time.Second)
count++
}
if count >= 12 {
rlog.Info("Create an empty block")
block := client.GetCurrentBlock()
emptyBlock := &types.Block{}
emptyBlock.StateHash = block.StateHash
emptyBlock.ParentHash = block.Hash(cfg)
emptyBlock.Height = block.Height + 1
emptyBlock.Txs = nil
emptyBlock.TxHash = zeroHash[:]
emptyBlock.BlockTime = types.Now().Unix()
entry := emptyBlock
client.propose(entry)
er := client.WriteBlock(block.StateHash, emptyBlock)
if er != nil {
rlog.Error(fmt.Sprintf("********************err:%v", er.Error()))
continue
}
client.SetCurrentBlock(emptyBlock)
count = 0
lastBlock, err := client.RequestLastBlock()
if err != nil {
rlog.Error("Leader RequestLastBlock fail", "err", err)
break
}
if client.GetCurrentInfoHeight() != lastBlock.Height {
rlog.Info("Leader wait commit blockInfo", "infoHeight", client.GetCurrentInfoHeight(),
"blockHeight", lastBlock.Height)
break
}
lastBlock := client.GetCurrentBlock()
txs := client.RequestTx(int(cfg.GetP(lastBlock.Height+1).MaxTxNumber), nil)
if len(txs) == 0 {
issleep = true
continue
count++
//not create empty block when emptyBlockInterval is 0
if emptyBlockInterval == 0 || count < emptyBlockInterval/writeBlockSeconds {
break
}
//create empty block every no tx in emptyBlockInterval seconds
rlog.Info("Leader create empty block")
}
issleep = false
count = 0
rlog.Debug("==================start create new block!=====================")
var newblock types.Block
newblock.ParentHash = lastBlock.Hash(cfg)
newblock.Height = lastBlock.Height + 1
......@@ -189,32 +186,37 @@ func (client *Client) CreateBlock() {
newblock.Txs = types.TransactionSort(newblock.Txs)
}
newblock.TxHash = merkle.CalcMerkleRoot(cfg, newblock.Height, newblock.Txs)
//固定难度
newblock.Difficulty = cfg.GetP(0).PowLimitBits
newblock.BlockTime = types.Now().Unix()
if lastBlock.BlockTime >= newblock.BlockTime {
newblock.BlockTime = lastBlock.BlockTime + 1
}
blockEntry := newblock
client.propose(&blockEntry)
err := client.WriteBlock(lastBlock.StateHash, &newblock)
err = client.WriteBlock(lastBlock.StateHash, &newblock)
if err != nil {
issleep = true
rlog.Error(fmt.Sprintf("********************err:%v", err.Error()))
continue
rlog.Error("Leader WriteBlock fail", "err", err)
break
}
time.Sleep(time.Second * time.Duration(writeBlockSeconds))
info := BlockInfo{
Height: newblock.Height,
Hash: common.ToHex(newblock.Hash(cfg)),
}
client.propose(info)
count = 0
}
}
}
// 向raft底层发送block
func (client *Client) propose(block *types.Block) {
client.proposeC <- block.Clone()
// 向raft底层发送BlockInfo
func (client *Client) propose(info BlockInfo) {
client.proposeC <- info
}
// 从receive channel中读leader发来的block
func (client *Client) readCommits(commitC <-chan *types.Block, errorC <-chan error) {
var data *types.Block
func (client *Client) readCommits(commitC <-chan *BlockInfo, errorC <-chan error) {
var data *BlockInfo
var ok bool
for {
select {
......@@ -222,10 +224,8 @@ func (client *Client) readCommits(commitC <-chan *types.Block, errorC <-chan err
if !ok || data == nil {
continue
}
rlog.Debug("===============Get block from commit channel===========")
// 在程序刚开始启动的时候有可能存在丢失数据的问题
//区块高度统一由base中的相关代码进行变更,防止错误区块出现
//client.SetCurrentBlock(data)
rlog.Info("Commit blockInfo", "height", data.Height, "blockhash", data.Hash)
client.SetCurrentInfo(data)
case err, ok := <-errorC:
if ok {
......@@ -239,9 +239,6 @@ func (client *Client) readCommits(commitC <-chan *types.Block, errorC <-chan err
//轮询任务,去检测本机器是否为validator节点,如果是,则执行打包任务
func (client *Client) pollingTask() {
ticker := time.NewTicker(100 * time.Millisecond)
defer ticker.Stop()
for {
select {
case <-client.ctx.Done():
......@@ -252,7 +249,7 @@ func (client *Client) pollingTask() {
client.InitBlock()
})
if ok && !value {
rlog.Debug("================I'm not the validator node!=============")
rlog.Debug("================I'm not the validator node=============")
leader := mux.Load().(bool)
if leader {
isLeader = false
......@@ -265,8 +262,6 @@ func (client *Client) pollingTask() {
} else if !ok {
break
}
case <-ticker.C:
rlog.Debug("Gets the leader node information timeout and triggers the ticker.")
}
}
}
......@@ -275,3 +270,60 @@ func (client *Client) pollingTask() {
func (client *Client) CmpBestBlock(newBlock *types.Block, cmpBlock *types.Block) bool {
return false
}
// BlockInfo struct
type BlockInfo struct {
Height int64 `json:"height"`
Hash string `json:"hash"`
}
// SetCurrentInfo ...
func (client *Client) SetCurrentInfo(info *BlockInfo) {
client.mtx.Lock()
defer client.mtx.Unlock()
client.blockInfo = info
}
// GetCurrentInfo ...
func (client *Client) GetCurrentInfo() *BlockInfo {
client.mtx.Lock()
defer client.mtx.Unlock()
return client.blockInfo
}
// GetCurrentInfoHeight ...
func (client *Client) GetCurrentInfoHeight() int64 {
client.mtx.Lock()
defer client.mtx.Unlock()
return client.blockInfo.Height
}
// CheckBlockInfo check corresponding block
func (client *Client) CheckBlockInfo(info *BlockInfo) bool {
retry := 0
factor := 1
for {
lastBlock, err := client.RequestLastBlock()
if err == nil && lastBlock.Height >= info.Height {
break
}
retry++
time.Sleep(500 * time.Millisecond)
if retry >= 30*factor {
rlog.Info(fmt.Sprintf("CheckBlockInfo wait %d seconds", retry/2), "height", info.Height)
factor = factor * 2
}
}
block, err := client.RequestBlock(info.Height)
if err != nil {
rlog.Error("CheckBlockInfo RequestBlock fail", "err", err)
return false
}
cfg := client.GetAPI().GetConfig()
if common.ToHex(block.Hash(cfg)) != info.Hash {
rlog.Error("CheckBlockInfo hash not equal", "blockHash", common.ToHex(block.Hash(cfg)),
"infoHash", info.Hash)
return false
}
return true
}
......@@ -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() {}
......@@ -3,17 +3,429 @@
# shellcheck source=/dev/null
source ../dapp-test-common.sh
MAIN_HTTP=""
HTTP=""
EXECTOR=""
EXECTOR_ADDR=""
TICKET_EXECTOR=""
TICKET_ADDR=""
propKey="0xfd0c4a8a1efcd221ee0f36b7d4f57d8ff843cb8bc193b39c7863332d355acafa"
propAddr="15VUiygdxMSZ3rykwe742yomp2cPJ9Tfve"
votePrKey="1c3e6cac2f887e1ab9180e2d5772dc4ba01accb8d4df434faba097003eb35482"
voteAddr="1Q9sQwothzM1gKSzkVZ8Dt1tqKX1uzSagx"
proposalID=""
boardsAddr=(
"1N578zmVzVR7RxLfnp7XAeDmAy499Jw3q2"
"1DZ1kL9x3rRwz7EZjcLt1kMYu6Zdp3MjGR"
"1HUYR1Mzb91m3dmsEE1vPrv7BsAHmEtVzM"
"1JHmVgchSLjszN9LAYa3gds811c4BH2J51"
"14TDcn95hxHbpySPtxGDK3aY6qDNuk5idg"
"1EpbYadEAcwbrxuh6Ph2qyJZhMY9F9CCCv"
"1NqfXb3YotDTPuShgSAhrBH28ETzCrsZx2"
"138xSezQUi9kynnAZR23kWBwHvDSRX8JDK"
"18bncBidkwRaUYPaqa9Rc58tWeRT2C5tfL"
"16z3gEvRGof8cnQRvicV8BdY54fUfnBo8A"
"1DpzRWk9SYnEvuGrFsJPFvMVRSYRHaCbtU"
"1JSQbsb1hfB6CLzwzVZZEtai4da8m59obK"
"12bRYKMsLSbN5upxoSenypWrygVuQh8rM5"
"1Ew4Cpcfh1u1EeRkYPwVc4PRaSnz4D2eph"
"156yPWN3eeZ4yPiwHRifu41FmrTVPavXQ5"
"192YKhdAkFm18KLcGumM8JeDgWrnpSdo93"
"12kXgBxsKzUmhfX5Mnv9EKRNGjQXhZzDFd"
"1HmyNGYj2xyMmQDTpcuheLKXKBe5rj3QpQ"
"1HGPrjc6H7yBzFV5yCbibvnSUGUgdDNQi3"
"19WGov4b7wLf4f8JHMRDnJsGVNMDzap38w"
"1HmRa1jAnzJ5SpJRrUWqUki6hx1u33Nbq4"
)
boardsPrKey=(
"fa54751118c8159ade22c253f85945a4dd2030b1cf2502eaf785d0a4f5ad7e35"
"da9371ea52f1fc9d72e75dbc9836774895cd0966fd53c83f5e2c92d878903693"
"ad9731261c40c68fee96f7b846408fa33d1f3dc2a27bdb3694ec8f3aa153a98b"
"e902d23ad26052cec64e9ed9055853327787b3bf26eb4646a6d6c1bb516f9fcd"
"b3af59368bcc6779aecb4e7fbf0cc4040f8f8329eb7632d580be4b6d3be15357"
"fd9284c11707b571e347b8f44c54aae89c0810d410a7c1f9613326358c564a5e"
"b013948c123986aadc2525bfe9935dd07972e14b250b938153e763f917ada8d3"
"5641e3aba9ce0660665cd1a816d1b50267b5bc5f337f73e6ceed0cc5ececa7d2"
"5a7631b7101252d685bf2b4ba2f11a72fb867faeaa545064ce8d0901ffc3cb17"
"c9d0d2639c0c0f2b275e5bf8a2797122af110316a4e8e1fe03c39693f5028c93"
"00b4e3ac1365b89d68c8d5b07b3505cd614408b0d9c8c88df564d4e072deb401"
"aa139d3f16c1785b2a9171d7863bc4ee9d45115cc0fa71a14c43536c933d1659"
"33f111573a4613477f8291928a9bae012a74fc9858acb22c9c65ecf7844b63f2"
"44e43dd0f769bb99638b9cc3c7468225ff703f69c17e9c4751d04e45fdc6c4a0"
"9a75d6c779846fe2ad4a36021fe9d08652ca69ce09ab39ad874d921a5ec41716"
"f5ca6b2ad545bd4b854871b18c8d37d2fe8c3625e91be86a204c4086f28e8d0f"
"89504608a03590e5a4d8c1c82b75e908b28f9963587c85b96b628d238d3a4d1a"
"fa653545ae52403665fb803ef410c4d3d7f74628b6d3f92218968ad496e4f81b"
"227df96a414e26e85c7d87a12296344e6a731ce73e424ba9845cb305ec963843"
"64259075bf2e5a74334442f5048ceaf8427f6097e2dac99c0e463785c7768550"
"3b812d92b5c365d698255f55c3f0dca027c2f89f2409c51a6297bcf3343c11e6"
)
boards='
"'${boardsAddr[0]}'",
"'${boardsAddr[1]}'",
"'${boardsAddr[2]}'",
"'${boardsAddr[3]}'",
"'${boardsAddr[4]}'",
"'${boardsAddr[5]}'",
"'${boardsAddr[6]}'",
"'${boardsAddr[7]}'",
"'${boardsAddr[8]}'",
"'${boardsAddr[9]}'",
"'${boardsAddr[10]}'",
"'${boardsAddr[11]}'",
"'${boardsAddr[12]}'",
"'${boardsAddr[13]}'",
"'${boardsAddr[14]}'",
"'${boardsAddr[15]}'",
"'${boardsAddr[16]}'",
"'${boardsAddr[17]}'",
"'${boardsAddr[18]}'",
"'${boardsAddr[19]}'",
"'${boardsAddr[20]}'"
'
chain33_para_init() {
ip=$1
chain33_ImportPrivkey "${votePrKey}" "${voteAddr}" "autonomytest" "${ip}"
chain33_SendToAddress "12qyocayNF7Lv6C9qW4avxs2E7U41fKSfv" "$voteAddr" 630000000000 "${ip}"
}
chain33_applyCoinsNOLimit() {
echo "chain33_getMainChainCoins"
if [ "$#" -lt 3 ]; then
echo "chain33_getMainCoins wrong params"
exit 1
fi
local targetAddr=$1
local count=$2
local ip=$3
local poolAddr="1PcGKYYoLn1PLLJJodc1UpgWGeFAQasAkx"
chain33_SendToAddress "${poolAddr}" "${targetAddr}" "$count" "${ip}"
}
handleBoards() {
local ip=$1
for ((i = 0; i < ${#boardsPrKey[*]}; i++)); do
echo "${boardsPrKey[$i]}"
lab="board_"${i}
chain33_ImportPrivkey "${boardsPrKey[$i]}" "${boardsAddr[$i]}" "${lab}" "${ip}"
chain33_applyCoins "${boardsAddr[$i]}" 100000000 "${ip}"
done
}
proposalBoardTx() {
local start=$1
local end=$2
local req='{"method":"Chain33.CreateTransaction","params":[{"execer":"'"${EXECTOR}"'", "actionName":"PropBoard", "payload":{"boards": ['"${boards}"'],"startBlockHeight":'"${start}"',"endBlockHeight":'"${end}"'}}]}'
echo "${req}"
chain33_Http "$req" ${HTTP} '(.error|not) and (.result != null)' "$FUNCNAME" ".result"
chain33_SignAndSendTx "${RETURN_RESP}" "${propKey}" "${HTTP}"
proposalID=$RAW_TX_HASH
echo "$proposalID"
echo_rst "proposalBoard query_tx" "$?"
}
voteBoardTx() {
local ID=$1
local privk=$2
local req='{"method":"Chain33.CreateTransaction","params":[{"execer":"'"${EXECTOR}"'", "actionName":"VotePropBoard", "payload":{"proposalID": "'"${ID}"'","approve": true}}]}'
echo "${req}"
chain33_Http "$req" ${HTTP} '(.error|not) and (.result != null)' "$FUNCNAME" ".result"
chain33_SignAndSendTx "${RETURN_RESP}" "${privk}" "${HTTP}"
echo "$RAW_TX_HASH"
echo_rst "voteBoard query_tx" "$?"
}
revokeProposalTx() {
local ID=$1
local funcName=$2
local req='{"method":"Chain33.CreateTransaction","params":[{"execer":"'"${EXECTOR}"'", "actionName":"'"${funcName}"'", "payload":{"proposalID": "'"${ID}"'"}}]}'
echo "${req}"
chain33_Http "$req" ${HTTP} '(.error|not) and (.result != null)' "$FUNCNAME" ".result"
chain33_SignAndSendTx "${RETURN_RESP}" "${propKey}" "${HTTP}"
echo "$RAW_TX_HASH"
echo_rst "revoke Proposal $funcName query_tx" "$?"
}
terminateProposalTx() {
local ID=$1
local funcName=$2
local req='{"method":"Chain33.CreateTransaction","params":[{"execer":"'"${EXECTOR}"'", "actionName":"'"${funcName}"'", "payload":{"proposalID": "'"${ID}"'"}}]}'
echo "${req}"
chain33_Http "$req" ${HTTP} '(.error|not) and (.result != null)' "$FUNCNAME" ".result"
chain33_SignAndSendTx "${RETURN_RESP}" "${propKey}" "${HTTP}"
echo "$RAW_TX_HASH"
echo_rst "terminate Proposal $funcName query_tx" "$?"
}
queryProposal() {
local ID=$1
local funcName=$2
local req='{"method":"Chain33.Query","params":[{"execer":"'"${EXECTOR}"'","funcName":"'"${funcName}"'","payload":{"data":"'"${ID}"'"}}]}'
resok='(.error|not)'
chain33_Http "$req" ${HTTP} "$resok" "$FUNCNAME"
}
listProposal() {
local status=$1
local funcName=$2
local addr=""
local direct=0
local req='{"method":"Chain33.Query","params":[{"execer":"'"${EXECTOR}"'","funcName":"'"${funcName}"'","payload":{"status":"'"${status}"'", "addr":"'"${addr}"'", "count":1, "direction":"'"${direct}"'"}}]}'
resok='(.error|not)'
chain33_Http "$req" ${HTTP} "$resok" "$FUNCNAME"
}
queryActivePropBoard() {
local req='{"method":"Chain33.Query","params":[{"execer":"'"${EXECTOR}"'","funcName":"GetActiveBoard","payload":{"data":"1"}}]}'
resok='(.error|not)'
chain33_Http "$req" ${HTTP} "$resok" "$FUNCNAME"
}
testProposalBoard() {
#proposal
chain33_LastBlockHeight ${HTTP}
start=$((LAST_BLOCK_HEIGHT + 10))
end=$((start + 20 + 720))
proposalBoardTx ${start} ${end}
#vote
chain33_BlockWait 10 "$HTTP"
voteBoardTx "${proposalID}" "${votePrKey}"
#query
queryProposal "${proposalID}" "GetProposalBoard"
listProposal 4 "ListProposalBoard"
queryActivePropBoard
#test revoke
chain33_LastBlockHeight ${HTTP}
start=$((LAST_BLOCK_HEIGHT + 100))
end=$((start + 120 + 720))
proposalBoardTx ${start} ${end}
revokeProposalTx "${proposalID}" "RvkPropBoard"
terminateProposalTx "${proposalID}" "TmintPropBoard"
queryProposal "${proposalID}" "GetProposalBoard"
listProposal 2 "ListProposalBoard"
}
proposalRuleTx() {
local start=$1
local end=$2
local propAmount=$3
local req='{"method":"Chain33.CreateTransaction","params":[{"execer":"'"${EXECTOR}"'", "actionName":"PropRule", "payload":{"ruleCfg": {"proposalAmount" : '"${propAmount}"'},"startBlockHeight":'"${start}"',"endBlockHeight":'"${end}"'}}]}'
echo "${req}"
chain33_Http "$req" ${HTTP} '(.error|not) and (.result != null)' "$FUNCNAME" ".result"
chain33_SignAndSendTx "${RETURN_RESP}" "${propKey}" "${HTTP}"
proposalID=$RAW_TX_HASH
echo "$proposalID"
echo_rst "proposalRule query_tx" "$?"
}
voteRuleTx() {
local ID=$1
local privk=$2
local req='{"method":"Chain33.CreateTransaction","params":[{"execer":"'"${EXECTOR}"'", "actionName":"VotePropRule", "payload":{"proposalID": "'"${ID}"'","approve": true}}]}'
echo "${req}"
chain33_Http "$req" ${HTTP} '(.error|not) and (.result != null)' "$FUNCNAME" ".result"
chain33_SignAndSendTx "${RETURN_RESP}" "${privk}" "${HTTP}"
echo "$RAW_TX_HASH"
echo_rst "voteRule query_tx" "$?"
}
queryActivePropRule() {
local req='{"method":"Chain33.Query","params":[{"execer":"'"${EXECTOR}"'","funcName":"GetActiveRule","payload":{"data":"1"}}]}'
resok='(.error|not)'
chain33_Http "$req" ${HTTP} "$resok" "$FUNCNAME"
}
testProposalRule() {
# proposal
chain33_LastBlockHeight ${HTTP}
start=$((LAST_BLOCK_HEIGHT + 10))
end=$((start + 20 + 720))
proposalRuleTx ${start} ${end} 2000000000
#vote
chain33_BlockWait 10 "$HTTP"
voteRuleTx "${proposalID}" ${votePrKey}
#query
queryProposal "${proposalID}" "GetProposalRule"
listProposal 4 "ListProposalRule"
queryActivePropRule
#test revoke
chain33_LastBlockHeight ${HTTP}
start=$((LAST_BLOCK_HEIGHT + 100))
end=$((start + 120 + 720))
proposalRuleTx ${start} ${end} 2000000000
revokeProposalTx "${proposalID}" "RvkPropRule"
terminateProposalTx "${proposalID}" "TmintPropRule"
queryProposal "${proposalID}" "GetProposalRule"
listProposal 2 "ListProposalRule"
}
proposalProjectTx() {
local start=$1
local end=$2
local amount=$3
local toAddr=$4
local req='{"method":"Chain33.CreateTransaction","params":[{"execer":"'"${EXECTOR}"'", "actionName":"PropProject", "payload":{"amount" : '"${amount}"', "toAddr" : "'"${toAddr}"'","startBlockHeight":'"${start}"',"endBlockHeight":'"${end}"'}}]}'
echo "${req}"
chain33_Http "$req" ${HTTP} '(.error|not) and (.result != null)' "$FUNCNAME" ".result"
chain33_SignAndSendTx "${RETURN_RESP}" "${propKey}" "${HTTP}"
proposalID=$RAW_TX_HASH
echo "$proposalID"
echo_rst "proposalRule query_tx" "$?"
}
voteProjectTx() {
local ID=$1
local privk=$2
local req='{"method":"Chain33.CreateTransaction","params":[{"execer":"'"${EXECTOR}"'", "actionName":"VotePropProject", "payload":{"proposalID": "'"${ID}"'","approve": true}}]}'
echo "${req}"
chain33_Http "$req" ${HTTP} '(.error|not) and (.result != null)' "$FUNCNAME" ".result"
chain33_SignAndSendTx "${RETURN_RESP}" "${privk}" "${HTTP}"
echo "$RAW_TX_HASH"
echo_rst "voteRule query_tx" "$?"
}
testProposalProject() {
# proposal
chain33_LastBlockHeight ${HTTP}
start=$((LAST_BLOCK_HEIGHT + 10))
end=$((start + 20 + 720))
proposalProjectTx ${start} ${end} 100000000 ${propAddr}
chain33_BlockWait 10 "$HTTP"
#vote
for ((i = 0; i < 11; i++)); do
voteProjectTx "${proposalID}" "${boardsPrKey[$i]}"
done
#query
queryProposal "${proposalID}" "GetProposalProject"
listProposal 5 "ListProposalProject"
#test revoke
chain33_LastBlockHeight ${HTTP}
start=$((LAST_BLOCK_HEIGHT + 100))
end=$((start + 120 + 720))
proposalProjectTx ${start} ${end} 100000000 ${propAddr}
revokeProposalTx "${proposalID}" "RvkPropProject"
terminateProposalTx "${proposalID}" "TmintPropProject"
queryProposal "${proposalID}" "GetProposalProject"
listProposal 2 "ListProposalProject"
}
proposalChangeTx() {
local start=$1
local end=$2
local addr=$3
local cancel=$4
local req='{"method":"Chain33.CreateTransaction","params":[{"execer":"'"${EXECTOR}"'", "actionName":"PropChange", "payload":{"changes" : [{"cancel": '"${cancel}"', "addr":"'"${addr}"'"}],"startBlockHeight":'"${start}"',"endBlockHeight":'"${end}"'}}]}'
echo "${req}"
chain33_Http "$req" ${HTTP} '(.error|not) and (.result != null)' "$FUNCNAME" ".result"
chain33_SignAndSendTx "${RETURN_RESP}" "${propKey}" "${HTTP}"
proposalID=$RAW_TX_HASH
echo "$proposalID"
echo_rst "proposalChange query_tx" "$?"
}
voteChangeTx() {
local ID=$1
local privk=$2
local req='{"method":"Chain33.CreateTransaction","params":[{"execer":"'"${EXECTOR}"'", "actionName":"VotePropChange", "payload":{"proposalID": "'"${ID}"'","approve": true}}]}'
echo "${req}"
chain33_Http "$req" ${HTTP} '(.error|not) and (.result != null)' "$FUNCNAME" ".result"
chain33_SignAndSendTx "${RETURN_RESP}" "${privk}" "${HTTP}"
echo "$RAW_TX_HASH"
echo_rst "voteRule query_tx" "$?"
}
testProposalChange() {
# proposal
chain33_LastBlockHeight ${HTTP}
start=$((LAST_BLOCK_HEIGHT + 10))
end=$((start + 20 + 720))
proposalChangeTx ${start} ${end} "${boardsAddr[20]}" true
chain33_BlockWait 10 "$HTTP"
#vote
for ((i = 0; i < 14; i++)); do
voteChangeTx "${proposalID}" "${boardsPrKey[$i]}"
done
#query
queryProposal "${proposalID}" "GetProposalChange"
listProposal 4 "ListProposalChange"
#test revoke
chain33_LastBlockHeight ${HTTP}
start=$((LAST_BLOCK_HEIGHT + 100))
end=$((start + 120 + 720))
proposalChangeTx ${start} ${end} "${boardsAddr[20]}" false
revokeProposalTx "${proposalID}" "RvkPropChange"
terminateProposalTx "${proposalID}" "TmintPropChange"
queryProposal "${proposalID}" "GetProposalChange"
listProposal 2 "ListProposalChange"
}
init() {
ispara=$(echo '"'"${HTTP}"'"' | jq '.|contains("8901")')
echo "ipara=$ispara"
if [ "$ispara" == true ]; then
EXECTOR_ADDR=$(curl -ksd '{"method":"Chain33.ConvertExectoAddr","params":[{"execname":"user.p.para.autonomy"}]}' ${HTTP} | jq -r ".result")
EXECTOR="user.p.para.autonomy"
TICKET_ADDR=$(curl -ksd '{"method":"Chain33.ConvertExectoAddr","params":[{"execname":"user.p.para.ticket"}]}' ${HTTP} | jq -r ".result")
TICKET_EXECTOR="user.p.para.ticket"
else
EXECTOR_ADDR=$(curl -ksd '{"method":"Chain33.ConvertExectoAddr","params":[{"execname":"autonomy"}]}' ${HTTP} | jq -r ".result")
EXECTOR="autonomy"
TICKET_ADDR=$(curl -ksd '{"method":"Chain33.ConvertExectoAddr","params":[{"execname":"ticket"}]}' ${HTTP} | jq -r ".result")
TICKET_EXECTOR="ticket"
fi
echo "EXECTOR_ADDR=$EXECTOR_ADDR"
local main_ip=${HTTP//8901/8801}
chain33_ImportPrivkey "${propKey}" "${propAddr}" "prop" "${main_ip}"
if [ "$ispara" == false ]; then
chain33_applyCoinsNOLimit "$propAddr" 100000000000 "${main_ip}"
chain33_QueryBalance "${propAddr}" "$main_ip"
else
chain33_applyCoins "$propAddr" 1000000000 "${main_ip}"
chain33_QueryBalance "${propAddr}" "$main_ip"
#主链投票账户转帐
handleBoards "$main_ip"
local para_ip="${HTTP}"
chain33_ImportPrivkey "${propKey}" "${propAddr}" "prop" "$para_ip"
#平行链中账户转帐
chain33_applyCoinsNOLimit "$propAddr" 100000000000 "$para_ip"
chain33_QueryBalance "$propAddr" "$para_ip"
chain33_para_init "$para_ip"
fi
# 往合约中转
chain33_SendToAddress "$propAddr" "$EXECTOR_ADDR" 90000000000 "$HTTP"
chain33_QueryExecBalance "$propAddr" "$EXECTOR" "$HTTP"
# 往ticket合约中转帐
chain33_SendToAddress "$voteAddr" "$TICKET_ADDR" 300100000000 "$HTTP"
chain33_QueryExecBalance "$voteAddr" "$TICKET_EXECTOR" "$HTTP"
# 往投票账户中转帐
handleBoards "$HTTP"
}
function run_testcases() {
echo "run_testcases"
testProposalRule
testProposalBoard
testProposalProject
testProposalChange
}
function rpc_test() {
chain33_RpcTestBegin autonomy
MAIN_HTTP="$1"
echo "main_ip=$MAIN_HTTP"
HTTP="$1"
echo "main_ip=$HTTP"
init
run_testcases
......
......@@ -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"
package commands
import (
"fmt"
"strconv"
jsonrpc "github.com/33cn/chain33/rpc/jsonclient"
rpctypes "github.com/33cn/chain33/rpc/types"
"github.com/33cn/chain33/types"
pkt "github.com/33cn/plugin/plugin/dapp/collateralize/types"
"github.com/spf13/cobra"
)
// CollateralizeCmd 斗牛游戏命令行
func CollateralizeCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "collateralize",
Short: "Collateralize command",
Args: cobra.MinimumNArgs(1),
}
cmd.AddCommand(
CollateralizeCreateRawTxCmd(),
CollateralizeBorrowRawTxCmd(),
CollateralizeAppendRawTxCmd(),
CollateralizeRepayRawTxCmd(),
CollateralizePriceFeedRawTxCmd(),
CollateralizeRetrieveRawTxCmd(),
CollateralizeManageRawTxCmd(),
CollateralizeQueryCmd(),
)
return cmd
}
// CollateralizeCreateRawTxCmd 生成开始交易命令行
func CollateralizeCreateRawTxCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "create",
Short: "Create a collateralize",
Run: CollateralizeCreate,
}
addCollateralizeCreateFlags(cmd)
return cmd
}
func addCollateralizeCreateFlags(cmd *cobra.Command) {
cmd.Flags().Float64P("balance", "b", 0, "balance")
cmd.MarkFlagRequired("balance")
}
func CollateralizeCreate(cmd *cobra.Command, args []string) {
title, _ := cmd.Flags().GetString("title")
cfg := types.GetCliSysParam(title)
if cfg == nil {
panic(fmt.Sprintln("can not find CliSysParam title", title))
}
rpcLaddr, _ := cmd.Flags().GetString("rpc_laddr")
balance, _ := cmd.Flags().GetFloat64("balance")
params := &rpctypes.CreateTxIn{
Execer: cfg.ExecName(pkt.CollateralizeX),
ActionName: "CollateralizeCreate",
Payload: []byte(fmt.Sprintf("{\"totalBalance\":%f}", balance)),
}
var res string
ctx := jsonrpc.NewRPCCtx(rpcLaddr, "Chain33.CreateTransaction", params, &res)
ctx.RunWithoutMarshal()
}
// CollateralizeBorrowRawTxCmd 生成开始交易命令行
func CollateralizeBorrowRawTxCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "borrow",
Short: "Borrow a collateralize",
Run: CollateralizeBorrow,
}
addCollateralizeBorrowFlags(cmd)
return cmd
}
func addCollateralizeBorrowFlags(cmd *cobra.Command) {
cmd.Flags().StringP("collateralizeID", "g", "", "collateralize ID")
cmd.MarkFlagRequired("collateralizeID")
cmd.Flags().Float64P("value", "v", 0, "value")
cmd.MarkFlagRequired("value")
}
func CollateralizeBorrow(cmd *cobra.Command, args []string) {
title, _ := cmd.Flags().GetString("title")
cfg := types.GetCliSysParam(title)
if cfg == nil {
panic(fmt.Sprintln("can not find CliSysParam title", title))
}
rpcLaddr, _ := cmd.Flags().GetString("rpc_laddr")
collateralizeID, _ := cmd.Flags().GetString("collateralizeID")
value, _ := cmd.Flags().GetFloat64("value")
params := &rpctypes.CreateTxIn{
Execer: cfg.ExecName(pkt.CollateralizeX),
ActionName: "CollateralizeBorrow",
Payload: []byte(fmt.Sprintf("{\"collateralizeID\":\"%s\",\"value\":%f}", collateralizeID, value)),
}
var res string
ctx := jsonrpc.NewRPCCtx(rpcLaddr, "Chain33.CreateTransaction", params, &res)
ctx.RunWithoutMarshal()
}
// CollateralizeAppendRawTxCmd 生成开始交易命令行
func CollateralizeAppendRawTxCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "append",
Short: "Append a collateralize",
Run: CollateralizeAppend,
}
addCollateralizeAppendFlags(cmd)
return cmd
}
func addCollateralizeAppendFlags(cmd *cobra.Command) {
cmd.Flags().StringP("collateralizeID", "g", "", "collateralize ID")
cmd.MarkFlagRequired("collateralizeID")
cmd.Flags().StringP("recordID", "r", "", "recordID")
cmd.MarkFlagRequired("recordID")
cmd.Flags().Float64P("value", "v", 0, "value")
cmd.MarkFlagRequired("value")
}
func CollateralizeAppend(cmd *cobra.Command, args []string) {
title, _ := cmd.Flags().GetString("title")
cfg := types.GetCliSysParam(title)
if cfg == nil {
panic(fmt.Sprintln("can not find CliSysParam title", title))
}
rpcLaddr, _ := cmd.Flags().GetString("rpc_laddr")
collateralizeID, _ := cmd.Flags().GetString("collateralizeID")
recordID, _ := cmd.Flags().GetString("recordID")
value, _ := cmd.Flags().GetFloat64("value")
params := &rpctypes.CreateTxIn{
Execer: cfg.ExecName(pkt.CollateralizeX),
ActionName: "CollateralizeAppend",
Payload: []byte(fmt.Sprintf("{\"collateralizeID\":\"%s\", \"recordID\":\"%s\", \"value\":%f}", collateralizeID, recordID, value)),
}
var res string
ctx := jsonrpc.NewRPCCtx(rpcLaddr, "Chain33.CreateTransaction", params, &res)
ctx.RunWithoutMarshal()
}
// CollateralizeRepayRawTxCmd 生成开始交易命令行
func CollateralizeRepayRawTxCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "repay",
Short: "Repay a collateralize",
Run: CollateralizeRepay,
}
addCollateralizeRepayFlags(cmd)
return cmd
}
func addCollateralizeRepayFlags(cmd *cobra.Command) {
cmd.Flags().StringP("collateralizeID", "g", "", "collateralize ID")
cmd.MarkFlagRequired("collateralizeID")
cmd.Flags().StringP("recordID", "r", "", "recordID")
cmd.MarkFlagRequired("recordID")
}
func CollateralizeRepay(cmd *cobra.Command, args []string) {
title, _ := cmd.Flags().GetString("title")
cfg := types.GetCliSysParam(title)
if cfg == nil {
panic(fmt.Sprintln("can not find CliSysParam title", title))
}
rpcLaddr, _ := cmd.Flags().GetString("rpc_laddr")
collateralizeID, _ := cmd.Flags().GetString("collateralizeID")
recordID, _ := cmd.Flags().GetString("recordID")
params := &rpctypes.CreateTxIn{
Execer: cfg.ExecName(pkt.CollateralizeX),
ActionName: "CollateralizeRepay",
Payload: []byte(fmt.Sprintf("{\"collateralizeID\":\"%s\",\"recordID\":\"%s\"}", collateralizeID, recordID)),
}
var res string
ctx := jsonrpc.NewRPCCtx(rpcLaddr, "Chain33.CreateTransaction", params, &res)
ctx.RunWithoutMarshal()
}
// CollateralizePriceFeedRawTxCmd 生成开始交易命令行
func CollateralizePriceFeedRawTxCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "feed",
Short: "price feed",
Run: CollateralizePriceFeed,
}
addCollateralizePriceFeedFlags(cmd)
return cmd
}
func addCollateralizePriceFeedFlags(cmd *cobra.Command) {
cmd.Flags().Float64P("price", "p", 0, "price")
cmd.MarkFlagRequired("price")
cmd.Flags().Uint64P("volume", "v", 0, "volume")
cmd.MarkFlagRequired("volume")
}
func CollateralizePriceFeed(cmd *cobra.Command, args []string) {
title, _ := cmd.Flags().GetString("title")
cfg := types.GetCliSysParam(title)
if cfg == nil {
panic(fmt.Sprintln("can not find CliSysParam title", title))
}
rpcLaddr, _ := cmd.Flags().GetString("rpc_laddr")
price, _ := cmd.Flags().GetFloat64("price")
volume, _ := cmd.Flags().GetUint64("volume")
params := &rpctypes.CreateTxIn{
Execer: cfg.ExecName(pkt.CollateralizeX),
ActionName: "CollateralizePriceFeed",
Payload: []byte(fmt.Sprintf("{\"price\":[ %f ], \"volume\":[ %d ]}", price, volume)),
}
var res string
ctx := jsonrpc.NewRPCCtx(rpcLaddr, "Chain33.CreateTransaction", params, &res)
ctx.RunWithoutMarshal()
}
// CollateralizeCloseRawTxCmd 生成开始交易命令行
func CollateralizeRetrieveRawTxCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "retrieve",
Short: "retrieve balance",
Run: CollateralizeRetrieve,
}
addCollateralizeRetrieveFlags(cmd)
return cmd
}
func addCollateralizeRetrieveFlags(cmd *cobra.Command) {
cmd.Flags().StringP("collateralizeID", "g", "", "collateralize ID")
cmd.MarkFlagRequired("collateralizeID")
cmd.Flags().Float64P("balance", "b", 0, "retrieve balance")
cmd.MarkFlagRequired("balance")
}
func CollateralizeRetrieve(cmd *cobra.Command, args []string) {
title, _ := cmd.Flags().GetString("title")
cfg := types.GetCliSysParam(title)
if cfg == nil {
panic(fmt.Sprintln("can not find CliSysParam title", title))
}
rpcLaddr, _ := cmd.Flags().GetString("rpc_laddr")
collateralizeID, _ := cmd.Flags().GetString("collateralizeID")
balance, _ := cmd.Flags().GetFloat64("balance")
params := &rpctypes.CreateTxIn{
Execer: cfg.ExecName(pkt.CollateralizeX),
ActionName: "CollateralizeRetrieve",
Payload: []byte(fmt.Sprintf("{\"collateralizeID\":\"%s\", \"balance\": %f}", collateralizeID, balance)),
}
var res string
ctx := jsonrpc.NewRPCCtx(rpcLaddr, "Chain33.CreateTransaction", params, &res)
ctx.RunWithoutMarshal()
}
// CollateralizeManageRawTxCmd 生成开始交易命令行
func CollateralizeManageRawTxCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "manage",
Short: "manage a collateralize",
Run: CollateralizeManage,
}
addCollateralizeManageFlags(cmd)
return cmd
}
func addCollateralizeManageFlags(cmd *cobra.Command) {
cmd.Flags().Float64P("debtCeiling", "d", 0, "debtCeiling")
cmd.Flags().Float64P("liquidationRatio", "l", 0, "liquidationRatio")
cmd.Flags().Float64P("stabilityFeeRatio", "s", 0, "stabilityFeeRatio")
cmd.Flags().Uint64P("period", "p", 0, "period")
cmd.Flags().Float64P("totalBalance", "t", 0, "totalBalance")
}
func CollateralizeManage(cmd *cobra.Command, args []string) {
title, _ := cmd.Flags().GetString("title")
cfg := types.GetCliSysParam(title)
if cfg == nil {
panic(fmt.Sprintln("can not find CliSysParam title", title))
}
rpcLaddr, _ := cmd.Flags().GetString("rpc_laddr")
debtCeiling, _ := cmd.Flags().GetFloat64("debtCeiling")
liquidationRatio, _ := cmd.Flags().GetFloat64("liquidationRatio")
stabilityFeeRatio, _ := cmd.Flags().GetFloat64("stabilityFeeRatio")
period, _ := cmd.Flags().GetUint64("period")
totalBalance, _ := cmd.Flags().GetFloat64("totalBalance")
params := &rpctypes.CreateTxIn{
Execer: cfg.ExecName(pkt.CollateralizeX),
ActionName: "CollateralizeManage",
Payload: []byte(fmt.Sprintf("{\"debtCeiling\":%f, \"liquidationRatio\":%f, \"stabilityFeeRatio\":%f, \"period\":%d, \"totalBalance\":%f}",
debtCeiling, liquidationRatio, stabilityFeeRatio, period, totalBalance)),
}
var res string
ctx := jsonrpc.NewRPCCtx(rpcLaddr, "Chain33.CreateTransaction", params, &res)
ctx.RunWithoutMarshal()
}
func CollateralizeQueryCfgCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "config",
Short: "Query config result",
Run: CollateralizeQueryConfig,
}
return cmd
}
func CollateralizeQueryConfig(cmd *cobra.Command, args []string) {
rpcLaddr, _ := cmd.Flags().GetString("rpc_laddr")
var params rpctypes.Query4Jrpc
params.Execer = pkt.CollateralizeX
params.FuncName = "CollateralizeConfig"
var res pkt.RepCollateralizeConfig
ctx := jsonrpc.NewRPCCtx(rpcLaddr, "Chain33.Query", params, &res)
ctx.Run()
}
func CollateralizeQueryPriceCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "price",
Short: "Query latest price",
Run: CollateralizeQueryPrice,
}
return cmd
}
func CollateralizeQueryPrice(cmd *cobra.Command, args []string) {
rpcLaddr, _ := cmd.Flags().GetString("rpc_laddr")
var params rpctypes.Query4Jrpc
params.Execer = pkt.CollateralizeX
params.FuncName = "CollateralizePrice"
var res pkt.RepCollateralizePrice
ctx := jsonrpc.NewRPCCtx(rpcLaddr, "Chain33.Query", params, &res)
ctx.Run()
}
func CollateralizeQueryUserBalanceCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "balance",
Short: "Query user balance",
Run: CollateralizeQueryUserBalance,
}
addCollateralizeQueryBalanceFlags(cmd)
return cmd
}
func addCollateralizeQueryBalanceFlags(cmd *cobra.Command) {
cmd.Flags().StringP("address", "a", "", "address")
cmd.MarkFlagRequired("address")
}
func CollateralizeQueryUserBalance(cmd *cobra.Command, args []string) {
rpcLaddr, _ := cmd.Flags().GetString("rpc_laddr")
addr, _ := cmd.Flags().GetString("address")
var params rpctypes.Query4Jrpc
params.Execer = pkt.CollateralizeX
params.FuncName = "CollateralizeUserBalance"
req := &pkt.ReqCollateralizeRecordByAddr{
Addr: addr,
}
params.Payload = types.MustPBToJSON(req)
var res pkt.RepCollateralizeUserBalance
ctx := jsonrpc.NewRPCCtx(rpcLaddr, "Chain33.Query", params, &res)
ctx.Run()
}
// CollateralizeQueryCmd 查询命令行
func CollateralizeQueryCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "query",
Short: "Query result",
Run: CollateralizeQuery,
}
addCollateralizeQueryFlags(cmd)
cmd.AddCommand(
CollateralizeQueryCfgCmd(),
CollateralizeQueryPriceCmd(),
CollateralizeQueryUserBalanceCmd(),
)
return cmd
}
func addCollateralizeQueryFlags(cmd *cobra.Command) {
cmd.Flags().StringP("collateralizeID", "g", "", "collateralize ID")
cmd.Flags().StringP("address", "a", "", "address")
cmd.Flags().StringP("index", "i", "", "index")
cmd.Flags().StringP("status", "s", "", "status")
cmd.Flags().StringP("collateralizeIDs", "d", "", "collateralize IDs")
cmd.Flags().StringP("borrowID", "b", "", "borrow ID")
}
func CollateralizeQuery(cmd *cobra.Command, args []string) {
rpcLaddr, _ := cmd.Flags().GetString("rpc_laddr")
collateralizeID, _ := cmd.Flags().GetString("collateralizeID")
address, _ := cmd.Flags().GetString("address")
statusStr, _ := cmd.Flags().GetString("status")
collateralizeIDs, _ := cmd.Flags().GetString("collateralizeIDs")
borrowID, _ := cmd.Flags().GetString("borrowID")
var params rpctypes.Query4Jrpc
params.Execer = pkt.CollateralizeX
var status int64
var err error
if statusStr != "" {
status, err = strconv.ParseInt(statusStr, 10, 32)
if err != nil {
fmt.Println(err)
cmd.Help()
return
}
}
if collateralizeID != "" {
if address != "" {
params.FuncName = "CollateralizeRecordByAddr"
req := &pkt.ReqCollateralizeRecordByAddr{
CollateralizeId: collateralizeID,
Status: int32(status),
Addr: address,
}
params.Payload = types.MustPBToJSON(req)
var res pkt.RepCollateralizeRecords
ctx := jsonrpc.NewRPCCtx(rpcLaddr, "Chain33.Query", params, &res)
ctx.Run()
} else if statusStr != "" {
params.FuncName = "CollateralizeRecordByStatus"
req := &pkt.ReqCollateralizeRecordByStatus{
CollateralizeId: collateralizeID,
Status: int32(status),
}
params.Payload = types.MustPBToJSON(req)
var res pkt.RepCollateralizeRecords
ctx := jsonrpc.NewRPCCtx(rpcLaddr, "Chain33.Query", params, &res)
ctx.Run()
} else if borrowID != "" {
params.FuncName = "CollateralizeRecordByID"
req := &pkt.ReqCollateralizeRecord{
CollateralizeId: collateralizeID,
RecordId: borrowID,
}
params.Payload = types.MustPBToJSON(req)
var res pkt.RepCollateralizeRecord
ctx := jsonrpc.NewRPCCtx(rpcLaddr, "Chain33.Query", params, &res)
ctx.Run()
} else {
params.FuncName = "CollateralizeInfoByID"
req := &pkt.ReqCollateralizeInfo{
CollateralizeId: collateralizeID,
}
params.Payload = types.MustPBToJSON(req)
var res pkt.RepCollateralizeCurrentInfo
ctx := jsonrpc.NewRPCCtx(rpcLaddr, "Chain33.Query", params, &res)
ctx.Run()
}
} else if address != "" {
params.FuncName = "CollateralizeByAddr"
req := &pkt.ReqCollateralizeByAddr{Addr: address}
params.Payload = types.MustPBToJSON(req)
var res pkt.RepCollateralizeIDs
ctx := jsonrpc.NewRPCCtx(rpcLaddr, "Chain33.Query", params, &res)
ctx.Run()
} else if statusStr != "" {
params.FuncName = "CollateralizeByStatus"
req := &pkt.ReqCollateralizeByStatus{Status: int32(status)}
params.Payload = types.MustPBToJSON(req)
var res pkt.RepCollateralizeIDs
ctx := jsonrpc.NewRPCCtx(rpcLaddr, "Chain33.Query", params, &res)
ctx.Run()
} else if collateralizeIDs != "" {
params.FuncName = "CollateralizeInfoByIDs"
var collateralizeIDsS []string
collateralizeIDsS = append(collateralizeIDsS, collateralizeIDs)
collateralizeIDsS = append(collateralizeIDsS, collateralizeIDs)
req := &pkt.ReqCollateralizeInfos{CollateralizeIds: collateralizeIDsS}
params.Payload = types.MustPBToJSON(req)
var res pkt.RepCollateralizeCurrentInfos
ctx := jsonrpc.NewRPCCtx(rpcLaddr, "Chain33.Query", params, &res)
ctx.Run()
} else {
fmt.Println("Error: requeres at least one of collId, address or status")
cmd.Help()
}
}
// 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()
}
package executor
import (
"testing"
"time"
"github.com/33cn/chain33/client"
"github.com/33cn/chain33/account"
apimock "github.com/33cn/chain33/client/mocks"
"github.com/33cn/chain33/common"
"github.com/33cn/chain33/common/crypto"
dbm "github.com/33cn/chain33/common/db"
"github.com/33cn/chain33/system/dapp"
pty "github.com/33cn/chain33/system/dapp/manage/types"
"github.com/33cn/chain33/types"
"github.com/33cn/chain33/util"
pkt "github.com/33cn/plugin/plugin/dapp/collateralize/types"
tokenE "github.com/33cn/plugin/plugin/dapp/token/executor"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
)
type execEnv struct {
blockTime int64
blockHeight int64
difficulty uint64
kvdb dbm.KVDB
api client.QueueProtocolAPI
db dbm.KV
execAddr string
cfg *types.Chain33Config
}
var (
PrivKeyA = "0x6da92a632ab7deb67d38c0f6560bcfed28167998f6496db64c258d5e8393a81b" // 1KSBd17H7ZK8iT37aJztFB22XGwsPTdwE4
PrivKeyB = "0x19c069234f9d3e61135fefbeb7791b149cdf6af536f26bebb310d4cd22c3fee4" // 1JRNjdEqp4LJ5fqycUBm9ayCKSeeskgMKR
PrivKeyC = "0xc2b31057b8692a56c7dd18199df71c1d21b781c0b6858c52997c9dbf778e8550" // 12evczYyX9ZKPYvwSEvRkRyTjpSrJuLudg
Nodes = [][]byte{
[]byte("1KSBd17H7ZK8iT37aJztFB22XGwsPTdwE4"),
[]byte("1JRNjdEqp4LJ5fqycUBm9ayCKSeeskgMKR"),
[]byte("12evczYyX9ZKPYvwSEvRkRyTjpSrJuLudg"),
}
total = 10000 * types.Coin
totalToken = 100000 * types.Coin
)
func manageKeySet(key string, value string, db dbm.KV) {
var item types.ConfigItem
item.Key = key
item.Addr = value
item.Ty = pty.ConfigItemArrayConfig
emptyValue := &types.ArrayConfig{Value: make([]string, 0)}
arr := types.ConfigItem_Arr{Arr: emptyValue}
item.Value = &arr
item.GetArr().Value = append(item.GetArr().Value, value)
manageKey := types.ManageKey(key)
valueSave := types.Encode(&item)
db.Set([]byte(manageKey), valueSave)
}
func addrKeySet(value string, db dbm.KV) {
var item types.ConfigItem
item.Addr = value
item.Ty = pty.ConfigItemArrayConfig
emptyValue := &types.ArrayConfig{Value: make([]string, 0)}
arr := types.ConfigItem_Arr{Arr: emptyValue}
item.Value = &arr
item.GetArr().Value = append(item.GetArr().Value, value)
valueSave := types.Encode(&item)
db.Set(AddrKey(), valueSave)
}
func initEnv() *execEnv {
cfg := types.NewChain33Config(types.GetDefaultCfgstring())
cfg.SetTitleOnlyForTest("chain33")
Init(pkt.CollateralizeX, cfg, nil)
_, _, kvdb := util.CreateTestDB()
accountA := types.Account{
Balance: total,
Frozen: 0,
Addr: string(Nodes[0]),
}
accountAToken := types.Account{
Balance: totalToken,
Frozen: 0,
Addr: string(Nodes[0]),
}
accountB := types.Account{
Balance: total,
Frozen: 0,
Addr: string(Nodes[1]),
}
accountBToken := types.Account{
Balance: types.Coin / 10,
Frozen: 0,
Addr: string(Nodes[1]),
}
accountC := types.Account{
Balance: total,
Frozen: 0,
Addr: string(Nodes[2]),
}
api := new(apimock.QueueProtocolAPI)
api.On("GetConfig", mock.Anything).Return(cfg, nil)
execAddr := dapp.ExecAddress(pkt.CollateralizeX)
stateDB, _ := dbm.NewGoMemDB("1", "2", 100)
accA := account.NewCoinsAccount(cfg)
accA.SetDB(stateDB)
accA.SaveExecAccount(execAddr, &accountA)
manageKeySet("issuance-manage", accountA.Addr, stateDB)
addrKeySet(accountA.Addr, stateDB)
tokenAccA, _ := account.NewAccountDB(cfg, tokenE.GetName(), pkt.CCNYTokenName, stateDB)
tokenAccA.SaveExecAccount(execAddr, &accountAToken)
accB := account.NewCoinsAccount(cfg)
accB.SetDB(stateDB)
accB.SaveExecAccount(execAddr, &accountB)
manageKeySet("issuance-price-feed", accountB.Addr, stateDB)
tokenAccB, _ := account.NewAccountDB(cfg, tokenE.GetName(), pkt.CCNYTokenName, stateDB)
tokenAccB.SaveExecAccount(execAddr, &accountBToken)
accC := account.NewCoinsAccount(cfg)
accC.SetDB(stateDB)
accC.SaveExecAccount(execAddr, &accountC)
manageKeySet("issuance-guarantor", accountC.Addr, stateDB)
return &execEnv{
blockTime: time.Now().Unix(),
blockHeight: cfg.GetDappFork(pkt.CollateralizeX, "Enable"),
difficulty: 1539918074,
kvdb: kvdb,
api: api,
db: stateDB,
execAddr: execAddr,
cfg: cfg,
}
}
func TestCollateralize(t *testing.T) {
env := initEnv()
// collateralize manage
p3 := &pkt.CollateralizeManageTx{}
p3.Period = 5
p3.LiquidationRatio = 0.25
p3.DebtCeiling = 100
p3.StabilityFeeRatio = 0.0001
p3.TotalBalance = 10000
createTx, err := pkt.CreateRawCollateralizeManageTx(env.cfg, p3)
if err != nil {
t.Error("RPC_Default_Process", "err", err)
}
createTx.Execer = []byte(pkt.CollateralizeX)
createTx, err = signTx(createTx, PrivKeyA)
if err != nil {
t.Error("RPC_Default_Process sign", "err", err)
}
exec := newCollateralize()
exec.SetAPI(env.api)
exec.SetStateDB(env.db)
assert.Equal(t, exec.GetCoinsAccount().LoadExecAccount(string(Nodes[0]), env.execAddr).GetBalance(), total)
exec.SetLocalDB(env.kvdb)
exec.SetEnv(env.blockHeight, env.blockTime, env.difficulty)
exec.SetEnv(env.blockHeight+1, env.blockTime+1, env.difficulty)
receipt, err := exec.Exec(createTx, int(1))
assert.Nil(t, err)
assert.NotNil(t, receipt)
t.Log(receipt)
for _, kv := range receipt.KV {
env.db.Set(kv.Key, kv.Value)
}
receiptData := &types.ReceiptData{Ty: receipt.Ty, Logs: receipt.Logs}
set, err := exec.ExecLocal(createTx, receiptData, int(1))
assert.Nil(t, err)
assert.NotNil(t, set)
for _, kv := range set.KV {
env.kvdb.Set(kv.Key, kv.Value)
}
// collateralize create
p1 := &pkt.CollateralizeCreateTx{
TotalBalance: 1000,
}
createTx, err = pkt.CreateRawCollateralizeCreateTx(env.cfg, p1)
if err != nil {
t.Error("RPC_Default_Process", "err", err)
}
createTx.Execer = []byte(pkt.CollateralizeX)
createTx, err = signTx(createTx, PrivKeyA)
if err != nil {
t.Error("RPC_Default_Process sign", "err", err)
}
receipt, err = exec.Exec(createTx, int(1))
assert.Nil(t, err)
assert.NotNil(t, receipt)
for _, kv := range receipt.KV {
env.db.Set(kv.Key, kv.Value)
}
receiptData = &types.ReceiptData{Ty: receipt.Ty, Logs: receipt.Logs}
set, err = exec.ExecLocal(createTx, receiptData, int(1))
assert.Nil(t, err)
assert.NotNil(t, set)
for _, kv := range set.KV {
env.kvdb.Set(kv.Key, kv.Value)
}
collateralizeID := createTx.Hash()
// query collateralize by id
res, err := exec.Query("CollateralizeInfoByID", types.Encode(&pkt.ReqCollateralizeInfo{CollateralizeId: common.ToHex(collateralizeID)}))
assert.Nil(t, err)
assert.NotNil(t, res)
// query collateralize by status
res, err = exec.Query("CollateralizeByStatus", types.Encode(&pkt.ReqCollateralizeByStatus{Status: 1}))
assert.Nil(t, err)
assert.NotNil(t, res)
// query collateralizes by ids
var collateralizeIDsS []string
collateralizeIDsS = append(collateralizeIDsS, common.ToHex(collateralizeID))
res, err = exec.Query("CollateralizeInfoByIDs", types.Encode(&pkt.ReqCollateralizeInfos{CollateralizeIds: collateralizeIDsS}))
assert.Nil(t, err)
assert.NotNil(t, res)
// collateralize price
p2 := &pkt.CollateralizeFeedTx{}
p2.Price = append(p2.Price, 1)
p2.Volume = append(p2.Volume, 100)
createTx, err = pkt.CreateRawCollateralizeFeedTx(env.cfg, p2)
if err != nil {
t.Error("RPC_Default_Process", "err", err)
}
createTx.Execer = []byte(pkt.CollateralizeX)
createTx, err = signTx(createTx, PrivKeyB)
if err != nil {
t.Error("RPC_Default_Process sign", "err", err)
}
exec.SetEnv(env.blockHeight+1, env.blockTime+1, env.difficulty)
receipt, err = exec.Exec(createTx, int(1))
assert.Nil(t, err)
assert.NotNil(t, receipt)
t.Log(receipt)
for _, kv := range receipt.KV {
env.db.Set(kv.Key, kv.Value)
}
receiptData = &types.ReceiptData{Ty: receipt.Ty, Logs: receipt.Logs}
set, err = exec.ExecLocal(createTx, receiptData, int(1))
assert.Nil(t, err)
assert.NotNil(t, set)
for _, kv := range set.KV {
env.kvdb.Set(kv.Key, kv.Value)
}
// query collateralize by id
res, err = exec.Query("CollateralizePrice", nil)
assert.Nil(t, err)
assert.NotNil(t, res)
// collateralize borrow
p4 := &pkt.CollateralizeBorrowTx{
CollateralizeID: common.ToHex(collateralizeID),
Value: 100,
}
createTx, err = pkt.CreateRawCollateralizeBorrowTx(env.cfg, p4)
if err != nil {
t.Error("RPC_Default_Process", "err", err)
}
createTx.Execer = []byte(pkt.CollateralizeX)
createTx, err = signTx(createTx, PrivKeyB)
if err != nil {
t.Error("RPC_Default_Process sign", "err", err)
}
exec.SetEnv(env.blockHeight+1, env.blockTime+1, env.difficulty)
receipt, err = exec.Exec(createTx, int(1))
assert.Nil(t, err)
assert.NotNil(t, receipt)
t.Log(receipt)
for _, kv := range receipt.KV {
env.db.Set(kv.Key, kv.Value)
}
receiptData = &types.ReceiptData{Ty: receipt.Ty, Logs: receipt.Logs}
set, err = exec.ExecLocal(createTx, receiptData, int(1))
assert.Nil(t, err)
assert.NotNil(t, set)
for _, kv := range set.KV {
env.kvdb.Set(kv.Key, kv.Value)
}
borrowID := createTx.Hash()
// query collateralize by id
res, err = exec.Query("CollateralizeRecordByID",
types.Encode(&pkt.ReqCollateralizeRecord{CollateralizeId: common.ToHex(collateralizeID), RecordId: common.ToHex(borrowID)}))
assert.Nil(t, err)
assert.NotNil(t, res)
// query collateralize by status
res, err = exec.Query("CollateralizeRecordByStatus",
types.Encode(&pkt.ReqCollateralizeRecordByStatus{CollateralizeId: common.ToHex(collateralizeID), Status: 1}))
assert.Nil(t, err)
assert.NotNil(t, res)
// query collateralize by addr
res, err = exec.Query("CollateralizeRecordByAddr",
types.Encode(&pkt.ReqCollateralizeRecordByAddr{CollateralizeId: common.ToHex(collateralizeID), Addr: string(Nodes[1]), Status: 1}))
assert.Nil(t, err)
assert.NotNil(t, res)
res, err = exec.Query("CollateralizeRecordByAddr",
types.Encode(&pkt.ReqCollateralizeRecordByAddr{Addr: string(Nodes[1]), Status: 1}))
assert.Nil(t, err)
assert.NotNil(t, res)
// query collateralize user balance
res, err = exec.Query("CollateralizeUserBalance",
types.Encode(&pkt.ReqCollateralizeRecordByAddr{Addr: string(Nodes[1]), Status: 1}))
assert.Nil(t, err)
assert.Equal(t, int64(100)*types.Coin, res.(*pkt.RepCollateralizeUserBalance).Balance)
// collateralize append
p5 := &pkt.CollateralizeAppendTx{
CollateralizeID: common.ToHex(collateralizeID),
RecordID: common.ToHex(borrowID),
Value: 100,
}
createTx, err = pkt.CreateRawCollateralizeAppendTx(env.cfg, p5)
if err != nil {
t.Error("RPC_Default_Process", "err", err)
}
createTx.Execer = []byte(pkt.CollateralizeX)
createTx, err = signTx(createTx, PrivKeyB)
if err != nil {
t.Error("RPC_Default_Process sign", "err", err)
}
exec.SetEnv(env.blockHeight+1, env.blockTime+1, env.difficulty)
receipt, err = exec.Exec(createTx, int(1))
assert.Nil(t, err)
assert.NotNil(t, receipt)
t.Log(receipt)
for _, kv := range receipt.KV {
env.db.Set(kv.Key, kv.Value)
}
receiptData = &types.ReceiptData{Ty: receipt.Ty, Logs: receipt.Logs}
set, err = exec.ExecLocal(createTx, receiptData, int(1))
assert.Nil(t, err)
assert.NotNil(t, set)
for _, kv := range set.KV {
env.kvdb.Set(kv.Key, kv.Value)
}
// query collateralize by id
res, err = exec.Query("CollateralizeRecordByID",
types.Encode(&pkt.ReqCollateralizeRecord{CollateralizeId: common.ToHex(collateralizeID), RecordId: common.ToHex(borrowID)}))
assert.Nil(t, err)
assert.NotNil(t, res)
// query collateralize by status
res, err = exec.Query("CollateralizeRecordByStatus",
types.Encode(&pkt.ReqCollateralizeRecordByStatus{CollateralizeId: common.ToHex(collateralizeID), Status: 1}))
assert.Nil(t, err)
assert.NotNil(t, res)
// query collateralize by addr
res, err = exec.Query("CollateralizeRecordByAddr",
types.Encode(&pkt.ReqCollateralizeRecordByAddr{CollateralizeId: common.ToHex(collateralizeID), Addr: string(Nodes[1]), Status: 1}))
assert.Nil(t, err)
assert.NotNil(t, res)
// collateralize repay
p6 := &pkt.CollateralizeRepayTx{
CollateralizeID: common.ToHex(collateralizeID),
RecordID: common.ToHex(borrowID),
}
createTx, err = pkt.CreateRawCollateralizeRepayTx(env.cfg, p6)
if err != nil {
t.Error("RPC_Default_Process", "err", err)
}
createTx.Execer = []byte(pkt.CollateralizeX)
createTx, err = signTx(createTx, PrivKeyB)
if err != nil {
t.Error("RPC_Default_Process sign", "err", err)
}
exec.SetEnv(env.blockHeight+1, env.blockTime+1, env.difficulty)
receipt, err = exec.Exec(createTx, int(1))
assert.Nil(t, err)
assert.NotNil(t, receipt)
t.Log(receipt)
for _, kv := range receipt.KV {
env.db.Set(kv.Key, kv.Value)
}
receiptData = &types.ReceiptData{Ty: receipt.Ty, Logs: receipt.Logs}
set, err = exec.ExecLocal(createTx, receiptData, int(1))
assert.Nil(t, err)
assert.NotNil(t, set)
for _, kv := range set.KV {
env.kvdb.Set(kv.Key, kv.Value)
}
// query collateralize by status
res, err = exec.Query("CollateralizeRecordByStatus",
types.Encode(&pkt.ReqCollateralizeRecordByStatus{CollateralizeId: common.ToHex(collateralizeID), Status: 6}))
assert.Nil(t, err)
assert.NotNil(t, res)
// query collateralize by addr
res, err = exec.Query("CollateralizeRecordByAddr",
types.Encode(&pkt.ReqCollateralizeRecordByAddr{CollateralizeId: common.ToHex(collateralizeID), Addr: string(Nodes[1]), Status: 6}))
assert.Nil(t, err)
assert.NotNil(t, res)
res, err = exec.Query("CollateralizeRecordByAddr",
types.Encode(&pkt.ReqCollateralizeRecordByAddr{Addr: string(Nodes[1]), Status: 6}))
assert.Nil(t, err)
assert.NotNil(t, res)
// query collateralize user balance
res, err = exec.Query("CollateralizeUserBalance",
types.Encode(&pkt.ReqCollateralizeRecordByAddr{Addr: string(Nodes[1]), Status: 1}))
assert.Nil(t, err)
assert.Equal(t, int64(0), res.(*pkt.RepCollateralizeUserBalance).Balance)
// collateralize liquidate
p7 := &pkt.CollateralizeBorrowTx{
CollateralizeID: common.ToHex(collateralizeID),
Value: 100,
}
createTx, err = pkt.CreateRawCollateralizeBorrowTx(env.cfg, p7)
if err != nil {
t.Error("RPC_Default_Process", "err", err)
}
createTx.Execer = []byte(pkt.CollateralizeX)
createTx, err = signTx(createTx, PrivKeyB)
if err != nil {
t.Error("RPC_Default_Process sign", "err", err)
}
exec.SetEnv(env.blockHeight+1, env.blockTime+1, env.difficulty)
receipt, err = exec.Exec(createTx, int(1))
assert.Nil(t, err)
assert.NotNil(t, receipt)
t.Log(receipt)
for _, kv := range receipt.KV {
env.db.Set(kv.Key, kv.Value)
}
receiptData = &types.ReceiptData{Ty: receipt.Ty, Logs: receipt.Logs}
set, err = exec.ExecLocal(createTx, receiptData, int(1))
assert.Nil(t, err)
assert.NotNil(t, set)
for _, kv := range set.KV {
env.kvdb.Set(kv.Key, kv.Value)
}
p8 := &pkt.CollateralizeFeedTx{}
p8.Price = append(p8.Price, 0.28)
p8.Volume = append(p8.Volume, 100)
createTx, err = pkt.CreateRawCollateralizeFeedTx(env.cfg, p8)
if err != nil {
t.Error("RPC_Default_Process", "err", err)
}
createTx.Execer = []byte(pkt.CollateralizeX)
createTx, err = signTx(createTx, PrivKeyB)
if err != nil {
t.Error("RPC_Default_Process sign", "err", err)
}
exec.SetEnv(env.blockHeight+1, env.blockTime+1, env.difficulty)
receipt, err = exec.Exec(createTx, int(1))
assert.Nil(t, err)
assert.NotNil(t, receipt)
t.Log(receipt)
for _, kv := range receipt.KV {
env.db.Set(kv.Key, kv.Value)
}
receiptData = &types.ReceiptData{Ty: receipt.Ty, Logs: receipt.Logs}
set, err = exec.ExecLocal(createTx, receiptData, int(1))
assert.Nil(t, err)
assert.NotNil(t, set)
for _, kv := range set.KV {
env.kvdb.Set(kv.Key, kv.Value)
}
// query collateralize by status
res, err = exec.Query("CollateralizeRecordByStatus",
types.Encode(&pkt.ReqCollateralizeRecordByStatus{CollateralizeId: common.ToHex(collateralizeID), Status: 2}))
assert.Nil(t, err)
assert.NotNil(t, res)
res, err = exec.Query("CollateralizeRecordByStatus",
types.Encode(&pkt.ReqCollateralizeRecordByStatus{CollateralizeId: common.ToHex(collateralizeID), Status: 4}))
assert.Nil(t, res)
p81 := &pkt.CollateralizeFeedTx{}
p81.Price = append(p81.Price, 0.5)
p81.Volume = append(p81.Volume, 100)
createTx, err = pkt.CreateRawCollateralizeFeedTx(env.cfg, p81)
if err != nil {
t.Error("RPC_Default_Process", "err", err)
}
createTx.Execer = []byte(pkt.CollateralizeX)
createTx, err = signTx(createTx, PrivKeyB)
if err != nil {
t.Error("RPC_Default_Process sign", "err", err)
}
exec.SetEnv(env.blockHeight+1, env.blockTime+1, env.difficulty)
receipt, err = exec.Exec(createTx, int(1))
assert.Nil(t, err)
assert.NotNil(t, receipt)
t.Log(receipt)
for _, kv := range receipt.KV {
env.db.Set(kv.Key, kv.Value)
}
receiptData = &types.ReceiptData{Ty: receipt.Ty, Logs: receipt.Logs}
set, err = exec.ExecLocal(createTx, receiptData, int(1))
assert.Nil(t, err)
assert.NotNil(t, set)
for _, kv := range set.KV {
env.kvdb.Set(kv.Key, kv.Value)
}
// query collateralize by status
res, err = exec.Query("CollateralizeRecordByStatus",
types.Encode(&pkt.ReqCollateralizeRecordByStatus{CollateralizeId: common.ToHex(collateralizeID), Status: 4}))
assert.Nil(t, err)
assert.NotNil(t, res)
p9 := &pkt.CollateralizeFeedTx{}
p9.Price = append(p9.Price, 0.25)
p9.Volume = append(p9.Volume, 100)
createTx, err = pkt.CreateRawCollateralizeFeedTx(env.cfg, p9)
if err != nil {
t.Error("RPC_Default_Process", "err", err)
}
createTx.Execer = []byte(pkt.CollateralizeX)
createTx, err = signTx(createTx, PrivKeyB)
if err != nil {
t.Error("RPC_Default_Process sign", "err", err)
}
exec.SetEnv(env.blockHeight+1, env.blockTime+1, env.difficulty)
receipt, err = exec.Exec(createTx, int(1))
assert.Nil(t, err)
assert.NotNil(t, receipt)
t.Log(receipt)
for _, kv := range receipt.KV {
env.db.Set(kv.Key, kv.Value)
}
receiptData = &types.ReceiptData{Ty: receipt.Ty, Logs: receipt.Logs}
set, err = exec.ExecLocal(createTx, receiptData, int(1))
assert.Nil(t, err)
assert.NotNil(t, set)
for _, kv := range set.KV {
env.kvdb.Set(kv.Key, kv.Value)
}
// query collateralize by status
res, err = exec.Query("CollateralizeRecordByStatus",
types.Encode(&pkt.ReqCollateralizeRecordByStatus{CollateralizeId: common.ToHex(collateralizeID), Status: 3}))
assert.Nil(t, err)
assert.NotNil(t, res)
res, err = exec.Query("CollateralizeRecordByStatus",
types.Encode(&pkt.ReqCollateralizeRecordByStatus{CollateralizeId: common.ToHex(collateralizeID), Status: 4}))
assert.Nil(t, res)
// expire liquidate
p10 := &pkt.CollateralizeBorrowTx{
CollateralizeID: common.ToHex(collateralizeID),
Value: 100,
}
createTx, err = pkt.CreateRawCollateralizeBorrowTx(env.cfg, p10)
if err != nil {
t.Error("RPC_Default_Process", "err", err)
}
createTx.Execer = []byte(pkt.CollateralizeX)
createTx, err = signTx(createTx, PrivKeyB)
if err != nil {
t.Error("RPC_Default_Process sign", "err", err)
}
exec.SetEnv(env.blockHeight+1, env.blockTime+1, env.difficulty)
receipt, err = exec.Exec(createTx, int(1))
assert.Nil(t, err)
assert.NotNil(t, receipt)
t.Log(receipt)
for _, kv := range receipt.KV {
env.db.Set(kv.Key, kv.Value)
}
receiptData = &types.ReceiptData{Ty: receipt.Ty, Logs: receipt.Logs}
set, err = exec.ExecLocal(createTx, receiptData, int(1))
assert.Nil(t, err)
assert.NotNil(t, set)
for _, kv := range set.KV {
env.kvdb.Set(kv.Key, kv.Value)
}
p11 := &pkt.CollateralizeFeedTx{}
p11.Price = append(p11.Price, 1)
p11.Volume = append(p11.Volume, 100)
createTx, err = pkt.CreateRawCollateralizeFeedTx(env.cfg, p11)
if err != nil {
t.Error("RPC_Default_Process", "err", err)
}
createTx.Execer = []byte(pkt.CollateralizeX)
createTx, err = signTx(createTx, PrivKeyB)
if err != nil {
t.Error("RPC_Default_Process sign", "err", err)
}
exec.SetEnv(env.blockHeight+1, env.blockTime+6, env.difficulty)
receipt, err = exec.Exec(createTx, int(1))
assert.Nil(t, err)
assert.NotNil(t, receipt)
t.Log(receipt)
for _, kv := range receipt.KV {
env.db.Set(kv.Key, kv.Value)
}
receiptData = &types.ReceiptData{Ty: receipt.Ty, Logs: receipt.Logs}
set, err = exec.ExecLocal(createTx, receiptData, int(1))
assert.Nil(t, err)
assert.NotNil(t, set)
for _, kv := range set.KV {
env.kvdb.Set(kv.Key, kv.Value)
}
// query collateralize by status
res, err = exec.Query("CollateralizeRecordByStatus",
types.Encode(&pkt.ReqCollateralizeRecordByStatus{CollateralizeId: common.ToHex(collateralizeID), Status: 5}))
assert.Nil(t, err)
assert.NotNil(t, res)
// collateralize retrieve
p12 := &pkt.CollateralizeRetrieveTx{
CollateralizeID: common.ToHex(collateralizeID),
Balance: 100,
}
createTx, err = pkt.CreateRawCollateralizeRetrieveTx(env.cfg, p12)
if err != nil {
t.Error("RPC_Default_Process", "err", err)
}
createTx.Execer = []byte(pkt.CollateralizeX)
createTx, err = signTx(createTx, PrivKeyA)
if err != nil {
t.Error("RPC_Default_Process sign", "err", err)
}
exec.SetEnv(env.blockHeight+2, env.blockTime+2, env.difficulty)
receipt, err = exec.Exec(createTx, int(1))
assert.Nil(t, err)
assert.NotNil(t, receipt)
for _, kv := range receipt.KV {
env.db.Set(kv.Key, kv.Value)
}
receiptData = &types.ReceiptData{Ty: receipt.Ty, Logs: receipt.Logs}
set, err = exec.ExecLocal(createTx, receiptData, int(1))
assert.Nil(t, err)
assert.NotNil(t, set)
for _, kv := range set.KV {
env.kvdb.Set(kv.Key, kv.Value)
}
// query collateralize by status
res, err = exec.Query("CollateralizeByStatus", types.Encode(&pkt.ReqCollateralizeByStatus{Status: 1}))
assert.Nil(t, err)
assert.NotNil(t, res)
}
func signTx(tx *types.Transaction, hexPrivKey string) (*types.Transaction, error) {
signType := types.SECP256K1
c, err := crypto.New(types.GetSignName(pkt.CollateralizeX, 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
}
// 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/account"
"github.com/33cn/chain33/common"
dbm "github.com/33cn/chain33/common/db"
"github.com/33cn/chain33/system/dapp"
"github.com/33cn/chain33/types"
pty "github.com/33cn/plugin/plugin/dapp/collateralize/types"
issuanceE "github.com/33cn/plugin/plugin/dapp/issuance/types"
tokenE "github.com/33cn/plugin/plugin/dapp/token/executor"
)
// List control
const (
ListDESC = int32(0) // list降序
ListASC = int32(1) // list升序
DefaultCount = int32(20) // 默认一次取多少条记录
MaxCount = int32(100) // 最多取100条
)
const (
Coin = types.Coin // 1e8
DefaultDebtCeiling = 10000 * Coin // 默认借贷限额
DefaultLiquidationRatio = 0.4 * 1e4 // 默认质押比
DefaultStabilityFeeRation = 0.08 * 1e4 // 默认稳定费
DefaultPeriod = 3600 * 24 * 365 // 默认合约限期
DefaultTotalBalance = 0 // 默认放贷总额
PriceWarningRate = 1.3 * 1e4 // 价格提前预警率
ExpireWarningTime = 3600 * 24 * 10 // 提前10天超时预警
)
// CollateralizeDB def
type CollateralizeDB struct {
pty.Collateralize
}
// GetKVSet for CollateralizeDB
func (coll *CollateralizeDB) GetKVSet() (kvset []*types.KeyValue) {
value := types.Encode(&coll.Collateralize)
kvset = append(kvset, &types.KeyValue{Key: Key(coll.CollateralizeId), Value: value})
return kvset
}
// Save for CollateralizeDB
func (coll *CollateralizeDB) Save(db dbm.KV) {
set := coll.GetKVSet()
for i := 0; i < len(set); i++ {
db.Set(set[i].GetKey(), set[i].Value)
}
}
// Key for Collateralize
func Key(id string) (key []byte) {
key = append(key, []byte("mavl-"+pty.CollateralizeX+"-")...)
key = append(key, []byte(id)...)
return key
}
// Key for CollateralizeConfig
func ConfigKey() (key []byte) {
key = append(key, []byte("mavl-"+pty.CollateralizeX+"-config")...)
return key
}
// Key for CollateralizeAddrConfig
func AddrKey() (key []byte) {
key = append(key, []byte("mavl-"+issuanceE.IssuanceX+"-addr")...)
return key
}
// Key for IssuancePriceFeed
func PriceKey() (key []byte) {
key = append(key, []byte("mavl-"+pty.CollateralizeX+"-price")...)
return key
}
// Action struct
type Action struct {
coinsAccount *account.DB // bty账户
tokenAccount *account.DB // ccny账户
db dbm.KV
localDB dbm.KVDB
txhash []byte
fromaddr string
blocktime int64
height int64
execaddr string
difficulty uint64
index int
Collateralize *Collateralize
}
// NewCollateralizeAction generate New Action
func NewCollateralizeAction(c *Collateralize, tx *types.Transaction, index int) *Action {
hash := tx.Hash()
fromaddr := tx.From()
cfg := c.GetAPI().GetConfig()
tokenDb, err := account.NewAccountDB(cfg, tokenE.GetName(), pty.CCNYTokenName, c.GetStateDB())
if err != nil {
clog.Error("NewCollateralizeAction", "Get Account DB error", "error", err)
return nil
}
return &Action{
coinsAccount: c.GetCoinsAccount(), tokenAccount: tokenDb, db: c.GetStateDB(), localDB: c.GetLocalDB(),
txhash: hash, fromaddr: fromaddr, blocktime: c.GetBlockTime(), height: c.GetHeight(),
execaddr: dapp.ExecAddress(string(tx.Execer)), difficulty: c.GetDifficulty(), index: index, Collateralize: c}
}
// GetCreateReceiptLog generate logs for Collateralize create action
func (action *Action) GetCreateReceiptLog(collateralize *pty.Collateralize) *types.ReceiptLog {
log := &types.ReceiptLog{}
log.Ty = pty.TyLogCollateralizeCreate
c := &pty.ReceiptCollateralize{}
c.CollateralizeId = collateralize.CollateralizeId
c.Status = collateralize.Status
c.AccountAddr = action.fromaddr
log.Log = types.Encode(c)
return log
}
// GetBorrowReceiptLog generate logs for Collateralize borrow action
func (action *Action) GetBorrowReceiptLog(collateralize *pty.Collateralize, record *pty.BorrowRecord) *types.ReceiptLog {
log := &types.ReceiptLog{}
log.Ty = pty.TyLogCollateralizeBorrow
c := &pty.ReceiptCollateralize{}
c.CollateralizeId = collateralize.CollateralizeId
c.AccountAddr = action.fromaddr
c.RecordId = record.RecordId
c.Status = record.Status
log.Log = types.Encode(c)
return log
}
// GetRepayReceiptLog generate logs for Collateralize Repay action
func (action *Action) GetRepayReceiptLog(collateralize *pty.Collateralize, record *pty.BorrowRecord) *types.ReceiptLog {
log := &types.ReceiptLog{}
log.Ty = pty.TyLogCollateralizeRepay
c := &pty.ReceiptCollateralize{}
c.CollateralizeId = collateralize.CollateralizeId
c.AccountAddr = action.fromaddr
c.RecordId = record.RecordId
c.Status = record.Status
log.Log = types.Encode(c)
return log
}
// GetAppendReceiptLog generate logs for Collateralize append action
func (action *Action) GetAppendReceiptLog(collateralize *pty.Collateralize, record *pty.BorrowRecord) *types.ReceiptLog {
log := &types.ReceiptLog{}
log.Ty = pty.TyLogCollateralizeAppend
c := &pty.ReceiptCollateralize{}
c.CollateralizeId = collateralize.CollateralizeId
c.AccountAddr = action.fromaddr
c.RecordId = record.RecordId
c.Status = record.Status
log.Log = types.Encode(c)
return log
}
// GetFeedReceiptLog generate logs for Collateralize price feed action
func (action *Action) GetFeedReceiptLog(collateralize *pty.Collateralize, record *pty.BorrowRecord) *types.ReceiptLog {
log := &types.ReceiptLog{}
log.Ty = pty.TyLogCollateralizeFeed
c := &pty.ReceiptCollateralize{}
c.CollateralizeId = collateralize.CollateralizeId
c.AccountAddr = record.AccountAddr
c.RecordId = record.RecordId
c.Status = record.Status
log.Log = types.Encode(c)
return log
}
// GetCloseReceiptLog generate logs for Collateralize close action
func (action *Action) GetRetrieveReceiptLog(collateralize *pty.Collateralize) *types.ReceiptLog {
log := &types.ReceiptLog{}
log.Ty = pty.TyLogCollateralizeRetrieve
c := &pty.ReceiptCollateralize{}
c.CollateralizeId = collateralize.CollateralizeId
c.Status = collateralize.Status
c.AccountAddr = action.fromaddr
log.Log = types.Encode(c)
return log
}
// GetIndex returns index in block
func (action *Action) GetIndex() int64 {
return action.height*types.MaxTxsPerBlock + int64(action.index)
}
func getLatestLiquidationPrice(coll *pty.Collateralize) int64 {
var latest int64
for _, collRecord := range coll.BorrowRecords {
if collRecord.LiquidationPrice > latest {
latest = collRecord.LiquidationPrice
}
}
return latest
}
func getLatestExpireTime(coll *pty.Collateralize) int64 {
var latest int64 = 0x7fffffffffffffff
for _, collRecord := range coll.BorrowRecords {
if collRecord.ExpireTime < latest {
latest = collRecord.ExpireTime
}
}
return latest
}
// CollateralizeConfig 设置全局借贷参数(管理员权限)
func (action *Action) CollateralizeManage(manage *pty.CollateralizeManage) (*types.Receipt, error) {
var kv []*types.KeyValue
var receipt *types.Receipt
// 是否配置管理用户
if !isRightAddr(issuanceE.ManageKey, action.fromaddr, action.db) {
clog.Error("CollateralizeManage", "addr", action.fromaddr, "error", "Address has no permission to config")
return nil, pty.ErrPermissionDeny
}
// 配置借贷参数
if manage.DebtCeiling < 0 || manage.LiquidationRatio < 0 || manage.LiquidationRatio >= 10000 ||
manage.StabilityFeeRatio < 0 || manage.StabilityFeeRatio >= 10000 {
return nil, pty.ErrRiskParam
}
manConfig, _ := getCollateralizeConfig(action.db)
if manConfig == nil {
manConfig = &pty.CollateralizeManage{
DebtCeiling: DefaultDebtCeiling,
LiquidationRatio: DefaultLiquidationRatio,
StabilityFeeRatio: DefaultStabilityFeeRation,
Period: DefaultPeriod,
TotalBalance: DefaultTotalBalance,
}
}
collConfig := &pty.CollateralizeManage{}
if manage.StabilityFeeRatio != 0 {
collConfig.StabilityFeeRatio = manage.StabilityFeeRatio
} else {
collConfig.StabilityFeeRatio = manConfig.StabilityFeeRatio
}
if manage.Period != 0 {
collConfig.Period = manage.Period
} else {
collConfig.Period = manConfig.Period
}
if manage.LiquidationRatio != 0 {
collConfig.LiquidationRatio = manage.LiquidationRatio
} else {
collConfig.LiquidationRatio = manConfig.LiquidationRatio
}
if manage.DebtCeiling != 0 {
collConfig.DebtCeiling = manage.DebtCeiling
} else {
collConfig.DebtCeiling = manConfig.DebtCeiling
}
if manage.TotalBalance != 0 {
collConfig.TotalBalance = manage.TotalBalance
} else {
collConfig.TotalBalance = manConfig.TotalBalance
}
collConfig.CurrentTime = action.blocktime
value := types.Encode(collConfig)
action.db.Set(ConfigKey(), value)
kv = append(kv, &types.KeyValue{Key: ConfigKey(), Value: value})
receipt = &types.Receipt{Ty: types.ExecOk, KV: kv, Logs: nil}
return receipt, nil
}
func getCollateralizeConfig(db dbm.KV) (*pty.CollateralizeManage, error) {
data, err := db.Get(ConfigKey())
if err != nil {
clog.Debug("getCollateralizeConfig", "error", err)
return nil, err
}
var collCfg pty.CollateralizeManage
err = types.Decode(data, &collCfg)
if err != nil {
clog.Debug("getCollateralizeConfig", "decode", err)
return nil, err
}
return &collCfg, nil
}
func isSuperAddr(addr string, db dbm.KV) bool {
data, err := db.Get(AddrKey())
if err != nil {
clog.Error("getSuperAddr", "error", err)
return false
}
var item types.ConfigItem
err = types.Decode(data, &item)
if err != nil {
clog.Error("isSuperAddr", "Decode", data)
return false
}
for _, op := range item.GetArr().Value {
if op == addr {
return true
}
}
return false
}
// 获取可放贷金额
func getCollBalance(totalBalance int64, localdb dbm.KVDB, db dbm.KV) (int64, error) {
collIDRecords, err := queryCollateralizeByStatus(localdb, pty.CollateralizeStatusCreated, "")
if err != nil {
clog.Debug("Query_CollateralizeByStatus", "get collateralize record error", err)
}
balance := totalBalance
for _, id := range collIDRecords {
coll, err := queryCollateralizeByID(db, id)
if err != nil {
clog.Error("Query_CollateralizeInfoByID", "id", id, "error", err)
return 0, err
}
balance -= coll.TotalBalance
}
return balance, nil
}
// CollateralizeCreate 创建借贷,持有一定数量ccny的用户可创建借贷,提供给其他用户借贷
func (action *Action) CollateralizeCreate(create *pty.CollateralizeCreate) (*types.Receipt, error) {
var logs []*types.ReceiptLog
var kv []*types.KeyValue
var receipt *types.Receipt
if !isSuperAddr(action.fromaddr, action.db) {
clog.Error("CollateralizeCreate", "error", "CollateralizeCreate need super address")
return nil, pty.ErrPermissionDeny
}
// 参数检查
if create.GetTotalBalance() <= 0 {
clog.Error("CollateralizeCreate", "addr", action.fromaddr, "execaddr", action.execaddr, "total balance", create.GetTotalBalance(), "error", types.ErrAmount)
return nil, types.ErrAmount
}
// 获取借贷配置
collcfg, err := getCollateralizeConfig(action.db)
if err != nil {
clog.Error("CollateralizeCreate.getCollateralizeConfig", "addr", action.fromaddr, "error", err)
return nil, err
}
// 判断当前可放贷金额
reBalance, err := getCollBalance(collcfg.TotalBalance, action.localDB, action.db)
if err != nil {
clog.Error("CollateralizeCreate.getCollBalance", "addr", action.fromaddr, "error", err)
return nil, err
}
if reBalance < create.GetTotalBalance() {
clog.Error("CollateralizeCreate.getCollBalance", "addr", action.fromaddr, "collBalance", reBalance, "create.balance", create.GetTotalBalance(), "error", pty.ErrCollateralizeLowBalance)
return nil, pty.ErrCollateralizeLowBalance
}
// 检查ccny余额
if !action.CheckExecTokenAccount(action.fromaddr, create.TotalBalance, false) {
clog.Error("CollateralizeCreate.CheckExecTokenAccount", "fromaddr", action.fromaddr, "balance", create.TotalBalance, "error", types.ErrInsufficientBalance)
return nil, types.ErrInsufficientBalance
}
// 根据地址查找ID
collateralizeIDs, err := queryCollateralizeByAddr(action.localDB, action.fromaddr, pty.CollateralizeStatusCreated, "")
if err != nil && err != types.ErrNotFound {
clog.Error("CollateralizeCreate.queryCollateralizeByAddr", "addr", action.fromaddr, "error", err)
return nil, err
}
// 冻结ccny
receipt, err = action.tokenAccount.ExecFrozen(action.fromaddr, action.execaddr, create.TotalBalance)
if err != nil {
clog.Error("CollateralizeCreate.Frozen", "addr", action.fromaddr, "execaddr", action.execaddr, "amount", create.TotalBalance)
return nil, err
}
logs = append(logs, receipt.Logs...)
kv = append(kv, receipt.KV...)
var collateralizeID string
coll := &CollateralizeDB{}
if collateralizeIDs == nil {
collateralizeID = common.ToHex(action.txhash)
// 构造coll结构
coll.CollateralizeId = collateralizeID
coll.LiquidationRatio = collcfg.LiquidationRatio
coll.TotalBalance = create.TotalBalance
coll.DebtCeiling = collcfg.DebtCeiling
coll.StabilityFeeRatio = collcfg.StabilityFeeRatio
coll.Period = collcfg.Period
coll.Balance = create.TotalBalance
coll.CreateAddr = action.fromaddr
coll.Status = pty.CollateralizeActionCreate
coll.CollBalance = 0
} else {
collateralize, err := queryCollateralizeByID(action.db, collateralizeIDs[0])
if err != nil {
clog.Error("CollateralizeCreate.queryCollateralizeByID", "addr", action.fromaddr, "execaddr", action.execaddr, "collId", collateralizeIDs[0])
return nil, err
}
coll.Collateralize = *collateralize
coll.TotalBalance += create.TotalBalance
coll.Balance += create.TotalBalance
coll.PreStatus = coll.Status
}
clog.Debug("CollateralizeCreate created", "CollateralizeID", collateralizeID, "TotalBalance", create.TotalBalance)
// 保存
coll.Save(action.db)
kv = append(kv, coll.GetKVSet()...)
receiptLog := action.GetCreateReceiptLog(&coll.Collateralize)
logs = append(logs, receiptLog)
receipt = &types.Receipt{Ty: types.ExecOk, KV: kv, Logs: logs}
return receipt, nil
}
// 根据最近抵押物价格计算需要冻结的BTY数量
func getBtyNumToFrozen(value int64, price int64, ratio int64) (int64, error) {
if price == 0 {
clog.Error("Bty price should greate to 0")
return 0, pty.ErrPriceInvalid
}
btyValue := (value * 1e4) / (price * ratio)
return btyValue * 1e4, nil
}
// 计算清算价格
// value:借出ccny数量, colValue:抵押物数量, price:抵押物价格
func calcLiquidationPrice(value int64, colValue int64) int64 {
return (value * pty.CollateralizePreLiquidationRatio) / colValue
}
// 获取最近抵押物价格
func getLatestPrice(db dbm.KV) (int64, error) {
data, err := db.Get(PriceKey())
if err != nil {
clog.Error("getLatestPrice", "get", err)
return -1, err
}
var price pty.AssetPriceRecord
//decode
err = types.Decode(data, &price)
if err != nil {
clog.Error("getLatestPrice", "decode", err)
return -1, err
}
return price.BtyPrice, nil
}
// CheckExecAccountBalance 检查账户抵押物余额
func (action *Action) CheckExecAccountBalance(fromAddr string, ToFrozen, ToActive int64) bool {
acc := action.coinsAccount.LoadExecAccount(fromAddr, action.execaddr)
if acc.GetBalance() >= ToFrozen && acc.GetFrozen() >= ToActive {
return true
}
return false
}
// CheckExecAccount 检查账户token余额
func (action *Action) CheckExecTokenAccount(addr string, amount int64, isFrozen bool) bool {
acc := action.tokenAccount.LoadExecAccount(addr, action.execaddr)
if isFrozen {
if acc.GetFrozen() >= amount {
return true
}
} else {
if acc.GetBalance() >= amount {
return true
}
}
return false
}
// CollateralizeBorrow 用户质押bty借出ccny
func (action *Action) CollateralizeBorrow(borrow *pty.CollateralizeBorrow) (*types.Receipt, error) {
var logs []*types.ReceiptLog
var kv []*types.KeyValue
// 查找对应的借贷ID
collateralize, err := queryCollateralizeByID(action.db, borrow.CollateralizeId)
if err != nil {
clog.Error("CollateralizeBorrow.queryCollateralizeByID", "CollateralizeId", borrow.CollateralizeId, "error", err)
return nil, err
}
// 状态检查
if collateralize.Status == pty.CollateralizeStatusClose {
clog.Error("CollateralizeBorrow", "CollID", collateralize.CollateralizeId, "addr", action.fromaddr, "execaddr", action.execaddr, "status", collateralize.Status, "error", pty.ErrCollateralizeStatus)
return nil, pty.ErrCollateralizeStatus
}
coll := &CollateralizeDB{*collateralize}
// 借贷金额检查
if borrow.GetValue() <= 0 {
clog.Error("CollateralizeBorrow", "CollID", coll.CollateralizeId, "addr", action.fromaddr, "execaddr", action.execaddr, "borrow value", borrow.GetValue(), "error", types.ErrInvalidParam)
return nil, types.ErrAmount
}
// 借贷金额不超过个人限额
userBalance, _ := queryCollateralizeUserBalance(action.db, action.localDB, action.fromaddr)
if borrow.GetValue()+userBalance > coll.DebtCeiling {
clog.Error("CollateralizeBorrow", "CollID", coll.CollateralizeId, "addr", action.fromaddr, "execaddr", action.execaddr,
"borrow value", borrow.GetValue(), "current balance", userBalance, "error", pty.ErrCollateralizeExceedDebtCeiling)
return nil, pty.ErrCollateralizeExceedDebtCeiling
}
// 借贷金额不超过当前可借贷金额
if borrow.GetValue() > coll.Balance {
clog.Error("CollateralizeBorrow", "CollID", coll.CollateralizeId, "addr", action.fromaddr, "execaddr", action.execaddr, "borrow value", borrow.GetValue(), "error", pty.ErrCollateralizeLowBalance)
return nil, pty.ErrCollateralizeLowBalance
}
clog.Debug("CollateralizeBorrow", "value", borrow.GetValue())
// 获取抵押物价格
lastPrice, err := getLatestPrice(action.db)
if err != nil {
clog.Error("CollateralizeBorrow.getLatestPrice", "CollID", coll.CollateralizeId, "addr", action.fromaddr, "execaddr", action.execaddr, "error", err)
return nil, err
}
// 根据价格和需要借贷的金额,计算需要质押的抵押物数量
btyFrozen, err := getBtyNumToFrozen(borrow.GetValue(), lastPrice, coll.LiquidationRatio)
if err != nil {
clog.Error("CollateralizeBorrow.getBtyNumToFrozen", "CollID", coll.CollateralizeId, "addr", action.fromaddr, "execaddr", action.execaddr, "error", err)
return nil, err
}
// 检查抵押物账户余额
if !action.CheckExecAccountBalance(action.fromaddr, btyFrozen, 0) {
clog.Error("CollateralizeBorrow.CheckExecAccountBalance", "CollID", coll.CollateralizeId, "addr", action.fromaddr, "execaddr", action.execaddr, "balance", btyFrozen, "error", types.ErrNoBalance)
return nil, types.ErrNoBalance
}
// 抵押物转账
receipt, err := action.coinsAccount.ExecTransfer(action.fromaddr, coll.CreateAddr, action.execaddr, btyFrozen)
if err != nil {
clog.Error("CollateralizeBorrow.ExecTransfer", "addr", action.fromaddr, "execaddr", action.execaddr, "amount", btyFrozen)
return nil, err
}
logs = append(logs, receipt.Logs...)
kv = append(kv, receipt.KV...)
// 抵押物冻结
receipt, err = action.coinsAccount.ExecFrozen(coll.CreateAddr, action.execaddr, btyFrozen)
if err != nil {
clog.Error("CollateralizeBorrow.Frozen", "addr", coll.CreateAddr, "execaddr", action.execaddr, "amount", btyFrozen)
return nil, err
}
logs = append(logs, receipt.Logs...)
kv = append(kv, receipt.KV...)
// 借出ccny
receipt, err = action.tokenAccount.ExecTransferFrozen(coll.CreateAddr, action.fromaddr, action.execaddr, borrow.GetValue())
if err != nil {
clog.Error("CollateralizeBorrow.ExecTokenTransfer", "addr", action.fromaddr, "execaddr", action.execaddr, "amount", borrow.GetValue())
return nil, err
}
logs = append(logs, receipt.Logs...)
kv = append(kv, receipt.KV...)
// 构造借出记录
borrowRecord := &pty.BorrowRecord{}
borrowRecord.RecordId = common.ToHex(action.txhash)
borrowRecord.CollateralizeId = coll.CollateralizeId
borrowRecord.AccountAddr = action.fromaddr
borrowRecord.CollateralValue = btyFrozen
borrowRecord.StartTime = action.blocktime
borrowRecord.CollateralPrice = lastPrice
borrowRecord.DebtValue = borrow.GetValue()
borrowRecord.LiquidationPrice = (coll.LiquidationRatio * lastPrice * pty.CollateralizePreLiquidationRatio) / 1e8
borrowRecord.Status = pty.CollateralizeUserStatusCreate
borrowRecord.ExpireTime = action.blocktime + coll.Period
// 记录当前借贷的最高自动清算价格
if coll.LatestLiquidationPrice < borrowRecord.LiquidationPrice {
coll.LatestLiquidationPrice = borrowRecord.LiquidationPrice
}
// 保存
coll.BorrowRecords = append(coll.BorrowRecords, borrowRecord)
coll.Status = pty.CollateralizeStatusCreated
coll.Balance -= borrow.GetValue()
coll.CollBalance += btyFrozen
coll.LatestExpireTime = getLatestExpireTime(&coll.Collateralize)
coll.Save(action.db)
kv = append(kv, coll.GetKVSet()...)
receiptLog := action.GetBorrowReceiptLog(&coll.Collateralize, borrowRecord)
logs = append(logs, receiptLog)
receipt = &types.Receipt{Ty: types.ExecOk, KV: kv, Logs: logs}
return receipt, nil
}
// CollateralizeRepay 用户主动清算
func (action *Action) CollateralizeRepay(repay *pty.CollateralizeRepay) (*types.Receipt, error) {
var logs []*types.ReceiptLog
var kv []*types.KeyValue
var receipt *types.Receipt
// 找到相应的借贷
collateralize, err := queryCollateralizeByID(action.db, repay.CollateralizeId)
if err != nil {
clog.Error("CollateralizeRepay", "CollID", repay.CollateralizeId, "error", err)
return nil, err
}
coll := &CollateralizeDB{*collateralize}
// 状态检查
if coll.Status != pty.CollateralizeStatusCreated {
clog.Error("CollateralizeRepay", "CollID", repay.CollateralizeId, "addr", action.fromaddr, "execaddr", action.execaddr, "error", "status error", "Status", coll.Status)
return nil, pty.ErrCollateralizeStatus
}
// 查找借出记录
var borrowRecord *pty.BorrowRecord
var index int
for i, record := range coll.BorrowRecords {
if record.RecordId == repay.RecordId {
borrowRecord = record
index = i
break
}
}
if borrowRecord == nil {
clog.Error("CollateralizeRepay", "CollID", repay.CollateralizeId, "addr", action.fromaddr, "execaddr", action.execaddr, "error", "Can not find borrow record")
return nil, pty.ErrRecordNotExist
}
// 借贷金额+利息
fee := ((borrowRecord.DebtValue * coll.StabilityFeeRatio) / 1e8) * 1e4
realRepay := borrowRecord.DebtValue + fee
// 检查
if !action.CheckExecTokenAccount(action.fromaddr, realRepay, false) {
clog.Error("CollateralizeRepay.CheckExecTokenAccount", "CollID", coll.CollateralizeId, "addr", action.fromaddr, "execaddr", action.execaddr, "amount", realRepay, "error", types.ErrInsufficientBalance)
return nil, types.ErrNoBalance
}
// ccny转移
receipt, err = action.tokenAccount.ExecTransfer(action.fromaddr, coll.CreateAddr, action.execaddr, realRepay)
if err != nil {
clog.Error("CollateralizeRepay.ExecTokenTransfer", "addr", action.fromaddr, "execaddr", action.execaddr, "amount", realRepay)
return nil, err
}
logs = append(logs, receipt.Logs...)
kv = append(kv, receipt.KV...)
// ccny冻结
receipt, err = action.tokenAccount.ExecFrozen(coll.CreateAddr, action.execaddr, borrowRecord.DebtValue)
if err != nil {
clog.Error("CollateralizeCreate.Frozen", "addr", action.fromaddr, "execaddr", action.execaddr, "amount", borrowRecord.DebtValue)
return nil, err
}
logs = append(logs, receipt.Logs...)
kv = append(kv, receipt.KV...)
// 抵押物归还
receipt, err = action.coinsAccount.ExecTransferFrozen(coll.CreateAddr, action.fromaddr, action.execaddr, borrowRecord.CollateralValue)
if err != nil {
clog.Error("CollateralizeRepay.ExecTransferFrozen", "addr", coll.CreateAddr, "execaddr", action.execaddr, "amount", borrowRecord.CollateralValue)
return nil, err
}
logs = append(logs, receipt.Logs...)
kv = append(kv, receipt.KV...)
// 借贷记录关闭
borrowRecord.PreStatus = borrowRecord.Status
borrowRecord.Status = pty.CollateralizeUserStatusClose
// 保存
coll.Balance += borrowRecord.DebtValue
coll.CollBalance -= borrowRecord.CollateralValue
coll.BorrowRecords = append(coll.BorrowRecords[:index], coll.BorrowRecords[index+1:]...)
coll.InvalidRecords = append(coll.InvalidRecords, borrowRecord)
coll.LatestLiquidationPrice = getLatestLiquidationPrice(&coll.Collateralize)
coll.LatestExpireTime = getLatestExpireTime(&coll.Collateralize)
coll.Save(action.db)
kv = append(kv, coll.GetKVSet()...)
receiptLog := action.GetRepayReceiptLog(&coll.Collateralize, borrowRecord)
logs = append(logs, receiptLog)
receipt = &types.Receipt{Ty: types.ExecOk, KV: kv, Logs: logs}
return receipt, nil
}
// CollateralizeAppend 追加抵押物
func (action *Action) CollateralizeAppend(cAppend *pty.CollateralizeAppend) (*types.Receipt, error) {
var logs []*types.ReceiptLog
var kv []*types.KeyValue
// 参数检查
if cAppend.GetCollateralValue() <= 0 {
clog.Error("CollateralizeAppend", "addr", action.fromaddr, "execaddr", action.execaddr, "append value", cAppend.GetCollateralValue(), "error", types.ErrAmount)
return nil, types.ErrAmount
}
// 查找对应的借贷ID
collateralize, err := queryCollateralizeByID(action.db, cAppend.CollateralizeId)
if err != nil {
clog.Error("CollateralizeAppend", "CollateralizeId", cAppend.CollateralizeId, "error", err)
return nil, err
}
coll := &CollateralizeDB{*collateralize}
// 状态检查
if coll.Status != pty.CollateralizeStatusCreated {
clog.Error("CollateralizeAppend", "CollID", coll.CollateralizeId, "addr", action.fromaddr, "execaddr", action.execaddr, "status", coll.Status, "error", pty.ErrCollateralizeStatus)
return nil, pty.ErrCollateralizeStatus
}
// 查找借出记录
var borrowRecord *pty.BorrowRecord
for _, record := range coll.BorrowRecords {
if record.RecordId == cAppend.RecordId {
borrowRecord = record
}
}
if borrowRecord == nil {
clog.Error("CollateralizeAppend", "CollID", cAppend.CollateralizeId, "addr", action.fromaddr, "execaddr", action.execaddr, "error", "Can not find borrow record")
return nil, pty.ErrRecordNotExist
}
clog.Debug("CollateralizeAppend", "value", cAppend.CollateralValue)
// 获取抵押物价格
lastPrice, err := getLatestPrice(action.db)
if err != nil {
clog.Error("CollateralizeBorrow", "CollID", coll.CollateralizeId, "addr", action.fromaddr, "execaddr", action.execaddr, "error", err)
return nil, err
}
// 检查抵押物账户余额
if !action.CheckExecAccountBalance(action.fromaddr, cAppend.CollateralValue, 0) {
clog.Error("CollateralizeBorrow.CheckExecAccountBalance", "CollID", coll.CollateralizeId, "addr", action.fromaddr, "execaddr", action.execaddr, "amount", cAppend.CollateralValue, "error", types.ErrNoBalance)
return nil, types.ErrNoBalance
}
// 抵押物转账
receipt, err := action.coinsAccount.ExecTransfer(action.fromaddr, coll.CreateAddr, action.execaddr, cAppend.CollateralValue)
if err != nil {
clog.Error("CollateralizeBorrow.ExecTransfer", "addr", action.fromaddr, "execaddr", action.execaddr, "amount", cAppend.CollateralValue, "error", err)
return nil, err
}
logs = append(logs, receipt.Logs...)
kv = append(kv, receipt.KV...)
// 抵押物冻结
receipt, err = action.coinsAccount.ExecFrozen(coll.CreateAddr, action.execaddr, cAppend.CollateralValue)
if err != nil {
clog.Error("CollateralizeBorrow.Frozen", "addr", coll.CreateAddr, "execaddr", action.execaddr, "amount", cAppend.CollateralValue, "error", err)
return nil, err
}
logs = append(logs, receipt.Logs...)
kv = append(kv, receipt.KV...)
// 构造借出记录
borrowRecord.CollateralValue += cAppend.CollateralValue
borrowRecord.CollateralPrice = lastPrice
borrowRecord.LiquidationPrice = calcLiquidationPrice(borrowRecord.DebtValue, borrowRecord.CollateralValue)
if borrowRecord.LiquidationPrice*PriceWarningRate < lastPrice {
// 告警解除
if borrowRecord.Status == pty.CollateralizeUserStatusWarning {
borrowRecord.PreStatus = borrowRecord.Status
borrowRecord.Status = pty.CollateralizeStatusCreated
}
}
// 记录当前借贷的最高自动清算价格
coll.CollBalance += cAppend.CollateralValue
coll.LatestLiquidationPrice = getLatestLiquidationPrice(&coll.Collateralize)
coll.LatestExpireTime = getLatestExpireTime(&coll.Collateralize)
// append操作不更新Index
coll.Save(action.db)
kv = append(kv, coll.GetKVSet()...)
receiptLog := action.GetAppendReceiptLog(&coll.Collateralize, borrowRecord)
logs = append(logs, receiptLog)
receipt = &types.Receipt{Ty: types.ExecOk, KV: kv, Logs: logs}
return receipt, nil
}
func getManageKey(key string, db dbm.KV) ([]byte, error) {
manageKey := types.ManageKey(key)
value, err := db.Get([]byte(manageKey))
if err != nil {
return nil, err
}
return value, nil
}
func isRightAddr(key string, addr string, db dbm.KV) bool {
value, err := getManageKey(key, db)
if err != nil {
clog.Error("isRightAddr", "Key", key)
return false
}
if value == nil {
clog.Error("isRightAddr", "key", key, "error", "Found key nil value")
return false
}
var item types.ConfigItem
err = types.Decode(value, &item)
if err != nil {
clog.Error("isRightAddr", "Decode", value)
return false
}
for _, op := range item.GetArr().Value {
if op == addr {
return true
}
}
return false
}
func getGuarantorAddr(db dbm.KV) (string, error) {
value, err := getManageKey(issuanceE.GuarantorKey, db)
if err != nil {
clog.Error("CollateralizePriceFeed", "getGuarantorAddr", err)
return "", err
}
if value == nil {
clog.Error("CollateralizePriceFeed guarantorKey found nil value")
return "", err
}
var item types.ConfigItem
err = types.Decode(value, &item)
if err != nil {
clog.Error("CollateralizePriceFeed", "getGuarantorAddr", err)
return "", err
}
return item.GetArr().Value[0], nil
}
// 系统清算
func (action *Action) systemLiquidation(coll *pty.Collateralize, price int64) (*types.Receipt, error) {
var logs []*types.ReceiptLog
var kv []*types.KeyValue
for index, borrowRecord := range coll.BorrowRecords {
if (borrowRecord.LiquidationPrice*PriceWarningRate)/1e4 < price {
// 价格恢复,告警记录恢复
if borrowRecord.Status == pty.CollateralizeUserStatusWarning {
borrowRecord.PreStatus = borrowRecord.Status
borrowRecord.Status = pty.CollateralizeUserStatusCreate
log := action.GetFeedReceiptLog(coll, borrowRecord)
logs = append(logs, log)
}
continue
}
// 价格低于清算线,记录清算
if borrowRecord.LiquidationPrice >= price {
getGuarantorAddr, err := getGuarantorAddr(action.db)
if err != nil {
if err != nil {
clog.Error("systemLiquidation", "getGuarantorAddr", err)
continue
}
}
// 抵押物转移
receipt, err := action.coinsAccount.ExecTransferFrozen(coll.CreateAddr, getGuarantorAddr, action.execaddr, borrowRecord.CollateralValue)
if err != nil {
clog.Error("systemLiquidation", "addr", action.fromaddr, "execaddr", action.execaddr, "amount", borrowRecord.CollateralValue, "error", err)
continue
}
logs = append(logs, receipt.Logs...)
kv = append(kv, receipt.KV...)
// 借贷记录清算
borrowRecord.LiquidateTime = action.blocktime
borrowRecord.PreStatus = borrowRecord.Status
borrowRecord.Status = pty.CollateralizeUserStatusSystemLiquidate
coll.InvalidRecords = append(coll.InvalidRecords, borrowRecord)
coll.BorrowRecords = append(coll.BorrowRecords[:index], coll.BorrowRecords[index+1:]...)
coll.CollBalance -= borrowRecord.CollateralValue
log := action.GetFeedReceiptLog(coll, borrowRecord)
logs = append(logs, log)
continue
}
// 价格高于清算线,且还不处于告警状态,记录告警
if borrowRecord.Status != pty.CollateralizeUserStatusWarning {
borrowRecord.PreStatus = borrowRecord.Status
borrowRecord.Status = pty.CollateralizeUserStatusWarning
log := action.GetFeedReceiptLog(coll, borrowRecord)
logs = append(logs, log)
}
}
// 保存
coll.LatestLiquidationPrice = getLatestLiquidationPrice(coll)
coll.LatestExpireTime = getLatestExpireTime(coll)
collDB := &CollateralizeDB{*coll}
collDB.Save(action.db)
kv = append(kv, collDB.GetKVSet()...)
receipt := &types.Receipt{Ty: types.ExecOk, KV: kv, Logs: logs}
return receipt, nil
}
// 超时清算
func (action *Action) expireLiquidation(coll *pty.Collateralize) (*types.Receipt, error) {
var logs []*types.ReceiptLog
var kv []*types.KeyValue
for index, borrowRecord := range coll.BorrowRecords {
if borrowRecord.ExpireTime-ExpireWarningTime > action.blocktime {
continue
}
// 超过超时时间,记录清算
if borrowRecord.ExpireTime <= action.blocktime {
getGuarantorAddr, err := getGuarantorAddr(action.db)
if err != nil {
if err != nil {
clog.Error("systemLiquidation", "getGuarantorAddr", err)
continue
}
}
// 抵押物转移
receipt, err := action.coinsAccount.ExecTransferFrozen(coll.CreateAddr, getGuarantorAddr, action.execaddr, borrowRecord.CollateralValue)
if err != nil {
clog.Error("systemLiquidation", "addr", action.fromaddr, "execaddr", action.execaddr, "amount", borrowRecord.CollateralValue, "error", err)
continue
}
logs = append(logs, receipt.Logs...)
kv = append(kv, receipt.KV...)
// 借贷记录清算
borrowRecord.LiquidateTime = action.blocktime
borrowRecord.PreStatus = borrowRecord.Status
borrowRecord.Status = pty.CollateralizeUserStatusExpireLiquidate
coll.InvalidRecords = append(coll.InvalidRecords, borrowRecord)
coll.BorrowRecords = append(coll.BorrowRecords[:index], coll.BorrowRecords[index+1:]...)
coll.CollBalance -= borrowRecord.CollateralValue
log := action.GetFeedReceiptLog(coll, borrowRecord)
logs = append(logs, log)
continue
}
// 还没记录超时告警,记录告警
if borrowRecord.Status != pty.CollateralizeUserStatusExpire {
borrowRecord.PreStatus = borrowRecord.Status
borrowRecord.Status = pty.CollateralizeUserStatusExpire
log := action.GetFeedReceiptLog(coll, borrowRecord)
logs = append(logs, log)
}
}
// 保存
coll.LatestLiquidationPrice = getLatestLiquidationPrice(coll)
coll.LatestExpireTime = getLatestExpireTime(coll)
collDB := &CollateralizeDB{*coll}
collDB.Save(action.db)
kv = append(kv, collDB.GetKVSet()...)
receipt := &types.Receipt{Ty: types.ExecOk, KV: kv, Logs: logs}
return receipt, nil
}
// 价格计算策略
func pricePolicy(feed *pty.CollateralizeFeed) int64 {
var totalPrice int64
var totalVolume int64
for _, volume := range feed.Volume {
totalVolume += volume
}
if totalVolume == 0 {
clog.Error("collateralize price feed volume empty")
return 0
}
for i, price := range feed.Price {
totalPrice += (price * feed.Volume[i]) / totalVolume
}
return totalPrice
}
// CollateralizeFeed 喂价
func (action *Action) CollateralizeFeed(feed *pty.CollateralizeFeed) (*types.Receipt, error) {
var logs []*types.ReceiptLog
var kv []*types.KeyValue
if feed == nil || len(feed.Price) == 0 || len(feed.Price) != len(feed.Volume) {
clog.Error("CollateralizePriceFeed", types.ErrInvalidParam)
return nil, types.ErrInvalidParam
}
// 是否后台管理用户
if !isRightAddr(issuanceE.PriceFeedKey, action.fromaddr, action.db) {
clog.Error("CollateralizePriceFeed", "addr", action.fromaddr, "error", "Address has no permission to feed price")
return nil, pty.ErrPermissionDeny
}
price := pricePolicy(feed)
if price <= 0 {
clog.Error("CollateralizePriceFeed", "price", price, "error", pty.ErrPriceInvalid)
return nil, pty.ErrPriceInvalid
}
ids, err := queryCollateralizeByStatus(action.localDB, pty.CollateralizeStatusCreated, "")
if err != nil {
clog.Debug("CollateralizePriceFeed", "get collateralize record error", err)
}
for _, collID := range ids {
coll, err := queryCollateralizeByID(action.db, collID)
if err != nil {
clog.Error("CollateralizePriceFeed", "Collateralize ID", coll.CollateralizeId, "get collateralize record by id error", err)
continue
}
// 超时清算判断
if coll.LatestExpireTime-ExpireWarningTime <= action.blocktime {
receipt, err := action.expireLiquidation(coll)
if err != nil {
clog.Error("CollateralizePriceFeed", "Collateralize ID", coll.CollateralizeId, "expire liquidation error", err)
continue
}
logs = append(logs, receipt.Logs...)
kv = append(kv, receipt.KV...)
}
// 系统清算判断
receipt, err := action.systemLiquidation(coll, price)
if err != nil {
clog.Error("CollateralizePriceFeed", "Collateralize ID", coll.CollateralizeId, "system liquidation error", err)
continue
}
logs = append(logs, receipt.Logs...)
kv = append(kv, receipt.KV...)
}
var priceRecord pty.AssetPriceRecord
priceRecord.BtyPrice = price
priceRecord.RecordTime = action.blocktime
// 最近喂价记录
pricekv := &types.KeyValue{Key: PriceKey(), Value: types.Encode(&priceRecord)}
action.db.Set(pricekv.Key, pricekv.Value)
kv = append(kv, pricekv)
receipt := &types.Receipt{Ty: types.ExecOk, KV: kv, Logs: logs}
return receipt, nil
}
// CollateralizeRetrieve 收回未放贷
func (action *Action) CollateralizeRetrieve(retrieve *pty.CollateralizeRetrieve) (*types.Receipt, error) {
var logs []*types.ReceiptLog
var kv []*types.KeyValue
var receipt *types.Receipt
collateralize, err := queryCollateralizeByID(action.db, retrieve.CollateralizeId)
if err != nil {
clog.Error("CollateralizeRetrieve", "CollateralizeId", retrieve.CollateralizeId, "error", err)
return nil, err
}
if action.fromaddr != collateralize.CreateAddr {
clog.Error("CollateralizeRetrieve", "CollateralizeId", retrieve.CollateralizeId, "error", "account error", "create", collateralize.CreateAddr, "from", action.fromaddr)
return nil, pty.ErrPermissionDeny
}
// 收回金额不能大于待放出金额
if retrieve.Balance > collateralize.Balance {
clog.Error("CollateralizeRetrieve", "CollateralizeId", retrieve.CollateralizeId, "error", "balance error", "retrieve balance", retrieve.Balance, "available balance", collateralize.Balance)
return nil, types.ErrAmount
}
// 解冻ccny
receipt, err = action.tokenAccount.ExecActive(action.fromaddr, action.execaddr, retrieve.Balance)
if err != nil {
clog.Error("IssuanceClose.ExecActive", "addr", action.fromaddr, "execaddr", action.execaddr, "balance", retrieve.Balance)
return nil, err
}
logs = append(logs, receipt.Logs...)
kv = append(kv, receipt.KV...)
clog.Debug("CollateralizeRetrieve", "ID", retrieve.CollateralizeId, "balance", retrieve.Balance)
coll := &CollateralizeDB{*collateralize}
coll.TotalBalance -= retrieve.Balance
coll.Balance -= retrieve.Balance
coll.PreStatus = coll.Status
if coll.TotalBalance == 0 {
coll.Status = pty.CollateralizeStatusClose
}
coll.Save(action.db)
kv = append(kv, coll.GetKVSet()...)
receiptLog := action.GetRetrieveReceiptLog(&coll.Collateralize)
logs = append(logs, receiptLog)
return &types.Receipt{Ty: types.ExecOk, KV: kv, Logs: logs}, nil
}
// 查找借贷
func queryCollateralizeByID(db dbm.KV, collateralizeID string) (*pty.Collateralize, error) {
data, err := db.Get(Key(collateralizeID))
if err != nil {
clog.Debug("queryCollateralizeByID", "error", err)
return nil, err
}
var coll pty.Collateralize
err = types.Decode(data, &coll)
if err != nil {
clog.Debug("queryCollateralizeByID", "decode", err)
return nil, err
}
return &coll, nil
}
func queryCollateralizeByStatus(localdb dbm.KVDB, status int32, collID string) ([]string, error) {
query := pty.NewCollateralizeTable(localdb).GetQuery(localdb)
var primary []byte
if len(collID) > 0 {
primary = []byte(collID)
}
var data = &pty.ReceiptCollateralize{
CollateralizeId: collID,
Status: status,
}
rows, err := query.List("status", data, primary, DefaultCount, ListDESC)
if err != nil {
clog.Debug("queryCollateralizeByStatus.List", "error", err)
return nil, err
}
var ids []string
for _, row := range rows {
ids = append(ids, string(row.Primary))
}
return ids, nil
}
func queryCollateralizeByAddr(localdb dbm.KVDB, addr string, status int32, collID string) ([]string, error) {
query := pty.NewCollateralizeTable(localdb).GetQuery(localdb)
var primary []byte
if len(collID) > 0 {
primary = []byte(collID)
}
var data = &pty.ReceiptCollateralize{
CollateralizeId: collID,
Status: status,
AccountAddr: addr,
}
var rows []*table.Row
var err error
if status == 0 {
rows, err = query.List("addr", data, primary, DefaultCount, ListDESC)
if err != nil {
clog.Debug("queryCollateralizeByAddr.List", "index", "addr", "error", err)
return nil, err
}
} else {
rows, err = query.List("addr_status", data, primary, DefaultCount, ListDESC)
if err != nil {
clog.Debug("queryCollateralizeByAddr.List", "index", "addr_status", "error", err)
return nil, err
}
}
var ids []string
for _, row := range rows {
ids = append(ids, string(row.Primary))
}
return ids, nil
}
// 精确查找发行记录
func queryCollateralizeRecordByID(db dbm.KV, collateralizeID string, recordID string) (*pty.BorrowRecord, error) {
coll, err := queryCollateralizeByID(db, collateralizeID)
if err != nil {
clog.Debug("queryCollateralizeRecordByID", "error", err)
return nil, err
}
for _, record := range coll.BorrowRecords {
if record.RecordId == recordID {
return record, nil
}
}
for _, record := range coll.InvalidRecords {
if record.RecordId == recordID {
return record, nil
}
}
return nil, types.ErrNotFound
}
func queryCollateralizeRecordByAddr(db dbm.KV, localdb dbm.KVDB, addr string, status int32, collID string, recordID string) ([]*pty.BorrowRecord, error) {
query := pty.NewRecordTable(localdb).GetQuery(localdb)
var primary []byte
if len(recordID) > 0 {
primary = []byte(recordID)
}
var data = &pty.ReceiptCollateralize{
AccountAddr: addr,
Status: status,
CollateralizeId: collID,
}
var rows []*table.Row
var err error
if len(collID) != 0 {
rows, err = query.List("id_addr", data, primary, DefaultCount, ListDESC)
if err != nil {
clog.Debug("queryCollateralizeRecordByAddr.List", "index", "id_addr", "error", err)
return nil, err
}
} else if status != 0 {
rows, err = query.List("addr_status", data, primary, DefaultCount, ListDESC)
if err != nil {
clog.Debug("queryCollateralizeRecordByAddr.List", "index", "addr_status", "error", err)
return nil, err
}
} else {
rows, err = query.List("addr", data, primary, DefaultCount, ListDESC)
if err != nil {
clog.Debug("queryCollateralizeRecordByAddr.List", "index", "addr", "error", err)
return nil, err
}
}
var records []*pty.BorrowRecord
for _, row := range rows {
record, err := queryCollateralizeRecordByID(db, row.Data.(*pty.ReceiptCollateralize).CollateralizeId, row.Data.(*pty.ReceiptCollateralize).RecordId)
if err != nil {
clog.Debug("queryCollateralizeRecordByAddr.queryCollateralizeRecordByID", "error", err)
continue
}
records = append(records, record)
}
return records, nil
}
func queryCollateralizeRecordByStatus(db dbm.KV, localdb dbm.KVDB, status int32, collID string, recordID string) ([]*pty.BorrowRecord, error) {
query := pty.NewRecordTable(localdb).GetQuery(localdb)
var primary []byte
if len(recordID) > 0 {
primary = []byte(recordID)
}
var data = &pty.ReceiptCollateralize{
Status: status,
CollateralizeId: collID,
}
var rows []*table.Row
var err error
if len(collID) == 0 {
rows, err = query.List("status", data, primary, DefaultCount, ListDESC)
if err != nil {
clog.Debug("queryCollateralizeRecordByStatus.List", "index", "status", "error", err)
return nil, err
}
} else {
rows, err = query.List("id_status", data, primary, DefaultCount, ListDESC)
if err != nil {
clog.Debug("queryCollateralizeRecordByStatus.List", "index", "id_status", "error", err)
return nil, err
}
}
var records []*pty.BorrowRecord
for _, row := range rows {
record, err := queryCollateralizeRecordByID(db, row.Data.(*pty.ReceiptCollateralize).CollateralizeId, row.Data.(*pty.ReceiptCollateralize).RecordId)
if err != nil {
clog.Debug("queryCollateralizeRecordByStatus.queryCollateralizeRecordByID", "error", err)
continue
}
records = append(records, record)
}
return records, nil
}
func queryCollateralizeUserBalanceStatus(db dbm.KV, localdb dbm.KVDB, addr string, status int32) (int64, error) {
var totalBalance int64
query := pty.NewRecordTable(localdb).GetQuery(localdb)
var primary []byte
var data = &pty.ReceiptCollateralize{
AccountAddr: addr,
Status: status,
}
var rows []*table.Row
var err error
for {
rows, err = query.List("addr_status", data, primary, DefaultCount, ListDESC)
if err != nil {
return -1, err
}
for _, row := range rows {
record, err := queryCollateralizeRecordByID(db, row.Data.(*pty.ReceiptCollateralize).CollateralizeId, row.Data.(*pty.ReceiptCollateralize).RecordId)
if err != nil {
continue
}
totalBalance += record.DebtValue
}
if len(rows) < int(DefaultCount) {
break
}
primary = []byte(rows[DefaultCount-1].Data.(*pty.ReceiptCollateralize).RecordId)
}
return totalBalance, nil
}
func queryCollateralizeUserBalance(db dbm.KV, localdb dbm.KVDB, addr string) (int64, error) {
var totalBalance int64
balance, err := queryCollateralizeUserBalanceStatus(db, localdb, addr, pty.CollateralizeUserStatusCreate)
if err != nil {
if err != types.ErrNotFound {
clog.Error("queryCollateralizeUserBalance", "err", err)
}
} else {
totalBalance += balance
}
balance, err = queryCollateralizeUserBalanceStatus(db, localdb, addr, pty.CollateralizeUserStatusWarning)
if err != nil {
if err != types.ErrNotFound {
clog.Error("queryCollateralizeUserBalance", "err", err)
}
} else {
totalBalance += balance
}
balance, err = queryCollateralizeUserBalanceStatus(db, localdb, addr, pty.CollateralizeUserStatusExpire)
if err != nil {
if err != types.ErrNotFound {
clog.Error("queryCollateralizeUserBalance", "err", err)
}
} else {
totalBalance += balance
}
return totalBalance, nil
}
// Copyright Fuzamei Corp. 2018 All Rights Reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package executor
/*
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
// 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."+CollateralizeX)
)
func init() {
types.AllowUserExec = append(types.AllowUserExec, []byte(CollateralizeX))
types.RegFork(CollateralizeX, InitFork)
types.RegExec(CollateralizeX, InitExecutor)
}
func InitFork(cfg *types.Chain33Config) {
cfg.RegisterDappFork(CollateralizeX, "Enable", 0)
}
func InitExecutor(cfg *types.Chain33Config) {
types.RegistorExecutor(CollateralizeX, NewType(cfg))
}
// CollateralizeType def
type CollateralizeType struct {
types.ExecTypeBase
}
// NewType method
func NewType(cfg *types.Chain33Config) *CollateralizeType {
c := &CollateralizeType{}
c.SetChild(c)
c.SetConfig(cfg)
return c
}
// GetName 获取执行器名称
func (collateralize *CollateralizeType) GetName() string {
return CollateralizeX
}
// GetLogMap method
func (collateralize *CollateralizeType) GetLogMap() map[int64]*types.LogInfo {
return map[int64]*types.LogInfo{
TyLogCollateralizeCreate: {Ty: reflect.TypeOf(ReceiptCollateralize{}), Name: "LogCollateralizeCreate"},
TyLogCollateralizeBorrow: {Ty: reflect.TypeOf(ReceiptCollateralize{}), Name: "LogCollateralizeBorrow"},
TyLogCollateralizeRepay: {Ty: reflect.TypeOf(ReceiptCollateralize{}), Name: "LogCollateralizeRepay"},
TyLogCollateralizeAppend: {Ty: reflect.TypeOf(ReceiptCollateralize{}), Name: "LogCollateralizeAppend"},
TyLogCollateralizeFeed: {Ty: reflect.TypeOf(ReceiptCollateralize{}), Name: "LogCollateralizeFeed"},
TyLogCollateralizeRetrieve: {Ty: reflect.TypeOf(ReceiptCollateralize{}), Name: "LogCollateralizeRetrieve"},
}
}
// GetPayload method
func (collateralize *CollateralizeType) GetPayload() types.Message {
return &CollateralizeAction{}
}
// CreateTx method
func (collateralize CollateralizeType) CreateTx(action string, message json.RawMessage) (*types.Transaction, error) {
llog.Debug("Collateralize.CreateTx", "action", action)
cfg := collateralize.GetConfig()
if action == "CollateralizeCreate" {
var param CollateralizeCreateTx
err := json.Unmarshal(message, &param)
if err != nil {
llog.Error("CreateTx", "Error", err)
return nil, types.ErrInvalidParam
}
return CreateRawCollateralizeCreateTx(cfg, &param)
} else if action == "CollateralizeBorrow" {
var param CollateralizeBorrowTx
err := json.Unmarshal(message, &param)
if err != nil {
llog.Error("CreateTx", "Error", err)
return nil, types.ErrInvalidParam
}
return CreateRawCollateralizeBorrowTx(cfg, &param)
} else if action == "CollateralizeRepay" {
var param CollateralizeRepayTx
err := json.Unmarshal(message, &param)
if err != nil {
llog.Error("CreateTx", "Error", err)
return nil, types.ErrInvalidParam
}
return CreateRawCollateralizeRepayTx(cfg, &param)
} else if action == "CollateralizeAppend" {
var param CollateralizeAppendTx
err := json.Unmarshal(message, &param)
if err != nil {
llog.Error("CreateTx", "Error", err)
return nil, types.ErrInvalidParam
}
return CreateRawCollateralizeAppendTx(cfg, &param)
} else if action == "CollateralizePriceFeed" {
var param CollateralizeFeedTx
err := json.Unmarshal(message, &param)
if err != nil {
llog.Error("CreateTx", "Error", err)
return nil, types.ErrInvalidParam
}
return CreateRawCollateralizeFeedTx(cfg, &param)
} else if action == "CollateralizeRetrieve" {
var param CollateralizeRetrieveTx
err := json.Unmarshal(message, &param)
if err != nil {
llog.Error("CreateTx", "Error", err)
return nil, types.ErrInvalidParam
}
return CreateRawCollateralizeRetrieveTx(cfg, &param)
} else if action == "CollateralizeManage" {
var param CollateralizeManageTx
err := json.Unmarshal(message, &param)
if err != nil {
llog.Error("CreateTx", "Error", err)
return nil, types.ErrInvalidParam
}
return CreateRawCollateralizeManageTx(cfg, &param)
} else {
return nil, types.ErrNotSupport
}
}
// GetTypeMap method
func (collateralize CollateralizeType) GetTypeMap() map[string]int32 {
return map[string]int32{
"Create": CollateralizeActionCreate,
"Borrow": CollateralizeActionBorrow,
"Repay": CollateralizeActionRepay,
"Append": CollateralizeActionAppend,
"Feed": CollateralizeActionFeed,
"Retrieve": CollateralizeActionRetrieve,
"Manage": CollateralizeActionManage,
}
}
// CreateRawCollateralizeCreateTx method
func CreateRawCollateralizeCreateTx(cfg *types.Chain33Config, parm *CollateralizeCreateTx) (*types.Transaction, error) {
if parm == nil {
llog.Error("CreateRawCollateralizeCreateTx", "parm", parm)
return nil, types.ErrInvalidParam
}
v := &CollateralizeCreate{
TotalBalance: int64(math.Trunc((parm.TotalBalance+0.0000001)*1e4)) * 1e4,
}
create := &CollateralizeAction{
Ty: CollateralizeActionCreate,
Value: &CollateralizeAction_Create{v},
}
tx := &types.Transaction{
Execer: []byte(cfg.ExecName(CollateralizeX)),
Payload: types.Encode(create),
Fee: parm.Fee,
To: address.ExecAddress(cfg.ExecName(CollateralizeX)),
}
name := cfg.ExecName(CollateralizeX)
tx, err := types.FormatTx(cfg, name, tx)
if err != nil {
return nil, err
}
return tx, nil
}
// CreateRawCollateralizeBorrowTx method
func CreateRawCollateralizeBorrowTx(cfg *types.Chain33Config, parm *CollateralizeBorrowTx) (*types.Transaction, error) {
if parm == nil {
llog.Error("CreateRawCollateralizeBorrowTx", "parm", parm)
return nil, types.ErrInvalidParam
}
v := &CollateralizeBorrow{
CollateralizeId: parm.CollateralizeID,
Value: int64(math.Trunc((parm.Value+0.0000001)*1e4)) * 1e4,
}
borrow := &CollateralizeAction{
Ty: CollateralizeActionBorrow,
Value: &CollateralizeAction_Borrow{v},
}
tx := &types.Transaction{
Execer: []byte(cfg.ExecName(CollateralizeX)),
Payload: types.Encode(borrow),
Fee: parm.Fee,
To: address.ExecAddress(cfg.ExecName(CollateralizeX)),
}
name := cfg.ExecName(CollateralizeX)
tx, err := types.FormatTx(cfg, name, tx)
if err != nil {
return nil, err
}
return tx, nil
}
// CreateRawCollateralizeRepayTx method
func CreateRawCollateralizeRepayTx(cfg *types.Chain33Config, parm *CollateralizeRepayTx) (*types.Transaction, error) {
if parm == nil {
llog.Error("CreateRawCollateralizeRepayTx", "parm", parm)
return nil, types.ErrInvalidParam
}
v := &CollateralizeRepay{
CollateralizeId: parm.CollateralizeID,
RecordId: parm.RecordID,
}
repay := &CollateralizeAction{
Ty: CollateralizeActionRepay,
Value: &CollateralizeAction_Repay{v},
}
tx := &types.Transaction{
Execer: []byte(cfg.ExecName(CollateralizeX)),
Payload: types.Encode(repay),
Fee: parm.Fee,
To: address.ExecAddress(cfg.ExecName(CollateralizeX)),
}
name := cfg.ExecName(CollateralizeX)
tx, err := types.FormatTx(cfg, name, tx)
if err != nil {
return nil, err
}
return tx, nil
}
// CreateRawCollateralizeAppendTx method
func CreateRawCollateralizeAppendTx(cfg *types.Chain33Config, parm *CollateralizeAppendTx) (*types.Transaction, error) {
if parm == nil {
llog.Error("CreateRawCollateralizeAppendTx", "parm", parm)
return nil, types.ErrInvalidParam
}
v := &CollateralizeAppend{
CollateralizeId: parm.CollateralizeID,
RecordId: parm.RecordID,
CollateralValue: int64(math.Trunc((parm.Value+0.0000001)*1e4)) * 1e4,
}
append := &CollateralizeAction{
Ty: CollateralizeActionAppend,
Value: &CollateralizeAction_Append{v},
}
tx := &types.Transaction{
Execer: []byte(cfg.ExecName(CollateralizeX)),
Payload: types.Encode(append),
Fee: parm.Fee,
To: address.ExecAddress(cfg.ExecName(CollateralizeX)),
}
name := cfg.ExecName(CollateralizeX)
tx, err := types.FormatTx(cfg, name, tx)
if err != nil {
return nil, err
}
return tx, nil
}
// CreateRawCollateralizeFeedTx method
func CreateRawCollateralizeFeedTx(cfg *types.Chain33Config, parm *CollateralizeFeedTx) (*types.Transaction, error) {
if parm == nil {
llog.Error("CreateRawCollateralizePriceFeedTx", "parm", parm)
return nil, types.ErrInvalidParam
}
v := &CollateralizeFeed{
Volume: parm.Volume,
}
for _, r := range parm.Price {
v.Price = append(v.Price, int64(math.Trunc(r*1e4)))
}
feed := &CollateralizeAction{
Ty: CollateralizeActionFeed,
Value: &CollateralizeAction_Feed{v},
}
tx := &types.Transaction{
Execer: []byte(cfg.ExecName(CollateralizeX)),
Payload: types.Encode(feed),
Fee: parm.Fee,
To: address.ExecAddress(cfg.ExecName(CollateralizeX)),
}
name := cfg.ExecName(CollateralizeX)
tx, err := types.FormatTx(cfg, name, tx)
if err != nil {
return nil, err
}
return tx, nil
}
// CreateRawCollateralizeRetrieveTx method
func CreateRawCollateralizeRetrieveTx(cfg *types.Chain33Config, parm *CollateralizeRetrieveTx) (*types.Transaction, error) {
if parm == nil {
llog.Error("CreateRawCollateralizeCloseTx", "parm", parm)
return nil, types.ErrInvalidParam
}
v := &CollateralizeRetrieve{
CollateralizeId: parm.CollateralizeID,
Balance: int64(math.Trunc((parm.Balance+0.0000001)*1e4)) * 1e4,
}
close := &CollateralizeAction{
Ty: CollateralizeActionRetrieve,
Value: &CollateralizeAction_Retrieve{v},
}
tx := &types.Transaction{
Execer: []byte(cfg.ExecName(CollateralizeX)),
Payload: types.Encode(close),
Fee: parm.Fee,
To: address.ExecAddress(cfg.ExecName(CollateralizeX)),
}
name := cfg.ExecName(CollateralizeX)
tx, err := types.FormatTx(cfg, name, tx)
if err != nil {
return nil, err
}
return tx, nil
}
// CreateRawCollateralizeManageTx method
func CreateRawCollateralizeManageTx(cfg *types.Chain33Config, parm *CollateralizeManageTx) (*types.Transaction, error) {
if parm == nil {
llog.Error("CreateRawCollateralizeManageTx", "parm", parm)
return nil, types.ErrInvalidParam
}
v := &CollateralizeManage{
DebtCeiling: int64(math.Trunc((parm.DebtCeiling+0.0000001)*1e4)) * 1e4,
LiquidationRatio: int64(math.Trunc((parm.LiquidationRatio + 0.0000001) * 1e4)),
StabilityFeeRatio: int64(math.Trunc((parm.StabilityFeeRatio + 0.0000001) * 1e4)),
Period: parm.Period,
TotalBalance: int64(math.Trunc((parm.TotalBalance+0.0000001)*1e4)) * 1e4,
}
manage := &CollateralizeAction{
Ty: CollateralizeActionManage,
Value: &CollateralizeAction_Manage{v},
}
tx := &types.Transaction{
Execer: []byte(cfg.ExecName(CollateralizeX)),
Payload: types.Encode(manage),
Fee: parm.Fee,
To: address.ExecAddress(cfg.ExecName(CollateralizeX)),
}
name := cfg.ExecName(CollateralizeX)
tx, err := types.FormatTx(cfg, name, tx)
if err != nil {
return nil, err
}
return tx, nil
}
// Code generated by protoc-gen-go. DO NOT EDIT.
// source: collateralize.proto
package types
import (
fmt "fmt"
proto "github.com/golang/protobuf/proto"
math "math"
)
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
// 放贷信息
type Collateralize struct {
CollateralizeId string `protobuf:"bytes,1,opt,name=collateralizeId,proto3" json:"collateralizeId,omitempty"`
TotalBalance int64 `protobuf:"varint,2,opt,name=totalBalance,proto3" json:"totalBalance,omitempty"`
DebtCeiling int64 `protobuf:"varint,3,opt,name=debtCeiling,proto3" json:"debtCeiling,omitempty"`
LiquidationRatio int64 `protobuf:"varint,4,opt,name=liquidationRatio,proto3" json:"liquidationRatio,omitempty"`
StabilityFeeRatio int64 `protobuf:"varint,5,opt,name=stabilityFeeRatio,proto3" json:"stabilityFeeRatio,omitempty"`
CreateAddr string `protobuf:"bytes,6,opt,name=createAddr,proto3" json:"createAddr,omitempty"`
Balance int64 `protobuf:"varint,7,opt,name=balance,proto3" json:"balance,omitempty"`
BorrowRecords []*BorrowRecord `protobuf:"bytes,8,rep,name=borrowRecords,proto3" json:"borrowRecords,omitempty"`
InvalidRecords []*BorrowRecord `protobuf:"bytes,9,rep,name=InvalidRecords,proto3" json:"InvalidRecords,omitempty"`
Status int32 `protobuf:"varint,10,opt,name=status,proto3" json:"status,omitempty"`
LatestLiquidationPrice int64 `protobuf:"varint,11,opt,name=latestLiquidationPrice,proto3" json:"latestLiquidationPrice,omitempty"`
Period int64 `protobuf:"varint,12,opt,name=period,proto3" json:"period,omitempty"`
LatestExpireTime int64 `protobuf:"varint,13,opt,name=latestExpireTime,proto3" json:"latestExpireTime,omitempty"`
CollBalance int64 `protobuf:"varint,14,opt,name=collBalance,proto3" json:"collBalance,omitempty"`
PreStatus int32 `protobuf:"varint,15,opt,name=preStatus,proto3" json:"preStatus,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *Collateralize) Reset() { *m = Collateralize{} }
func (m *Collateralize) String() string { return proto.CompactTextString(m) }
func (*Collateralize) ProtoMessage() {}
func (*Collateralize) Descriptor() ([]byte, []int) {
return fileDescriptor_collateralize_eee08d5094b5a295, []int{0}
}
func (m *Collateralize) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_Collateralize.Unmarshal(m, b)
}
func (m *Collateralize) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_Collateralize.Marshal(b, m, deterministic)
}
func (dst *Collateralize) XXX_Merge(src proto.Message) {
xxx_messageInfo_Collateralize.Merge(dst, src)
}
func (m *Collateralize) XXX_Size() int {
return xxx_messageInfo_Collateralize.Size(m)
}
func (m *Collateralize) XXX_DiscardUnknown() {
xxx_messageInfo_Collateralize.DiscardUnknown(m)
}
var xxx_messageInfo_Collateralize proto.InternalMessageInfo
func (m *Collateralize) GetCollateralizeId() string {
if m != nil {
return m.CollateralizeId
}
return ""
}
func (m *Collateralize) GetTotalBalance() int64 {
if m != nil {
return m.TotalBalance
}
return 0
}
func (m *Collateralize) GetDebtCeiling() int64 {
if m != nil {
return m.DebtCeiling
}
return 0
}
func (m *Collateralize) GetLiquidationRatio() int64 {
if m != nil {
return m.LiquidationRatio
}
return 0
}
func (m *Collateralize) GetStabilityFeeRatio() int64 {
if m != nil {
return m.StabilityFeeRatio
}
return 0
}
func (m *Collateralize) GetCreateAddr() string {
if m != nil {
return m.CreateAddr
}
return ""
}
func (m *Collateralize) GetBalance() int64 {
if m != nil {
return m.Balance
}
return 0
}
func (m *Collateralize) GetBorrowRecords() []*BorrowRecord {
if m != nil {
return m.BorrowRecords
}
return nil
}
func (m *Collateralize) GetInvalidRecords() []*BorrowRecord {
if m != nil {
return m.InvalidRecords
}
return nil
}
func (m *Collateralize) GetStatus() int32 {
if m != nil {
return m.Status
}
return 0
}
func (m *Collateralize) GetLatestLiquidationPrice() int64 {
if m != nil {
return m.LatestLiquidationPrice
}
return 0
}
func (m *Collateralize) GetPeriod() int64 {
if m != nil {
return m.Period
}
return 0
}
func (m *Collateralize) GetLatestExpireTime() int64 {
if m != nil {
return m.LatestExpireTime
}
return 0
}
func (m *Collateralize) GetCollBalance() int64 {
if m != nil {
return m.CollBalance
}
return 0
}
func (m *Collateralize) GetPreStatus() int32 {
if m != nil {
return m.PreStatus
}
return 0
}
// 借出记录
type BorrowRecord struct {
AccountAddr string `protobuf:"bytes,1,opt,name=accountAddr,proto3" json:"accountAddr,omitempty"`
StartTime int64 `protobuf:"varint,2,opt,name=startTime,proto3" json:"startTime,omitempty"`
CollateralValue int64 `protobuf:"varint,3,opt,name=collateralValue,proto3" json:"collateralValue,omitempty"`
CollateralPrice int64 `protobuf:"varint,4,opt,name=collateralPrice,proto3" json:"collateralPrice,omitempty"`
DebtValue int64 `protobuf:"varint,5,opt,name=debtValue,proto3" json:"debtValue,omitempty"`
LiquidationPrice int64 `protobuf:"varint,6,opt,name=liquidationPrice,proto3" json:"liquidationPrice,omitempty"`
Status int32 `protobuf:"varint,7,opt,name=status,proto3" json:"status,omitempty"`
LiquidateTime int64 `protobuf:"varint,8,opt,name=liquidateTime,proto3" json:"liquidateTime,omitempty"`
ExpireTime int64 `protobuf:"varint,9,opt,name=expireTime,proto3" json:"expireTime,omitempty"`
PreStatus int32 `protobuf:"varint,10,opt,name=preStatus,proto3" json:"preStatus,omitempty"`
RecordId string `protobuf:"bytes,11,opt,name=recordId,proto3" json:"recordId,omitempty"`
CollateralizeId string `protobuf:"bytes,12,opt,name=collateralizeId,proto3" json:"collateralizeId,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *BorrowRecord) Reset() { *m = BorrowRecord{} }
func (m *BorrowRecord) String() string { return proto.CompactTextString(m) }
func (*BorrowRecord) ProtoMessage() {}
func (*BorrowRecord) Descriptor() ([]byte, []int) {
return fileDescriptor_collateralize_eee08d5094b5a295, []int{1}
}
func (m *BorrowRecord) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_BorrowRecord.Unmarshal(m, b)
}
func (m *BorrowRecord) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_BorrowRecord.Marshal(b, m, deterministic)
}
func (dst *BorrowRecord) XXX_Merge(src proto.Message) {
xxx_messageInfo_BorrowRecord.Merge(dst, src)
}
func (m *BorrowRecord) XXX_Size() int {
return xxx_messageInfo_BorrowRecord.Size(m)
}
func (m *BorrowRecord) XXX_DiscardUnknown() {
xxx_messageInfo_BorrowRecord.DiscardUnknown(m)
}
var xxx_messageInfo_BorrowRecord proto.InternalMessageInfo
func (m *BorrowRecord) GetAccountAddr() string {
if m != nil {
return m.AccountAddr
}
return ""
}
func (m *BorrowRecord) GetStartTime() int64 {
if m != nil {
return m.StartTime
}
return 0
}
func (m *BorrowRecord) GetCollateralValue() int64 {
if m != nil {
return m.CollateralValue
}
return 0
}
func (m *BorrowRecord) GetCollateralPrice() int64 {
if m != nil {
return m.CollateralPrice
}
return 0
}
func (m *BorrowRecord) GetDebtValue() int64 {
if m != nil {
return m.DebtValue
}
return 0
}
func (m *BorrowRecord) GetLiquidationPrice() int64 {
if m != nil {
return m.LiquidationPrice
}
return 0
}
func (m *BorrowRecord) GetStatus() int32 {
if m != nil {
return m.Status
}
return 0
}
func (m *BorrowRecord) GetLiquidateTime() int64 {
if m != nil {
return m.LiquidateTime
}
return 0
}
func (m *BorrowRecord) GetExpireTime() int64 {
if m != nil {
return m.ExpireTime
}
return 0
}
func (m *BorrowRecord) GetPreStatus() int32 {
if m != nil {
return m.PreStatus
}
return 0
}
func (m *BorrowRecord) GetRecordId() string {
if m != nil {
return m.RecordId
}
return ""
}
func (m *BorrowRecord) GetCollateralizeId() string {
if m != nil {
return m.CollateralizeId
}
return ""
}
// 资产价格记录
type AssetPriceRecord struct {
RecordTime int64 `protobuf:"varint,1,opt,name=recordTime,proto3" json:"recordTime,omitempty"`
BtyPrice int64 `protobuf:"varint,2,opt,name=btyPrice,proto3" json:"btyPrice,omitempty"`
BtcPrice int64 `protobuf:"varint,3,opt,name=btcPrice,proto3" json:"btcPrice,omitempty"`
EthPrice int64 `protobuf:"varint,4,opt,name=ethPrice,proto3" json:"ethPrice,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *AssetPriceRecord) Reset() { *m = AssetPriceRecord{} }
func (m *AssetPriceRecord) String() string { return proto.CompactTextString(m) }
func (*AssetPriceRecord) ProtoMessage() {}
func (*AssetPriceRecord) Descriptor() ([]byte, []int) {
return fileDescriptor_collateralize_eee08d5094b5a295, []int{2}
}
func (m *AssetPriceRecord) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_AssetPriceRecord.Unmarshal(m, b)
}
func (m *AssetPriceRecord) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_AssetPriceRecord.Marshal(b, m, deterministic)
}
func (dst *AssetPriceRecord) XXX_Merge(src proto.Message) {
xxx_messageInfo_AssetPriceRecord.Merge(dst, src)
}
func (m *AssetPriceRecord) XXX_Size() int {
return xxx_messageInfo_AssetPriceRecord.Size(m)
}
func (m *AssetPriceRecord) XXX_DiscardUnknown() {
xxx_messageInfo_AssetPriceRecord.DiscardUnknown(m)
}
var xxx_messageInfo_AssetPriceRecord proto.InternalMessageInfo
func (m *AssetPriceRecord) GetRecordTime() int64 {
if m != nil {
return m.RecordTime
}
return 0
}
func (m *AssetPriceRecord) GetBtyPrice() int64 {
if m != nil {
return m.BtyPrice
}
return 0
}
func (m *AssetPriceRecord) GetBtcPrice() int64 {
if m != nil {
return m.BtcPrice
}
return 0
}
func (m *AssetPriceRecord) GetEthPrice() int64 {
if m != nil {
return m.EthPrice
}
return 0
}
// action
type CollateralizeAction struct {
// Types that are valid to be assigned to Value:
// *CollateralizeAction_Create
// *CollateralizeAction_Borrow
// *CollateralizeAction_Repay
// *CollateralizeAction_Append
// *CollateralizeAction_Feed
// *CollateralizeAction_Retrieve
// *CollateralizeAction_Manage
Value isCollateralizeAction_Value `protobuf_oneof:"value"`
Ty int32 `protobuf:"varint,10,opt,name=ty,proto3" json:"ty,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *CollateralizeAction) Reset() { *m = CollateralizeAction{} }
func (m *CollateralizeAction) String() string { return proto.CompactTextString(m) }
func (*CollateralizeAction) ProtoMessage() {}
func (*CollateralizeAction) Descriptor() ([]byte, []int) {
return fileDescriptor_collateralize_eee08d5094b5a295, []int{3}
}
func (m *CollateralizeAction) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_CollateralizeAction.Unmarshal(m, b)
}
func (m *CollateralizeAction) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_CollateralizeAction.Marshal(b, m, deterministic)
}
func (dst *CollateralizeAction) XXX_Merge(src proto.Message) {
xxx_messageInfo_CollateralizeAction.Merge(dst, src)
}
func (m *CollateralizeAction) XXX_Size() int {
return xxx_messageInfo_CollateralizeAction.Size(m)
}
func (m *CollateralizeAction) XXX_DiscardUnknown() {
xxx_messageInfo_CollateralizeAction.DiscardUnknown(m)
}
var xxx_messageInfo_CollateralizeAction proto.InternalMessageInfo
type isCollateralizeAction_Value interface {
isCollateralizeAction_Value()
}
type CollateralizeAction_Create struct {
Create *CollateralizeCreate `protobuf:"bytes,1,opt,name=create,proto3,oneof"`
}
type CollateralizeAction_Borrow struct {
Borrow *CollateralizeBorrow `protobuf:"bytes,2,opt,name=borrow,proto3,oneof"`
}
type CollateralizeAction_Repay struct {
Repay *CollateralizeRepay `protobuf:"bytes,3,opt,name=repay,proto3,oneof"`
}
type CollateralizeAction_Append struct {
Append *CollateralizeAppend `protobuf:"bytes,4,opt,name=append,proto3,oneof"`
}
type CollateralizeAction_Feed struct {
Feed *CollateralizeFeed `protobuf:"bytes,5,opt,name=feed,proto3,oneof"`
}
type CollateralizeAction_Retrieve struct {
Retrieve *CollateralizeRetrieve `protobuf:"bytes,6,opt,name=retrieve,proto3,oneof"`
}
type CollateralizeAction_Manage struct {
Manage *CollateralizeManage `protobuf:"bytes,7,opt,name=manage,proto3,oneof"`
}
func (*CollateralizeAction_Create) isCollateralizeAction_Value() {}
func (*CollateralizeAction_Borrow) isCollateralizeAction_Value() {}
func (*CollateralizeAction_Repay) isCollateralizeAction_Value() {}
func (*CollateralizeAction_Append) isCollateralizeAction_Value() {}
func (*CollateralizeAction_Feed) isCollateralizeAction_Value() {}
func (*CollateralizeAction_Retrieve) isCollateralizeAction_Value() {}
func (*CollateralizeAction_Manage) isCollateralizeAction_Value() {}
func (m *CollateralizeAction) GetValue() isCollateralizeAction_Value {
if m != nil {
return m.Value
}
return nil
}
func (m *CollateralizeAction) GetCreate() *CollateralizeCreate {
if x, ok := m.GetValue().(*CollateralizeAction_Create); ok {
return x.Create
}
return nil
}
func (m *CollateralizeAction) GetBorrow() *CollateralizeBorrow {
if x, ok := m.GetValue().(*CollateralizeAction_Borrow); ok {
return x.Borrow
}
return nil
}
func (m *CollateralizeAction) GetRepay() *CollateralizeRepay {
if x, ok := m.GetValue().(*CollateralizeAction_Repay); ok {
return x.Repay
}
return nil
}
func (m *CollateralizeAction) GetAppend() *CollateralizeAppend {
if x, ok := m.GetValue().(*CollateralizeAction_Append); ok {
return x.Append
}
return nil
}
func (m *CollateralizeAction) GetFeed() *CollateralizeFeed {
if x, ok := m.GetValue().(*CollateralizeAction_Feed); ok {
return x.Feed
}
return nil
}
func (m *CollateralizeAction) GetRetrieve() *CollateralizeRetrieve {
if x, ok := m.GetValue().(*CollateralizeAction_Retrieve); ok {
return x.Retrieve
}
return nil
}
func (m *CollateralizeAction) GetManage() *CollateralizeManage {
if x, ok := m.GetValue().(*CollateralizeAction_Manage); ok {
return x.Manage
}
return nil
}
func (m *CollateralizeAction) GetTy() int32 {
if m != nil {
return m.Ty
}
return 0
}
// XXX_OneofFuncs is for the internal use of the proto package.
func (*CollateralizeAction) XXX_OneofFuncs() (func(msg proto.Message, b *proto.Buffer) error, func(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error), func(msg proto.Message) (n int), []interface{}) {
return _CollateralizeAction_OneofMarshaler, _CollateralizeAction_OneofUnmarshaler, _CollateralizeAction_OneofSizer, []interface{}{
(*CollateralizeAction_Create)(nil),
(*CollateralizeAction_Borrow)(nil),
(*CollateralizeAction_Repay)(nil),
(*CollateralizeAction_Append)(nil),
(*CollateralizeAction_Feed)(nil),
(*CollateralizeAction_Retrieve)(nil),
(*CollateralizeAction_Manage)(nil),
}
}
func _CollateralizeAction_OneofMarshaler(msg proto.Message, b *proto.Buffer) error {
m := msg.(*CollateralizeAction)
// value
switch x := m.Value.(type) {
case *CollateralizeAction_Create:
b.EncodeVarint(1<<3 | proto.WireBytes)
if err := b.EncodeMessage(x.Create); err != nil {
return err
}
case *CollateralizeAction_Borrow:
b.EncodeVarint(2<<3 | proto.WireBytes)
if err := b.EncodeMessage(x.Borrow); err != nil {
return err
}
case *CollateralizeAction_Repay:
b.EncodeVarint(3<<3 | proto.WireBytes)
if err := b.EncodeMessage(x.Repay); err != nil {
return err
}
case *CollateralizeAction_Append:
b.EncodeVarint(4<<3 | proto.WireBytes)
if err := b.EncodeMessage(x.Append); err != nil {
return err
}
case *CollateralizeAction_Feed:
b.EncodeVarint(5<<3 | proto.WireBytes)
if err := b.EncodeMessage(x.Feed); err != nil {
return err
}
case *CollateralizeAction_Retrieve:
b.EncodeVarint(6<<3 | proto.WireBytes)
if err := b.EncodeMessage(x.Retrieve); err != nil {
return err
}
case *CollateralizeAction_Manage:
b.EncodeVarint(7<<3 | proto.WireBytes)
if err := b.EncodeMessage(x.Manage); err != nil {
return err
}
case nil:
default:
return fmt.Errorf("CollateralizeAction.Value has unexpected type %T", x)
}
return nil
}
func _CollateralizeAction_OneofUnmarshaler(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error) {
m := msg.(*CollateralizeAction)
switch tag {
case 1: // value.create
if wire != proto.WireBytes {
return true, proto.ErrInternalBadWireType
}
msg := new(CollateralizeCreate)
err := b.DecodeMessage(msg)
m.Value = &CollateralizeAction_Create{msg}
return true, err
case 2: // value.borrow
if wire != proto.WireBytes {
return true, proto.ErrInternalBadWireType
}
msg := new(CollateralizeBorrow)
err := b.DecodeMessage(msg)
m.Value = &CollateralizeAction_Borrow{msg}
return true, err
case 3: // value.repay
if wire != proto.WireBytes {
return true, proto.ErrInternalBadWireType
}
msg := new(CollateralizeRepay)
err := b.DecodeMessage(msg)
m.Value = &CollateralizeAction_Repay{msg}
return true, err
case 4: // value.append
if wire != proto.WireBytes {
return true, proto.ErrInternalBadWireType
}
msg := new(CollateralizeAppend)
err := b.DecodeMessage(msg)
m.Value = &CollateralizeAction_Append{msg}
return true, err
case 5: // value.feed
if wire != proto.WireBytes {
return true, proto.ErrInternalBadWireType
}
msg := new(CollateralizeFeed)
err := b.DecodeMessage(msg)
m.Value = &CollateralizeAction_Feed{msg}
return true, err
case 6: // value.retrieve
if wire != proto.WireBytes {
return true, proto.ErrInternalBadWireType
}
msg := new(CollateralizeRetrieve)
err := b.DecodeMessage(msg)
m.Value = &CollateralizeAction_Retrieve{msg}
return true, err
case 7: // value.manage
if wire != proto.WireBytes {
return true, proto.ErrInternalBadWireType
}
msg := new(CollateralizeManage)
err := b.DecodeMessage(msg)
m.Value = &CollateralizeAction_Manage{msg}
return true, err
default:
return false, nil
}
}
func _CollateralizeAction_OneofSizer(msg proto.Message) (n int) {
m := msg.(*CollateralizeAction)
// value
switch x := m.Value.(type) {
case *CollateralizeAction_Create:
s := proto.Size(x.Create)
n += 1 // tag and wire
n += proto.SizeVarint(uint64(s))
n += s
case *CollateralizeAction_Borrow:
s := proto.Size(x.Borrow)
n += 1 // tag and wire
n += proto.SizeVarint(uint64(s))
n += s
case *CollateralizeAction_Repay:
s := proto.Size(x.Repay)
n += 1 // tag and wire
n += proto.SizeVarint(uint64(s))
n += s
case *CollateralizeAction_Append:
s := proto.Size(x.Append)
n += 1 // tag and wire
n += proto.SizeVarint(uint64(s))
n += s
case *CollateralizeAction_Feed:
s := proto.Size(x.Feed)
n += 1 // tag and wire
n += proto.SizeVarint(uint64(s))
n += s
case *CollateralizeAction_Retrieve:
s := proto.Size(x.Retrieve)
n += 1 // tag and wire
n += proto.SizeVarint(uint64(s))
n += s
case *CollateralizeAction_Manage:
s := proto.Size(x.Manage)
n += 1 // tag and wire
n += proto.SizeVarint(uint64(s))
n += s
case nil:
default:
panic(fmt.Sprintf("proto: unexpected type %T in oneof", x))
}
return n
}
type CollateralizeManage struct {
DebtCeiling int64 `protobuf:"varint,1,opt,name=debtCeiling,proto3" json:"debtCeiling,omitempty"`
LiquidationRatio int64 `protobuf:"varint,2,opt,name=liquidationRatio,proto3" json:"liquidationRatio,omitempty"`
StabilityFeeRatio int64 `protobuf:"varint,3,opt,name=stabilityFeeRatio,proto3" json:"stabilityFeeRatio,omitempty"`
Period int64 `protobuf:"varint,4,opt,name=period,proto3" json:"period,omitempty"`
TotalBalance int64 `protobuf:"varint,5,opt,name=totalBalance,proto3" json:"totalBalance,omitempty"`
CurrentTime int64 `protobuf:"varint,6,opt,name=currentTime,proto3" json:"currentTime,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *CollateralizeManage) Reset() { *m = CollateralizeManage{} }
func (m *CollateralizeManage) String() string { return proto.CompactTextString(m) }
func (*CollateralizeManage) ProtoMessage() {}
func (*CollateralizeManage) Descriptor() ([]byte, []int) {
return fileDescriptor_collateralize_eee08d5094b5a295, []int{4}
}
func (m *CollateralizeManage) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_CollateralizeManage.Unmarshal(m, b)
}
func (m *CollateralizeManage) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_CollateralizeManage.Marshal(b, m, deterministic)
}
func (dst *CollateralizeManage) XXX_Merge(src proto.Message) {
xxx_messageInfo_CollateralizeManage.Merge(dst, src)
}
func (m *CollateralizeManage) XXX_Size() int {
return xxx_messageInfo_CollateralizeManage.Size(m)
}
func (m *CollateralizeManage) XXX_DiscardUnknown() {
xxx_messageInfo_CollateralizeManage.DiscardUnknown(m)
}
var xxx_messageInfo_CollateralizeManage proto.InternalMessageInfo
func (m *CollateralizeManage) GetDebtCeiling() int64 {
if m != nil {
return m.DebtCeiling
}
return 0
}
func (m *CollateralizeManage) GetLiquidationRatio() int64 {
if m != nil {
return m.LiquidationRatio
}
return 0
}
func (m *CollateralizeManage) GetStabilityFeeRatio() int64 {
if m != nil {
return m.StabilityFeeRatio
}
return 0
}
func (m *CollateralizeManage) GetPeriod() int64 {
if m != nil {
return m.Period
}
return 0
}
func (m *CollateralizeManage) GetTotalBalance() int64 {
if m != nil {
return m.TotalBalance
}
return 0
}
func (m *CollateralizeManage) GetCurrentTime() int64 {
if m != nil {
return m.CurrentTime
}
return 0
}
type CollateralizeAddr struct {
SuperAddrs []string `protobuf:"bytes,1,rep,name=superAddrs,proto3" json:"superAddrs,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *CollateralizeAddr) Reset() { *m = CollateralizeAddr{} }
func (m *CollateralizeAddr) String() string { return proto.CompactTextString(m) }
func (*CollateralizeAddr) ProtoMessage() {}
func (*CollateralizeAddr) Descriptor() ([]byte, []int) {
return fileDescriptor_collateralize_eee08d5094b5a295, []int{5}
}
func (m *CollateralizeAddr) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_CollateralizeAddr.Unmarshal(m, b)
}
func (m *CollateralizeAddr) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_CollateralizeAddr.Marshal(b, m, deterministic)
}
func (dst *CollateralizeAddr) XXX_Merge(src proto.Message) {
xxx_messageInfo_CollateralizeAddr.Merge(dst, src)
}
func (m *CollateralizeAddr) XXX_Size() int {
return xxx_messageInfo_CollateralizeAddr.Size(m)
}
func (m *CollateralizeAddr) XXX_DiscardUnknown() {
xxx_messageInfo_CollateralizeAddr.DiscardUnknown(m)
}
var xxx_messageInfo_CollateralizeAddr proto.InternalMessageInfo
func (m *CollateralizeAddr) GetSuperAddrs() []string {
if m != nil {
return m.SuperAddrs
}
return nil
}
// 创建放贷
type CollateralizeCreate struct {
TotalBalance int64 `protobuf:"varint,1,opt,name=totalBalance,proto3" json:"totalBalance,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *CollateralizeCreate) Reset() { *m = CollateralizeCreate{} }
func (m *CollateralizeCreate) String() string { return proto.CompactTextString(m) }
func (*CollateralizeCreate) ProtoMessage() {}
func (*CollateralizeCreate) Descriptor() ([]byte, []int) {
return fileDescriptor_collateralize_eee08d5094b5a295, []int{6}
}
func (m *CollateralizeCreate) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_CollateralizeCreate.Unmarshal(m, b)
}
func (m *CollateralizeCreate) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_CollateralizeCreate.Marshal(b, m, deterministic)
}
func (dst *CollateralizeCreate) XXX_Merge(src proto.Message) {
xxx_messageInfo_CollateralizeCreate.Merge(dst, src)
}
func (m *CollateralizeCreate) XXX_Size() int {
return xxx_messageInfo_CollateralizeCreate.Size(m)
}
func (m *CollateralizeCreate) XXX_DiscardUnknown() {
xxx_messageInfo_CollateralizeCreate.DiscardUnknown(m)
}
var xxx_messageInfo_CollateralizeCreate proto.InternalMessageInfo
func (m *CollateralizeCreate) GetTotalBalance() int64 {
if m != nil {
return m.TotalBalance
}
return 0
}
// 质押借出
type CollateralizeBorrow struct {
CollateralizeId string `protobuf:"bytes,1,opt,name=collateralizeId,proto3" json:"collateralizeId,omitempty"`
Value int64 `protobuf:"varint,2,opt,name=value,proto3" json:"value,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *CollateralizeBorrow) Reset() { *m = CollateralizeBorrow{} }
func (m *CollateralizeBorrow) String() string { return proto.CompactTextString(m) }
func (*CollateralizeBorrow) ProtoMessage() {}
func (*CollateralizeBorrow) Descriptor() ([]byte, []int) {
return fileDescriptor_collateralize_eee08d5094b5a295, []int{7}
}
func (m *CollateralizeBorrow) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_CollateralizeBorrow.Unmarshal(m, b)
}
func (m *CollateralizeBorrow) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_CollateralizeBorrow.Marshal(b, m, deterministic)
}
func (dst *CollateralizeBorrow) XXX_Merge(src proto.Message) {
xxx_messageInfo_CollateralizeBorrow.Merge(dst, src)
}
func (m *CollateralizeBorrow) XXX_Size() int {
return xxx_messageInfo_CollateralizeBorrow.Size(m)
}
func (m *CollateralizeBorrow) XXX_DiscardUnknown() {
xxx_messageInfo_CollateralizeBorrow.DiscardUnknown(m)
}
var xxx_messageInfo_CollateralizeBorrow proto.InternalMessageInfo
func (m *CollateralizeBorrow) GetCollateralizeId() string {
if m != nil {
return m.CollateralizeId
}
return ""
}
func (m *CollateralizeBorrow) GetValue() int64 {
if m != nil {
return m.Value
}
return 0
}
// 质押清算
type CollateralizeRepay struct {
CollateralizeId string `protobuf:"bytes,1,opt,name=collateralizeId,proto3" json:"collateralizeId,omitempty"`
RecordId string `protobuf:"bytes,2,opt,name=recordId,proto3" json:"recordId,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *CollateralizeRepay) Reset() { *m = CollateralizeRepay{} }
func (m *CollateralizeRepay) String() string { return proto.CompactTextString(m) }
func (*CollateralizeRepay) ProtoMessage() {}
func (*CollateralizeRepay) Descriptor() ([]byte, []int) {
return fileDescriptor_collateralize_eee08d5094b5a295, []int{8}
}
func (m *CollateralizeRepay) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_CollateralizeRepay.Unmarshal(m, b)
}
func (m *CollateralizeRepay) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_CollateralizeRepay.Marshal(b, m, deterministic)
}
func (dst *CollateralizeRepay) XXX_Merge(src proto.Message) {
xxx_messageInfo_CollateralizeRepay.Merge(dst, src)
}
func (m *CollateralizeRepay) XXX_Size() int {
return xxx_messageInfo_CollateralizeRepay.Size(m)
}
func (m *CollateralizeRepay) XXX_DiscardUnknown() {
xxx_messageInfo_CollateralizeRepay.DiscardUnknown(m)
}
var xxx_messageInfo_CollateralizeRepay proto.InternalMessageInfo
func (m *CollateralizeRepay) GetCollateralizeId() string {
if m != nil {
return m.CollateralizeId
}
return ""
}
func (m *CollateralizeRepay) GetRecordId() string {
if m != nil {
return m.RecordId
}
return ""
}
// 追加抵押物
type CollateralizeAppend struct {
CollateralizeId string `protobuf:"bytes,1,opt,name=collateralizeId,proto3" json:"collateralizeId,omitempty"`
RecordId string `protobuf:"bytes,2,opt,name=recordId,proto3" json:"recordId,omitempty"`
CollateralValue int64 `protobuf:"varint,3,opt,name=collateralValue,proto3" json:"collateralValue,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *CollateralizeAppend) Reset() { *m = CollateralizeAppend{} }
func (m *CollateralizeAppend) String() string { return proto.CompactTextString(m) }
func (*CollateralizeAppend) ProtoMessage() {}
func (*CollateralizeAppend) Descriptor() ([]byte, []int) {
return fileDescriptor_collateralize_eee08d5094b5a295, []int{9}
}
func (m *CollateralizeAppend) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_CollateralizeAppend.Unmarshal(m, b)
}
func (m *CollateralizeAppend) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_CollateralizeAppend.Marshal(b, m, deterministic)
}
func (dst *CollateralizeAppend) XXX_Merge(src proto.Message) {
xxx_messageInfo_CollateralizeAppend.Merge(dst, src)
}
func (m *CollateralizeAppend) XXX_Size() int {
return xxx_messageInfo_CollateralizeAppend.Size(m)
}
func (m *CollateralizeAppend) XXX_DiscardUnknown() {
xxx_messageInfo_CollateralizeAppend.DiscardUnknown(m)
}
var xxx_messageInfo_CollateralizeAppend proto.InternalMessageInfo
func (m *CollateralizeAppend) GetCollateralizeId() string {
if m != nil {
return m.CollateralizeId
}
return ""
}
func (m *CollateralizeAppend) GetRecordId() string {
if m != nil {
return m.RecordId
}
return ""
}
func (m *CollateralizeAppend) GetCollateralValue() int64 {
if m != nil {
return m.CollateralValue
}
return 0
}
// 喂价
type CollateralizeFeed struct {
CollType int32 `protobuf:"varint,1,opt,name=collType,proto3" json:"collType,omitempty"`
Price []int64 `protobuf:"varint,2,rep,packed,name=price,proto3" json:"price,omitempty"`
Volume []int64 `protobuf:"varint,3,rep,packed,name=volume,proto3" json:"volume,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *CollateralizeFeed) Reset() { *m = CollateralizeFeed{} }
func (m *CollateralizeFeed) String() string { return proto.CompactTextString(m) }
func (*CollateralizeFeed) ProtoMessage() {}
func (*CollateralizeFeed) Descriptor() ([]byte, []int) {
return fileDescriptor_collateralize_eee08d5094b5a295, []int{10}
}
func (m *CollateralizeFeed) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_CollateralizeFeed.Unmarshal(m, b)
}
func (m *CollateralizeFeed) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_CollateralizeFeed.Marshal(b, m, deterministic)
}
func (dst *CollateralizeFeed) XXX_Merge(src proto.Message) {
xxx_messageInfo_CollateralizeFeed.Merge(dst, src)
}
func (m *CollateralizeFeed) XXX_Size() int {
return xxx_messageInfo_CollateralizeFeed.Size(m)
}
func (m *CollateralizeFeed) XXX_DiscardUnknown() {
xxx_messageInfo_CollateralizeFeed.DiscardUnknown(m)
}
var xxx_messageInfo_CollateralizeFeed proto.InternalMessageInfo
func (m *CollateralizeFeed) GetCollType() int32 {
if m != nil {
return m.CollType
}
return 0
}
func (m *CollateralizeFeed) GetPrice() []int64 {
if m != nil {
return m.Price
}
return nil
}
func (m *CollateralizeFeed) GetVolume() []int64 {
if m != nil {
return m.Volume
}
return nil
}
// 收回
type CollateralizeRetrieve struct {
CollateralizeId string `protobuf:"bytes,1,opt,name=collateralizeId,proto3" json:"collateralizeId,omitempty"`
Balance int64 `protobuf:"varint,2,opt,name=balance,proto3" json:"balance,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *CollateralizeRetrieve) Reset() { *m = CollateralizeRetrieve{} }
func (m *CollateralizeRetrieve) String() string { return proto.CompactTextString(m) }
func (*CollateralizeRetrieve) ProtoMessage() {}
func (*CollateralizeRetrieve) Descriptor() ([]byte, []int) {
return fileDescriptor_collateralize_eee08d5094b5a295, []int{11}
}
func (m *CollateralizeRetrieve) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_CollateralizeRetrieve.Unmarshal(m, b)
}
func (m *CollateralizeRetrieve) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_CollateralizeRetrieve.Marshal(b, m, deterministic)
}
func (dst *CollateralizeRetrieve) XXX_Merge(src proto.Message) {
xxx_messageInfo_CollateralizeRetrieve.Merge(dst, src)
}
func (m *CollateralizeRetrieve) XXX_Size() int {
return xxx_messageInfo_CollateralizeRetrieve.Size(m)
}
func (m *CollateralizeRetrieve) XXX_DiscardUnknown() {
xxx_messageInfo_CollateralizeRetrieve.DiscardUnknown(m)
}
var xxx_messageInfo_CollateralizeRetrieve proto.InternalMessageInfo
func (m *CollateralizeRetrieve) GetCollateralizeId() string {
if m != nil {
return m.CollateralizeId
}
return ""
}
func (m *CollateralizeRetrieve) GetBalance() int64 {
if m != nil {
return m.Balance
}
return 0
}
// exec_local 放贷信息
type ReceiptCollateralize struct {
CollateralizeId string `protobuf:"bytes,1,opt,name=collateralizeId,proto3" json:"collateralizeId,omitempty"`
AccountAddr string `protobuf:"bytes,3,opt,name=accountAddr,proto3" json:"accountAddr,omitempty"`
RecordId string `protobuf:"bytes,4,opt,name=recordId,proto3" json:"recordId,omitempty"`
Status int32 `protobuf:"varint,5,opt,name=status,proto3" json:"status,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *ReceiptCollateralize) Reset() { *m = ReceiptCollateralize{} }
func (m *ReceiptCollateralize) String() string { return proto.CompactTextString(m) }
func (*ReceiptCollateralize) ProtoMessage() {}
func (*ReceiptCollateralize) Descriptor() ([]byte, []int) {
return fileDescriptor_collateralize_eee08d5094b5a295, []int{12}
}
func (m *ReceiptCollateralize) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ReceiptCollateralize.Unmarshal(m, b)
}
func (m *ReceiptCollateralize) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_ReceiptCollateralize.Marshal(b, m, deterministic)
}
func (dst *ReceiptCollateralize) XXX_Merge(src proto.Message) {
xxx_messageInfo_ReceiptCollateralize.Merge(dst, src)
}
func (m *ReceiptCollateralize) XXX_Size() int {
return xxx_messageInfo_ReceiptCollateralize.Size(m)
}
func (m *ReceiptCollateralize) XXX_DiscardUnknown() {
xxx_messageInfo_ReceiptCollateralize.DiscardUnknown(m)
}
var xxx_messageInfo_ReceiptCollateralize proto.InternalMessageInfo
func (m *ReceiptCollateralize) GetCollateralizeId() string {
if m != nil {
return m.CollateralizeId
}
return ""
}
func (m *ReceiptCollateralize) GetAccountAddr() string {
if m != nil {
return m.AccountAddr
}
return ""
}
func (m *ReceiptCollateralize) GetRecordId() string {
if m != nil {
return m.RecordId
}
return ""
}
func (m *ReceiptCollateralize) GetStatus() int32 {
if m != nil {
return m.Status
}
return 0
}
// exec_local 放贷记录信息列表
type CollateralizeRecords struct {
Records []*ReceiptCollateralize `protobuf:"bytes,1,rep,name=records,proto3" json:"records,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *CollateralizeRecords) Reset() { *m = CollateralizeRecords{} }
func (m *CollateralizeRecords) String() string { return proto.CompactTextString(m) }
func (*CollateralizeRecords) ProtoMessage() {}
func (*CollateralizeRecords) Descriptor() ([]byte, []int) {
return fileDescriptor_collateralize_eee08d5094b5a295, []int{13}
}
func (m *CollateralizeRecords) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_CollateralizeRecords.Unmarshal(m, b)
}
func (m *CollateralizeRecords) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_CollateralizeRecords.Marshal(b, m, deterministic)
}
func (dst *CollateralizeRecords) XXX_Merge(src proto.Message) {
xxx_messageInfo_CollateralizeRecords.Merge(dst, src)
}
func (m *CollateralizeRecords) XXX_Size() int {
return xxx_messageInfo_CollateralizeRecords.Size(m)
}
func (m *CollateralizeRecords) XXX_DiscardUnknown() {
xxx_messageInfo_CollateralizeRecords.DiscardUnknown(m)
}
var xxx_messageInfo_CollateralizeRecords proto.InternalMessageInfo
func (m *CollateralizeRecords) GetRecords() []*ReceiptCollateralize {
if m != nil {
return m.Records
}
return nil
}
// 根据ID查询一期放贷信息
type ReqCollateralizeInfo struct {
CollateralizeId string `protobuf:"bytes,1,opt,name=collateralizeId,proto3" json:"collateralizeId,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *ReqCollateralizeInfo) Reset() { *m = ReqCollateralizeInfo{} }
func (m *ReqCollateralizeInfo) String() string { return proto.CompactTextString(m) }
func (*ReqCollateralizeInfo) ProtoMessage() {}
func (*ReqCollateralizeInfo) Descriptor() ([]byte, []int) {
return fileDescriptor_collateralize_eee08d5094b5a295, []int{14}
}
func (m *ReqCollateralizeInfo) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ReqCollateralizeInfo.Unmarshal(m, b)
}
func (m *ReqCollateralizeInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_ReqCollateralizeInfo.Marshal(b, m, deterministic)
}
func (dst *ReqCollateralizeInfo) XXX_Merge(src proto.Message) {
xxx_messageInfo_ReqCollateralizeInfo.Merge(dst, src)
}
func (m *ReqCollateralizeInfo) XXX_Size() int {
return xxx_messageInfo_ReqCollateralizeInfo.Size(m)
}
func (m *ReqCollateralizeInfo) XXX_DiscardUnknown() {
xxx_messageInfo_ReqCollateralizeInfo.DiscardUnknown(m)
}
var xxx_messageInfo_ReqCollateralizeInfo proto.InternalMessageInfo
func (m *ReqCollateralizeInfo) GetCollateralizeId() string {
if m != nil {
return m.CollateralizeId
}
return ""
}
// 返回一期放贷信息
type RepCollateralizeCurrentInfo struct {
Status int32 `protobuf:"varint,1,opt,name=status,proto3" json:"status,omitempty"`
TotalBalance int64 `protobuf:"varint,2,opt,name=totalBalance,proto3" json:"totalBalance,omitempty"`
DebtCeiling int64 `protobuf:"varint,3,opt,name=debtCeiling,proto3" json:"debtCeiling,omitempty"`
LiquidationRatio int64 `protobuf:"varint,4,opt,name=liquidationRatio,proto3" json:"liquidationRatio,omitempty"`
StabilityFeeRatio int64 `protobuf:"varint,5,opt,name=stabilityFeeRatio,proto3" json:"stabilityFeeRatio,omitempty"`
CreateAddr string `protobuf:"bytes,6,opt,name=createAddr,proto3" json:"createAddr,omitempty"`
Balance int64 `protobuf:"varint,7,opt,name=balance,proto3" json:"balance,omitempty"`
Period int64 `protobuf:"varint,8,opt,name=period,proto3" json:"period,omitempty"`
CollateralizeId string `protobuf:"bytes,9,opt,name=collateralizeId,proto3" json:"collateralizeId,omitempty"`
CollBalance int64 `protobuf:"varint,10,opt,name=collBalance,proto3" json:"collBalance,omitempty"`
BorrowRecords []*BorrowRecord `protobuf:"bytes,11,rep,name=borrowRecords,proto3" json:"borrowRecords,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *RepCollateralizeCurrentInfo) Reset() { *m = RepCollateralizeCurrentInfo{} }
func (m *RepCollateralizeCurrentInfo) String() string { return proto.CompactTextString(m) }
func (*RepCollateralizeCurrentInfo) ProtoMessage() {}
func (*RepCollateralizeCurrentInfo) Descriptor() ([]byte, []int) {
return fileDescriptor_collateralize_eee08d5094b5a295, []int{15}
}
func (m *RepCollateralizeCurrentInfo) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_RepCollateralizeCurrentInfo.Unmarshal(m, b)
}
func (m *RepCollateralizeCurrentInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_RepCollateralizeCurrentInfo.Marshal(b, m, deterministic)
}
func (dst *RepCollateralizeCurrentInfo) XXX_Merge(src proto.Message) {
xxx_messageInfo_RepCollateralizeCurrentInfo.Merge(dst, src)
}
func (m *RepCollateralizeCurrentInfo) XXX_Size() int {
return xxx_messageInfo_RepCollateralizeCurrentInfo.Size(m)
}
func (m *RepCollateralizeCurrentInfo) XXX_DiscardUnknown() {
xxx_messageInfo_RepCollateralizeCurrentInfo.DiscardUnknown(m)
}
var xxx_messageInfo_RepCollateralizeCurrentInfo proto.InternalMessageInfo
func (m *RepCollateralizeCurrentInfo) GetStatus() int32 {
if m != nil {
return m.Status
}
return 0
}
func (m *RepCollateralizeCurrentInfo) GetTotalBalance() int64 {
if m != nil {
return m.TotalBalance
}
return 0
}
func (m *RepCollateralizeCurrentInfo) GetDebtCeiling() int64 {
if m != nil {
return m.DebtCeiling
}
return 0
}
func (m *RepCollateralizeCurrentInfo) GetLiquidationRatio() int64 {
if m != nil {
return m.LiquidationRatio
}
return 0
}
func (m *RepCollateralizeCurrentInfo) GetStabilityFeeRatio() int64 {
if m != nil {
return m.StabilityFeeRatio
}
return 0
}
func (m *RepCollateralizeCurrentInfo) GetCreateAddr() string {
if m != nil {
return m.CreateAddr
}
return ""
}
func (m *RepCollateralizeCurrentInfo) GetBalance() int64 {
if m != nil {
return m.Balance
}
return 0
}
func (m *RepCollateralizeCurrentInfo) GetPeriod() int64 {
if m != nil {
return m.Period
}
return 0
}
func (m *RepCollateralizeCurrentInfo) GetCollateralizeId() string {
if m != nil {
return m.CollateralizeId
}
return ""
}
func (m *RepCollateralizeCurrentInfo) GetCollBalance() int64 {
if m != nil {
return m.CollBalance
}
return 0
}
func (m *RepCollateralizeCurrentInfo) GetBorrowRecords() []*BorrowRecord {
if m != nil {
return m.BorrowRecords
}
return nil
}
// 根据ID列表查询多期放贷信息
type ReqCollateralizeInfos struct {
CollateralizeIds []string `protobuf:"bytes,1,rep,name=collateralizeIds,proto3" json:"collateralizeIds,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *ReqCollateralizeInfos) Reset() { *m = ReqCollateralizeInfos{} }
func (m *ReqCollateralizeInfos) String() string { return proto.CompactTextString(m) }
func (*ReqCollateralizeInfos) ProtoMessage() {}
func (*ReqCollateralizeInfos) Descriptor() ([]byte, []int) {
return fileDescriptor_collateralize_eee08d5094b5a295, []int{16}
}
func (m *ReqCollateralizeInfos) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ReqCollateralizeInfos.Unmarshal(m, b)
}
func (m *ReqCollateralizeInfos) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_ReqCollateralizeInfos.Marshal(b, m, deterministic)
}
func (dst *ReqCollateralizeInfos) XXX_Merge(src proto.Message) {
xxx_messageInfo_ReqCollateralizeInfos.Merge(dst, src)
}
func (m *ReqCollateralizeInfos) XXX_Size() int {
return xxx_messageInfo_ReqCollateralizeInfos.Size(m)
}
func (m *ReqCollateralizeInfos) XXX_DiscardUnknown() {
xxx_messageInfo_ReqCollateralizeInfos.DiscardUnknown(m)
}
var xxx_messageInfo_ReqCollateralizeInfos proto.InternalMessageInfo
func (m *ReqCollateralizeInfos) GetCollateralizeIds() []string {
if m != nil {
return m.CollateralizeIds
}
return nil
}
// 返回多期放贷信息
type RepCollateralizeCurrentInfos struct {
Infos []*RepCollateralizeCurrentInfo `protobuf:"bytes,1,rep,name=infos,proto3" json:"infos,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *RepCollateralizeCurrentInfos) Reset() { *m = RepCollateralizeCurrentInfos{} }
func (m *RepCollateralizeCurrentInfos) String() string { return proto.CompactTextString(m) }
func (*RepCollateralizeCurrentInfos) ProtoMessage() {}
func (*RepCollateralizeCurrentInfos) Descriptor() ([]byte, []int) {
return fileDescriptor_collateralize_eee08d5094b5a295, []int{17}
}
func (m *RepCollateralizeCurrentInfos) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_RepCollateralizeCurrentInfos.Unmarshal(m, b)
}
func (m *RepCollateralizeCurrentInfos) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_RepCollateralizeCurrentInfos.Marshal(b, m, deterministic)
}
func (dst *RepCollateralizeCurrentInfos) XXX_Merge(src proto.Message) {
xxx_messageInfo_RepCollateralizeCurrentInfos.Merge(dst, src)
}
func (m *RepCollateralizeCurrentInfos) XXX_Size() int {
return xxx_messageInfo_RepCollateralizeCurrentInfos.Size(m)
}
func (m *RepCollateralizeCurrentInfos) XXX_DiscardUnknown() {
xxx_messageInfo_RepCollateralizeCurrentInfos.DiscardUnknown(m)
}
var xxx_messageInfo_RepCollateralizeCurrentInfos proto.InternalMessageInfo
func (m *RepCollateralizeCurrentInfos) GetInfos() []*RepCollateralizeCurrentInfo {
if m != nil {
return m.Infos
}
return nil
}
// 根据放贷状态查询
type ReqCollateralizeByStatus struct {
Status int32 `protobuf:"varint,1,opt,name=status,proto3" json:"status,omitempty"`
CollID string `protobuf:"bytes,2,opt,name=collID,proto3" json:"collID,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *ReqCollateralizeByStatus) Reset() { *m = ReqCollateralizeByStatus{} }
func (m *ReqCollateralizeByStatus) String() string { return proto.CompactTextString(m) }
func (*ReqCollateralizeByStatus) ProtoMessage() {}
func (*ReqCollateralizeByStatus) Descriptor() ([]byte, []int) {
return fileDescriptor_collateralize_eee08d5094b5a295, []int{18}
}
func (m *ReqCollateralizeByStatus) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ReqCollateralizeByStatus.Unmarshal(m, b)
}
func (m *ReqCollateralizeByStatus) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_ReqCollateralizeByStatus.Marshal(b, m, deterministic)
}
func (dst *ReqCollateralizeByStatus) XXX_Merge(src proto.Message) {
xxx_messageInfo_ReqCollateralizeByStatus.Merge(dst, src)
}
func (m *ReqCollateralizeByStatus) XXX_Size() int {
return xxx_messageInfo_ReqCollateralizeByStatus.Size(m)
}
func (m *ReqCollateralizeByStatus) XXX_DiscardUnknown() {
xxx_messageInfo_ReqCollateralizeByStatus.DiscardUnknown(m)
}
var xxx_messageInfo_ReqCollateralizeByStatus proto.InternalMessageInfo
func (m *ReqCollateralizeByStatus) GetStatus() int32 {
if m != nil {
return m.Status
}
return 0
}
func (m *ReqCollateralizeByStatus) GetCollID() string {
if m != nil {
return m.CollID
}
return ""
}
// 根据用户地址查询
type ReqCollateralizeByAddr struct {
Addr string `protobuf:"bytes,1,opt,name=addr,proto3" json:"addr,omitempty"`
Status int32 `protobuf:"varint,2,opt,name=status,proto3" json:"status,omitempty"`
CollID string `protobuf:"bytes,3,opt,name=collID,proto3" json:"collID,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *ReqCollateralizeByAddr) Reset() { *m = ReqCollateralizeByAddr{} }
func (m *ReqCollateralizeByAddr) String() string { return proto.CompactTextString(m) }
func (*ReqCollateralizeByAddr) ProtoMessage() {}
func (*ReqCollateralizeByAddr) Descriptor() ([]byte, []int) {
return fileDescriptor_collateralize_eee08d5094b5a295, []int{19}
}
func (m *ReqCollateralizeByAddr) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ReqCollateralizeByAddr.Unmarshal(m, b)
}
func (m *ReqCollateralizeByAddr) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_ReqCollateralizeByAddr.Marshal(b, m, deterministic)
}
func (dst *ReqCollateralizeByAddr) XXX_Merge(src proto.Message) {
xxx_messageInfo_ReqCollateralizeByAddr.Merge(dst, src)
}
func (m *ReqCollateralizeByAddr) XXX_Size() int {
return xxx_messageInfo_ReqCollateralizeByAddr.Size(m)
}
func (m *ReqCollateralizeByAddr) XXX_DiscardUnknown() {
xxx_messageInfo_ReqCollateralizeByAddr.DiscardUnknown(m)
}
var xxx_messageInfo_ReqCollateralizeByAddr proto.InternalMessageInfo
func (m *ReqCollateralizeByAddr) GetAddr() string {
if m != nil {
return m.Addr
}
return ""
}
func (m *ReqCollateralizeByAddr) GetStatus() int32 {
if m != nil {
return m.Status
}
return 0
}
func (m *ReqCollateralizeByAddr) GetCollID() string {
if m != nil {
return m.CollID
}
return ""
}
// 返回放贷ID列表
type RepCollateralizeIDs struct {
IDs []string `protobuf:"bytes,1,rep,name=IDs,proto3" json:"IDs,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *RepCollateralizeIDs) Reset() { *m = RepCollateralizeIDs{} }
func (m *RepCollateralizeIDs) String() string { return proto.CompactTextString(m) }
func (*RepCollateralizeIDs) ProtoMessage() {}
func (*RepCollateralizeIDs) Descriptor() ([]byte, []int) {
return fileDescriptor_collateralize_eee08d5094b5a295, []int{20}
}
func (m *RepCollateralizeIDs) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_RepCollateralizeIDs.Unmarshal(m, b)
}
func (m *RepCollateralizeIDs) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_RepCollateralizeIDs.Marshal(b, m, deterministic)
}
func (dst *RepCollateralizeIDs) XXX_Merge(src proto.Message) {
xxx_messageInfo_RepCollateralizeIDs.Merge(dst, src)
}
func (m *RepCollateralizeIDs) XXX_Size() int {
return xxx_messageInfo_RepCollateralizeIDs.Size(m)
}
func (m *RepCollateralizeIDs) XXX_DiscardUnknown() {
xxx_messageInfo_RepCollateralizeIDs.DiscardUnknown(m)
}
var xxx_messageInfo_RepCollateralizeIDs proto.InternalMessageInfo
func (m *RepCollateralizeIDs) GetIDs() []string {
if m != nil {
return m.IDs
}
return nil
}
// 根据地址和借贷ID混合查询具体借贷记录
type ReqCollateralizeRecordByAddr struct {
CollateralizeId string `protobuf:"bytes,1,opt,name=collateralizeId,proto3" json:"collateralizeId,omitempty"`
Addr string `protobuf:"bytes,2,opt,name=addr,proto3" json:"addr,omitempty"`
Status int32 `protobuf:"varint,3,opt,name=status,proto3" json:"status,omitempty"`
RecordId string `protobuf:"bytes,4,opt,name=recordId,proto3" json:"recordId,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *ReqCollateralizeRecordByAddr) Reset() { *m = ReqCollateralizeRecordByAddr{} }
func (m *ReqCollateralizeRecordByAddr) String() string { return proto.CompactTextString(m) }
func (*ReqCollateralizeRecordByAddr) ProtoMessage() {}
func (*ReqCollateralizeRecordByAddr) Descriptor() ([]byte, []int) {
return fileDescriptor_collateralize_eee08d5094b5a295, []int{21}
}
func (m *ReqCollateralizeRecordByAddr) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ReqCollateralizeRecordByAddr.Unmarshal(m, b)
}
func (m *ReqCollateralizeRecordByAddr) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_ReqCollateralizeRecordByAddr.Marshal(b, m, deterministic)
}
func (dst *ReqCollateralizeRecordByAddr) XXX_Merge(src proto.Message) {
xxx_messageInfo_ReqCollateralizeRecordByAddr.Merge(dst, src)
}
func (m *ReqCollateralizeRecordByAddr) XXX_Size() int {
return xxx_messageInfo_ReqCollateralizeRecordByAddr.Size(m)
}
func (m *ReqCollateralizeRecordByAddr) XXX_DiscardUnknown() {
xxx_messageInfo_ReqCollateralizeRecordByAddr.DiscardUnknown(m)
}
var xxx_messageInfo_ReqCollateralizeRecordByAddr proto.InternalMessageInfo
func (m *ReqCollateralizeRecordByAddr) GetCollateralizeId() string {
if m != nil {
return m.CollateralizeId
}
return ""
}
func (m *ReqCollateralizeRecordByAddr) GetAddr() string {
if m != nil {
return m.Addr
}
return ""
}
func (m *ReqCollateralizeRecordByAddr) GetStatus() int32 {
if m != nil {
return m.Status
}
return 0
}
func (m *ReqCollateralizeRecordByAddr) GetRecordId() string {
if m != nil {
return m.RecordId
}
return ""
}
// 根据状态和借贷ID混合查询具体借贷记录
type ReqCollateralizeRecordByStatus struct {
CollateralizeId string `protobuf:"bytes,1,opt,name=collateralizeId,proto3" json:"collateralizeId,omitempty"`
Status int32 `protobuf:"varint,2,opt,name=status,proto3" json:"status,omitempty"`
RecordId string `protobuf:"bytes,3,opt,name=recordId,proto3" json:"recordId,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *ReqCollateralizeRecordByStatus) Reset() { *m = ReqCollateralizeRecordByStatus{} }
func (m *ReqCollateralizeRecordByStatus) String() string { return proto.CompactTextString(m) }
func (*ReqCollateralizeRecordByStatus) ProtoMessage() {}
func (*ReqCollateralizeRecordByStatus) Descriptor() ([]byte, []int) {
return fileDescriptor_collateralize_eee08d5094b5a295, []int{22}
}
func (m *ReqCollateralizeRecordByStatus) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ReqCollateralizeRecordByStatus.Unmarshal(m, b)
}
func (m *ReqCollateralizeRecordByStatus) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_ReqCollateralizeRecordByStatus.Marshal(b, m, deterministic)
}
func (dst *ReqCollateralizeRecordByStatus) XXX_Merge(src proto.Message) {
xxx_messageInfo_ReqCollateralizeRecordByStatus.Merge(dst, src)
}
func (m *ReqCollateralizeRecordByStatus) XXX_Size() int {
return xxx_messageInfo_ReqCollateralizeRecordByStatus.Size(m)
}
func (m *ReqCollateralizeRecordByStatus) XXX_DiscardUnknown() {
xxx_messageInfo_ReqCollateralizeRecordByStatus.DiscardUnknown(m)
}
var xxx_messageInfo_ReqCollateralizeRecordByStatus proto.InternalMessageInfo
func (m *ReqCollateralizeRecordByStatus) GetCollateralizeId() string {
if m != nil {
return m.CollateralizeId
}
return ""
}
func (m *ReqCollateralizeRecordByStatus) GetStatus() int32 {
if m != nil {
return m.Status
}
return 0
}
func (m *ReqCollateralizeRecordByStatus) GetRecordId() string {
if m != nil {
return m.RecordId
}
return ""
}
// 返回借贷记录
type RepCollateralizeRecords struct {
Records []*BorrowRecord `protobuf:"bytes,1,rep,name=records,proto3" json:"records,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *RepCollateralizeRecords) Reset() { *m = RepCollateralizeRecords{} }
func (m *RepCollateralizeRecords) String() string { return proto.CompactTextString(m) }
func (*RepCollateralizeRecords) ProtoMessage() {}
func (*RepCollateralizeRecords) Descriptor() ([]byte, []int) {
return fileDescriptor_collateralize_eee08d5094b5a295, []int{23}
}
func (m *RepCollateralizeRecords) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_RepCollateralizeRecords.Unmarshal(m, b)
}
func (m *RepCollateralizeRecords) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_RepCollateralizeRecords.Marshal(b, m, deterministic)
}
func (dst *RepCollateralizeRecords) XXX_Merge(src proto.Message) {
xxx_messageInfo_RepCollateralizeRecords.Merge(dst, src)
}
func (m *RepCollateralizeRecords) XXX_Size() int {
return xxx_messageInfo_RepCollateralizeRecords.Size(m)
}
func (m *RepCollateralizeRecords) XXX_DiscardUnknown() {
xxx_messageInfo_RepCollateralizeRecords.DiscardUnknown(m)
}
var xxx_messageInfo_RepCollateralizeRecords proto.InternalMessageInfo
func (m *RepCollateralizeRecords) GetRecords() []*BorrowRecord {
if m != nil {
return m.Records
}
return nil
}
// 精确查找借贷记录
type ReqCollateralizeRecord struct {
CollateralizeId string `protobuf:"bytes,1,opt,name=collateralizeId,proto3" json:"collateralizeId,omitempty"`
RecordId string `protobuf:"bytes,2,opt,name=recordId,proto3" json:"recordId,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *ReqCollateralizeRecord) Reset() { *m = ReqCollateralizeRecord{} }
func (m *ReqCollateralizeRecord) String() string { return proto.CompactTextString(m) }
func (*ReqCollateralizeRecord) ProtoMessage() {}
func (*ReqCollateralizeRecord) Descriptor() ([]byte, []int) {
return fileDescriptor_collateralize_eee08d5094b5a295, []int{24}
}
func (m *ReqCollateralizeRecord) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ReqCollateralizeRecord.Unmarshal(m, b)
}
func (m *ReqCollateralizeRecord) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_ReqCollateralizeRecord.Marshal(b, m, deterministic)
}
func (dst *ReqCollateralizeRecord) XXX_Merge(src proto.Message) {
xxx_messageInfo_ReqCollateralizeRecord.Merge(dst, src)
}
func (m *ReqCollateralizeRecord) XXX_Size() int {
return xxx_messageInfo_ReqCollateralizeRecord.Size(m)
}
func (m *ReqCollateralizeRecord) XXX_DiscardUnknown() {
xxx_messageInfo_ReqCollateralizeRecord.DiscardUnknown(m)
}
var xxx_messageInfo_ReqCollateralizeRecord proto.InternalMessageInfo
func (m *ReqCollateralizeRecord) GetCollateralizeId() string {
if m != nil {
return m.CollateralizeId
}
return ""
}
func (m *ReqCollateralizeRecord) GetRecordId() string {
if m != nil {
return m.RecordId
}
return ""
}
// 返回借贷记录
type RepCollateralizeRecord struct {
Record *BorrowRecord `protobuf:"bytes,1,opt,name=record,proto3" json:"record,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *RepCollateralizeRecord) Reset() { *m = RepCollateralizeRecord{} }
func (m *RepCollateralizeRecord) String() string { return proto.CompactTextString(m) }
func (*RepCollateralizeRecord) ProtoMessage() {}
func (*RepCollateralizeRecord) Descriptor() ([]byte, []int) {
return fileDescriptor_collateralize_eee08d5094b5a295, []int{25}
}
func (m *RepCollateralizeRecord) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_RepCollateralizeRecord.Unmarshal(m, b)
}
func (m *RepCollateralizeRecord) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_RepCollateralizeRecord.Marshal(b, m, deterministic)
}
func (dst *RepCollateralizeRecord) XXX_Merge(src proto.Message) {
xxx_messageInfo_RepCollateralizeRecord.Merge(dst, src)
}
func (m *RepCollateralizeRecord) XXX_Size() int {
return xxx_messageInfo_RepCollateralizeRecord.Size(m)
}
func (m *RepCollateralizeRecord) XXX_DiscardUnknown() {
xxx_messageInfo_RepCollateralizeRecord.DiscardUnknown(m)
}
var xxx_messageInfo_RepCollateralizeRecord proto.InternalMessageInfo
func (m *RepCollateralizeRecord) GetRecord() *BorrowRecord {
if m != nil {
return m.Record
}
return nil
}
// 返回放贷配置
type RepCollateralizeConfig struct {
DebtCeiling int64 `protobuf:"varint,1,opt,name=debtCeiling,proto3" json:"debtCeiling,omitempty"`
LiquidationRatio int64 `protobuf:"varint,2,opt,name=liquidationRatio,proto3" json:"liquidationRatio,omitempty"`
StabilityFeeRatio int64 `protobuf:"varint,3,opt,name=stabilityFeeRatio,proto3" json:"stabilityFeeRatio,omitempty"`
Period int64 `protobuf:"varint,4,opt,name=period,proto3" json:"period,omitempty"`
TotalBalance int64 `protobuf:"varint,5,opt,name=totalBalance,proto3" json:"totalBalance,omitempty"`
Balance int64 `protobuf:"varint,6,opt,name=balance,proto3" json:"balance,omitempty"`
CurrentTime int64 `protobuf:"varint,7,opt,name=currentTime,proto3" json:"currentTime,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *RepCollateralizeConfig) Reset() { *m = RepCollateralizeConfig{} }
func (m *RepCollateralizeConfig) String() string { return proto.CompactTextString(m) }
func (*RepCollateralizeConfig) ProtoMessage() {}
func (*RepCollateralizeConfig) Descriptor() ([]byte, []int) {
return fileDescriptor_collateralize_eee08d5094b5a295, []int{26}
}
func (m *RepCollateralizeConfig) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_RepCollateralizeConfig.Unmarshal(m, b)
}
func (m *RepCollateralizeConfig) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_RepCollateralizeConfig.Marshal(b, m, deterministic)
}
func (dst *RepCollateralizeConfig) XXX_Merge(src proto.Message) {
xxx_messageInfo_RepCollateralizeConfig.Merge(dst, src)
}
func (m *RepCollateralizeConfig) XXX_Size() int {
return xxx_messageInfo_RepCollateralizeConfig.Size(m)
}
func (m *RepCollateralizeConfig) XXX_DiscardUnknown() {
xxx_messageInfo_RepCollateralizeConfig.DiscardUnknown(m)
}
var xxx_messageInfo_RepCollateralizeConfig proto.InternalMessageInfo
func (m *RepCollateralizeConfig) GetDebtCeiling() int64 {
if m != nil {
return m.DebtCeiling
}
return 0
}
func (m *RepCollateralizeConfig) GetLiquidationRatio() int64 {
if m != nil {
return m.LiquidationRatio
}
return 0
}
func (m *RepCollateralizeConfig) GetStabilityFeeRatio() int64 {
if m != nil {
return m.StabilityFeeRatio
}
return 0
}
func (m *RepCollateralizeConfig) GetPeriod() int64 {
if m != nil {
return m.Period
}
return 0
}
func (m *RepCollateralizeConfig) GetTotalBalance() int64 {
if m != nil {
return m.TotalBalance
}
return 0
}
func (m *RepCollateralizeConfig) GetBalance() int64 {
if m != nil {
return m.Balance
}
return 0
}
func (m *RepCollateralizeConfig) GetCurrentTime() int64 {
if m != nil {
return m.CurrentTime
}
return 0
}
// 返回最新抵押物价格
type RepCollateralizePrice struct {
Price int64 `protobuf:"varint,1,opt,name=price,proto3" json:"price,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *RepCollateralizePrice) Reset() { *m = RepCollateralizePrice{} }
func (m *RepCollateralizePrice) String() string { return proto.CompactTextString(m) }
func (*RepCollateralizePrice) ProtoMessage() {}
func (*RepCollateralizePrice) Descriptor() ([]byte, []int) {
return fileDescriptor_collateralize_eee08d5094b5a295, []int{27}
}
func (m *RepCollateralizePrice) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_RepCollateralizePrice.Unmarshal(m, b)
}
func (m *RepCollateralizePrice) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_RepCollateralizePrice.Marshal(b, m, deterministic)
}
func (dst *RepCollateralizePrice) XXX_Merge(src proto.Message) {
xxx_messageInfo_RepCollateralizePrice.Merge(dst, src)
}
func (m *RepCollateralizePrice) XXX_Size() int {
return xxx_messageInfo_RepCollateralizePrice.Size(m)
}
func (m *RepCollateralizePrice) XXX_DiscardUnknown() {
xxx_messageInfo_RepCollateralizePrice.DiscardUnknown(m)
}
var xxx_messageInfo_RepCollateralizePrice proto.InternalMessageInfo
func (m *RepCollateralizePrice) GetPrice() int64 {
if m != nil {
return m.Price
}
return 0
}
// 返回用户借贷总额
type RepCollateralizeUserBalance struct {
Balance int64 `protobuf:"varint,1,opt,name=balance,proto3" json:"balance,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *RepCollateralizeUserBalance) Reset() { *m = RepCollateralizeUserBalance{} }
func (m *RepCollateralizeUserBalance) String() string { return proto.CompactTextString(m) }
func (*RepCollateralizeUserBalance) ProtoMessage() {}
func (*RepCollateralizeUserBalance) Descriptor() ([]byte, []int) {
return fileDescriptor_collateralize_eee08d5094b5a295, []int{28}
}
func (m *RepCollateralizeUserBalance) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_RepCollateralizeUserBalance.Unmarshal(m, b)
}
func (m *RepCollateralizeUserBalance) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_RepCollateralizeUserBalance.Marshal(b, m, deterministic)
}
func (dst *RepCollateralizeUserBalance) XXX_Merge(src proto.Message) {
xxx_messageInfo_RepCollateralizeUserBalance.Merge(dst, src)
}
func (m *RepCollateralizeUserBalance) XXX_Size() int {
return xxx_messageInfo_RepCollateralizeUserBalance.Size(m)
}
func (m *RepCollateralizeUserBalance) XXX_DiscardUnknown() {
xxx_messageInfo_RepCollateralizeUserBalance.DiscardUnknown(m)
}
var xxx_messageInfo_RepCollateralizeUserBalance proto.InternalMessageInfo
func (m *RepCollateralizeUserBalance) GetBalance() int64 {
if m != nil {
return m.Balance
}
return 0
}
func init() {
proto.RegisterType((*Collateralize)(nil), "types.Collateralize")
proto.RegisterType((*BorrowRecord)(nil), "types.BorrowRecord")
proto.RegisterType((*AssetPriceRecord)(nil), "types.AssetPriceRecord")
proto.RegisterType((*CollateralizeAction)(nil), "types.CollateralizeAction")
proto.RegisterType((*CollateralizeManage)(nil), "types.CollateralizeManage")
proto.RegisterType((*CollateralizeAddr)(nil), "types.CollateralizeAddr")
proto.RegisterType((*CollateralizeCreate)(nil), "types.CollateralizeCreate")
proto.RegisterType((*CollateralizeBorrow)(nil), "types.CollateralizeBorrow")
proto.RegisterType((*CollateralizeRepay)(nil), "types.CollateralizeRepay")
proto.RegisterType((*CollateralizeAppend)(nil), "types.CollateralizeAppend")
proto.RegisterType((*CollateralizeFeed)(nil), "types.CollateralizeFeed")
proto.RegisterType((*CollateralizeRetrieve)(nil), "types.CollateralizeRetrieve")
proto.RegisterType((*ReceiptCollateralize)(nil), "types.ReceiptCollateralize")
proto.RegisterType((*CollateralizeRecords)(nil), "types.CollateralizeRecords")
proto.RegisterType((*ReqCollateralizeInfo)(nil), "types.ReqCollateralizeInfo")
proto.RegisterType((*RepCollateralizeCurrentInfo)(nil), "types.RepCollateralizeCurrentInfo")
proto.RegisterType((*ReqCollateralizeInfos)(nil), "types.ReqCollateralizeInfos")
proto.RegisterType((*RepCollateralizeCurrentInfos)(nil), "types.RepCollateralizeCurrentInfos")
proto.RegisterType((*ReqCollateralizeByStatus)(nil), "types.ReqCollateralizeByStatus")
proto.RegisterType((*ReqCollateralizeByAddr)(nil), "types.ReqCollateralizeByAddr")
proto.RegisterType((*RepCollateralizeIDs)(nil), "types.RepCollateralizeIDs")
proto.RegisterType((*ReqCollateralizeRecordByAddr)(nil), "types.ReqCollateralizeRecordByAddr")
proto.RegisterType((*ReqCollateralizeRecordByStatus)(nil), "types.ReqCollateralizeRecordByStatus")
proto.RegisterType((*RepCollateralizeRecords)(nil), "types.RepCollateralizeRecords")
proto.RegisterType((*ReqCollateralizeRecord)(nil), "types.ReqCollateralizeRecord")
proto.RegisterType((*RepCollateralizeRecord)(nil), "types.RepCollateralizeRecord")
proto.RegisterType((*RepCollateralizeConfig)(nil), "types.RepCollateralizeConfig")
proto.RegisterType((*RepCollateralizePrice)(nil), "types.RepCollateralizePrice")
proto.RegisterType((*RepCollateralizeUserBalance)(nil), "types.RepCollateralizeUserBalance")
}
func init() { proto.RegisterFile("collateralize.proto", fileDescriptor_collateralize_eee08d5094b5a295) }
var fileDescriptor_collateralize_eee08d5094b5a295 = []byte{
// 1208 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xdc, 0x58, 0x5b, 0x6f, 0xdc, 0x44,
0x14, 0x8e, 0xd7, 0x7b, 0xc9, 0x9e, 0x4d, 0xd2, 0x74, 0x92, 0x06, 0xd3, 0x46, 0xd1, 0x6a, 0x84,
0x44, 0x04, 0x34, 0x12, 0x29, 0xb7, 0xc2, 0x0b, 0xb9, 0xb4, 0xca, 0x22, 0x2a, 0x21, 0xd3, 0x22,
0xc4, 0x4d, 0xf2, 0xda, 0x93, 0x60, 0xc9, 0x59, 0x3b, 0xf6, 0x6c, 0x60, 0x79, 0xe0, 0x0d, 0x9e,
0x78, 0xe0, 0x89, 0x7f, 0xc0, 0x2b, 0x7f, 0x89, 0x9f, 0xc0, 0x5f, 0x40, 0x33, 0x67, 0x7c, 0x99,
0xb1, 0x5d, 0x6d, 0x50, 0x5f, 0xe8, 0x4b, 0xb5, 0x73, 0xe6, 0x3b, 0xc7, 0xdf, 0x7c, 0xe7, 0xcc,
0x99, 0xd3, 0xc0, 0x96, 0x1f, 0x47, 0x91, 0xc7, 0x59, 0xea, 0x45, 0xe1, 0x4f, 0xec, 0x20, 0x49,
0x63, 0x1e, 0x93, 0x1e, 0x5f, 0x24, 0x2c, 0xa3, 0x7f, 0x77, 0x61, 0xfd, 0xa4, 0xba, 0x4d, 0xf6,
0xe1, 0x96, 0x86, 0x9f, 0x04, 0x8e, 0x35, 0xb6, 0xf6, 0x87, 0xae, 0x69, 0x26, 0x14, 0xd6, 0x78,
0xcc, 0xbd, 0xe8, 0xd8, 0x8b, 0xbc, 0x99, 0xcf, 0x9c, 0xce, 0xd8, 0xda, 0xb7, 0x5d, 0xcd, 0x46,
0xc6, 0x30, 0x0a, 0xd8, 0x94, 0x9f, 0xb0, 0x30, 0x0a, 0x67, 0x17, 0x8e, 0x2d, 0x21, 0x55, 0x13,
0x79, 0x03, 0x36, 0xa3, 0xf0, 0x6a, 0x1e, 0x06, 0x1e, 0x0f, 0xe3, 0x99, 0x2b, 0xfe, 0x75, 0xba,
0x12, 0x56, 0xb3, 0x93, 0xb7, 0xe0, 0x76, 0xc6, 0xbd, 0x69, 0x18, 0x85, 0x7c, 0xf1, 0x98, 0x31,
0x04, 0xf7, 0x24, 0xb8, 0xbe, 0x41, 0xf6, 0x00, 0xfc, 0x94, 0x79, 0x9c, 0x1d, 0x05, 0x41, 0xea,
0xf4, 0xe5, 0x21, 0x2a, 0x16, 0xe2, 0xc0, 0x60, 0xaa, 0xa8, 0x0f, 0x64, 0x8c, 0x7c, 0x49, 0x1e,
0xc2, 0xfa, 0x34, 0x4e, 0xd3, 0xf8, 0x07, 0x97, 0xf9, 0x71, 0x1a, 0x64, 0xce, 0xea, 0xd8, 0xde,
0x1f, 0x1d, 0x6e, 0x1d, 0x48, 0xd1, 0x0e, 0x8e, 0x2b, 0x7b, 0xae, 0x8e, 0x24, 0x1f, 0xc1, 0xc6,
0x64, 0x76, 0xed, 0x45, 0x61, 0x90, 0xfb, 0x0e, 0xdb, 0x7d, 0x0d, 0x28, 0xd9, 0x81, 0x7e, 0xc6,
0x3d, 0x3e, 0xcf, 0x1c, 0x18, 0x5b, 0xfb, 0x3d, 0x57, 0xad, 0xc8, 0x7b, 0xb0, 0x23, 0x94, 0xcf,
0xf8, 0xa7, 0xa5, 0x22, 0x9f, 0xa5, 0xa1, 0xcf, 0x9c, 0x91, 0x24, 0xde, 0xb2, 0x2b, 0xe2, 0x25,
0x2c, 0x0d, 0xe3, 0xc0, 0x59, 0x93, 0x38, 0xb5, 0x92, 0x9a, 0x4b, 0x8f, 0x47, 0x3f, 0x26, 0x61,
0xca, 0x9e, 0x86, 0x97, 0xcc, 0x59, 0x57, 0x9a, 0x1b, 0x76, 0x91, 0x41, 0x91, 0xf8, 0x3c, 0xc9,
0x1b, 0x98, 0xc1, 0x8a, 0x89, 0xec, 0xc2, 0x30, 0x49, 0xd9, 0xe7, 0x48, 0xfc, 0x96, 0x24, 0x5e,
0x1a, 0xe8, 0x5f, 0x36, 0xac, 0x55, 0x0f, 0x2d, 0x02, 0x7a, 0xbe, 0x1f, 0xcf, 0x67, 0x5c, 0xe6,
0x05, 0x8b, 0xab, 0x6a, 0x12, 0x01, 0x33, 0xee, 0xa5, 0x5c, 0xf2, 0xc2, 0xaa, 0x2a, 0x0d, 0x7a,
0x81, 0x7e, 0xe1, 0x45, 0x73, 0xa6, 0xca, 0xca, 0x34, 0xeb, 0x48, 0xd4, 0xab, 0x6b, 0x22, 0x51,
0xa8, 0x5d, 0x18, 0x8a, 0x9a, 0xc4, 0x68, 0x58, 0x50, 0xa5, 0xc1, 0x28, 0x51, 0x0c, 0xd4, 0xaf,
0x95, 0x68, 0x21, 0xb9, 0x4a, 0xe1, 0x40, 0x4b, 0xe1, 0x6b, 0xb0, 0x9e, 0x63, 0x51, 0xef, 0x55,
0x19, 0x40, 0x37, 0x8a, 0x92, 0x65, 0x65, 0x4a, 0x86, 0x12, 0x52, 0xb1, 0xe8, 0x52, 0x83, 0x21,
0x35, 0xb9, 0x0b, 0xab, 0xa9, 0xd4, 0x78, 0x12, 0xc8, 0xc2, 0x18, 0xba, 0xc5, 0xba, 0xe9, 0x5a,
0xaf, 0x35, 0x5e, 0x6b, 0xfa, 0xab, 0x05, 0x9b, 0x47, 0x59, 0xc6, 0xb8, 0x3c, 0x90, 0x4a, 0xda,
0x1e, 0x00, 0x86, 0x92, 0xc4, 0x2c, 0x24, 0x56, 0x5a, 0xc4, 0xa7, 0xa7, 0x7c, 0x81, 0xd2, 0x60,
0xc6, 0x8a, 0x35, 0xee, 0xf9, 0xb8, 0x67, 0xe7, 0x7b, 0x7e, 0xb1, 0xc7, 0xf8, 0xf7, 0xd5, 0xdc,
0x14, 0x6b, 0xfa, 0xa7, 0x0d, 0x5b, 0x5a, 0x6f, 0x3a, 0xf2, 0x85, 0xce, 0xe4, 0x1d, 0xe8, 0xe3,
0x2d, 0x96, 0x3c, 0x46, 0x87, 0x77, 0xd5, 0xd5, 0xd2, 0xb0, 0x27, 0x12, 0x71, 0xb6, 0xe2, 0x2a,
0xac, 0xf0, 0xc2, 0x9b, 0x2a, 0xf9, 0xb5, 0x78, 0x61, 0xa1, 0x0a, 0x2f, 0xc4, 0x92, 0xb7, 0xa1,
0x97, 0xb2, 0xc4, 0x5b, 0x48, 0xe2, 0xa3, 0xc3, 0x57, 0x9b, 0x9c, 0x5c, 0x01, 0x38, 0x5b, 0x71,
0x11, 0x29, 0x3e, 0xe4, 0x25, 0x09, 0x9b, 0x05, 0xf2, 0x40, 0x2d, 0x1f, 0x3a, 0x92, 0x08, 0xf1,
0x21, 0xc4, 0x92, 0x03, 0xe8, 0x9e, 0x33, 0x16, 0xc8, 0xe2, 0x1b, 0x1d, 0x3a, 0x4d, 0x3e, 0x8f,
0x19, 0x13, 0x1e, 0x12, 0x47, 0x3e, 0x14, 0xb9, 0xe6, 0x69, 0xc8, 0xae, 0xb1, 0x16, 0x47, 0x87,
0xbb, 0xcd, 0xdc, 0x10, 0x73, 0xb6, 0xe2, 0x16, 0x78, 0xc1, 0xf0, 0xd2, 0x9b, 0x79, 0x17, 0xd8,
0xf7, 0x5a, 0x18, 0x3e, 0x91, 0x08, 0xc1, 0x10, 0xb1, 0x64, 0x03, 0x3a, 0x7c, 0xa1, 0x8a, 0xae,
0xc3, 0x17, 0xc7, 0x03, 0xe8, 0x5d, 0x8b, 0xeb, 0x41, 0xff, 0xb1, 0x8c, 0x3c, 0xa1, 0xab, 0xd9,
0xfb, 0xad, 0xe5, 0x7a, 0x7f, 0xe7, 0x26, 0xbd, 0xdf, 0x6e, 0xeb, 0xfd, 0x65, 0xe7, 0xeb, 0x6a,
0x9d, 0xcf, 0x7c, 0xb3, 0x7a, 0xcd, 0x6f, 0x96, 0x3f, 0x4f, 0x53, 0x36, 0xc3, 0x06, 0xd4, 0x57,
0x1d, 0xaf, 0x34, 0xd1, 0x07, 0x70, 0x5b, 0xcf, 0xa6, 0xe8, 0x5a, 0x7b, 0x00, 0xd9, 0x3c, 0x61,
0xa9, 0x58, 0x64, 0x8e, 0x35, 0xb6, 0xc5, 0x73, 0x53, 0x5a, 0xe8, 0x43, 0x43, 0x25, 0xac, 0xd0,
0x1a, 0x23, 0xab, 0xce, 0x88, 0x3e, 0x33, 0x5c, 0xb1, 0x4c, 0x6f, 0xf0, 0x54, 0x6f, 0xab, 0x5c,
0x29, 0x75, 0x55, 0xe2, 0xbe, 0x02, 0x52, 0x2f, 0xe4, 0x1b, 0x44, 0xad, 0xf6, 0x9b, 0x8e, 0xde,
0x6f, 0xe8, 0x2f, 0x66, 0x51, 0x60, 0xc5, 0xbf, 0x98, 0xe8, 0xcb, 0xbf, 0x01, 0xf4, 0x5b, 0x23,
0x55, 0xe2, 0x12, 0x89, 0xd0, 0x02, 0xf7, 0x74, 0x91, 0xa0, 0xde, 0x3d, 0xb7, 0x58, 0x0b, 0xa9,
0x12, 0xd5, 0xc6, 0x6c, 0x21, 0x55, 0x92, 0xb7, 0xf5, 0xeb, 0x38, 0x9a, 0x5f, 0x8a, 0xef, 0x08,
0xb3, 0x5a, 0xd1, 0xaf, 0xe1, 0x4e, 0xe3, 0x7d, 0xbb, 0xc1, 0x39, 0x2b, 0x63, 0x48, 0x47, 0x1b,
0x43, 0xe8, 0x1f, 0x16, 0x6c, 0xbb, 0xcc, 0x67, 0x61, 0xc2, 0xff, 0xeb, 0x8c, 0x66, 0x3c, 0xb6,
0x76, 0xfd, 0xb1, 0xad, 0xca, 0xdc, 0x35, 0x64, 0x2e, 0x1f, 0xb3, 0x5e, 0xf5, 0x31, 0xa3, 0x4f,
0x60, 0xdb, 0x38, 0x35, 0xce, 0x2f, 0xef, 0xc2, 0x20, 0x55, 0x53, 0x8f, 0x25, 0xa7, 0x9e, 0x7b,
0xaa, 0xb3, 0x34, 0x9d, 0xc2, 0xcd, 0xb1, 0xf4, 0x63, 0x71, 0xcc, 0x2b, 0x6d, 0x73, 0x32, 0x3b,
0x8f, 0x97, 0x3f, 0xa6, 0x18, 0x32, 0xee, 0xb9, 0x2c, 0xd1, 0xef, 0x17, 0x5e, 0x58, 0x19, 0xa9,
0x3c, 0x88, 0xa5, 0xbd, 0xca, 0x2f, 0xef, 0x08, 0x5b, 0x36, 0xc0, 0x55, 0xad, 0x01, 0x36, 0x68,
0x3a, 0x6c, 0x2d, 0x9d, 0xea, 0xe0, 0x07, 0xf5, 0xc1, 0xaf, 0x36, 0x26, 0x8f, 0x96, 0x1d, 0x93,
0xe9, 0x09, 0xdc, 0x69, 0x4a, 0x79, 0x26, 0xb4, 0x34, 0x88, 0xe4, 0xbd, 0xb4, 0x66, 0xa7, 0x5f,
0xc2, 0xee, 0x73, 0x92, 0x9e, 0x91, 0x0f, 0xa0, 0x17, 0x8a, 0x1f, 0xaa, 0x18, 0x69, 0x51, 0x8c,
0xad, 0x3e, 0x2e, 0x3a, 0xd0, 0x4f, 0xc0, 0x31, 0xe9, 0x1d, 0x2f, 0xd4, 0x94, 0xd5, 0x56, 0x4b,
0x3b, 0xd0, 0x17, 0x0c, 0x27, 0xa7, 0xaa, 0x5b, 0xa9, 0x15, 0xfd, 0x06, 0x76, 0xea, 0xb1, 0x64,
0xf6, 0x08, 0x74, 0xbd, 0x72, 0x04, 0x96, 0xbf, 0x2b, 0xd1, 0x3b, 0x2d, 0xd1, 0x6d, 0x2d, 0xfa,
0xeb, 0xb0, 0x65, 0x9e, 0x67, 0x72, 0x9a, 0x91, 0x4d, 0xb0, 0x27, 0xa7, 0xb9, 0x72, 0xe2, 0x27,
0xfd, 0xdd, 0x12, 0x6a, 0x5d, 0x35, 0xdc, 0x5b, 0xc5, 0x66, 0xf9, 0xa6, 0x92, 0xf3, 0xee, 0x34,
0xf2, 0xb6, 0x35, 0xde, 0xcf, 0x69, 0x2f, 0xf4, 0x67, 0xd8, 0x6b, 0x63, 0xa4, 0xb4, 0x5e, 0x9e,
0x53, 0x9b, 0x6e, 0xd5, 0xef, 0xdb, 0xc6, 0xf7, 0xcf, 0xe0, 0x15, 0x53, 0xbb, 0xbc, 0x93, 0xdd,
0x37, 0x3b, 0x59, 0x63, 0x51, 0x17, 0x1d, 0xec, 0xbb, 0x7a, 0x8e, 0xd5, 0xe0, 0xfc, 0x62, 0x5e,
0xd3, 0x47, 0x22, 0x7e, 0x13, 0x53, 0xf2, 0x26, 0xf4, 0x11, 0xa5, 0x86, 0xe1, 0x46, 0x9e, 0x0a,
0x42, 0x7f, 0xeb, 0xd4, 0xe3, 0x9c, 0xc4, 0xb3, 0xf3, 0xf0, 0xe2, 0x7f, 0x3b, 0xac, 0x55, 0x3a,
0x60, 0x5f, 0xef, 0x80, 0xc6, 0x18, 0x37, 0xa8, 0x8f, 0x71, 0xf7, 0x45, 0x13, 0xd2, 0xd5, 0xc0,
0xff, 0x95, 0x14, 0x33, 0x00, 0xca, 0x80, 0x0b, 0xfa, 0x7e, 0xfd, 0x8d, 0x79, 0x96, 0xb1, 0xb4,
0x81, 0x89, 0xa5, 0x31, 0x99, 0xf6, 0xe5, 0x9f, 0x5c, 0x1e, 0xfc, 0x1b, 0x00, 0x00, 0xff, 0xff,
0x0c, 0xfe, 0xe3, 0xa0, 0x89, 0x11, 0x00, 0x00,
}
// 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 {
......
......@@ -437,81 +437,294 @@ func TestExchange(t *testing.T) {
assert.NotEqual(t, nil, err)
err = Exec_RevokeOrder(t, orderID, PrivKeyB, stateDB, kvdb, env)
assert.Equal(t, nil, err)
//清理环境,重建数据库
util.CloseTestDB(dir, stateDB)
total = 1000 * types.Coin
accountA = types.Account{
Balance: total,
Frozen: 0,
Addr: Nodes[0],
}
accountB = types.Account{
Balance: total,
Frozen: 0,
Addr: Nodes[1],
}
dir, stateDB, kvdb = util.CreateTestDB()
defer util.CloseTestDB(dir, stateDB)
//execAddr := address.ExecAddress(et.ExchangeX)
accA, _ = account.NewAccountDB(cfg, "coins", "bty", stateDB)
accA.SaveExecAccount(execAddr, &accountA)
accB, _ = account.NewAccountDB(cfg, "coins", "bty", stateDB)
accB.SaveExecAccount(execAddr, &accountB)
accA1, _ = account.NewAccountDB(cfg, "token", "CCNY", stateDB)
accA1.SaveExecAccount(execAddr, &accountA)
accB1, _ = account.NewAccountDB(cfg, "token", "CCNY", stateDB)
accB1.SaveExecAccount(execAddr, &accountB)
env = &execEnv{
10,
1,
1539918074,
}
/*
//批量测试,同一个区块内出现多笔可以撮合的买卖交易
用例说明:
1.在同一个区块内,出现如下:
10笔买单
20笔卖单
50笔买单
20笔卖单
50笔买单
100笔卖单
*/
acc = accB1.LoadExecAccount(Nodes[1], execAddr)
assert.Equal(t, 1000*types.Coin, acc.Balance)
acc = accA.LoadExecAccount(Nodes[0], execAddr)
assert.Equal(t, 1000*types.Coin, acc.Balance)
var txs []*types.Transaction
for i := 0; i < 10; i++ {
tx, err := CreateLimitOrder(&et.LimitOrder{LeftAsset: &et.Asset{Symbol: "bty", Execer: "coins"},
RightAsset: &et.Asset{Execer: "token", Symbol: "CCNY"}, Price: types.Coin, Amount: types.Coin, Op: et.OpBuy}, PrivKeyB)
assert.Equal(t, nil, err)
txs = append(txs, tx)
}
for i := 0; i < 20; i++ {
tx, err := CreateLimitOrder(&et.LimitOrder{LeftAsset: &et.Asset{Symbol: "bty", Execer: "coins"},
RightAsset: &et.Asset{Execer: "token", Symbol: "CCNY"}, Price: types.Coin, Amount: types.Coin, Op: et.OpSell}, PrivKeyA)
assert.Equal(t, nil, err)
txs = append(txs, tx)
}
for i := 0; i < 50; i++ {
tx, err := CreateLimitOrder(&et.LimitOrder{LeftAsset: &et.Asset{Symbol: "bty", Execer: "coins"},
RightAsset: &et.Asset{Execer: "token", Symbol: "CCNY"}, Price: types.Coin, Amount: types.Coin, Op: et.OpBuy}, PrivKeyB)
assert.Equal(t, nil, err)
txs = append(txs, tx)
}
for i := 0; i < 20; i++ {
tx, err := CreateLimitOrder(&et.LimitOrder{LeftAsset: &et.Asset{Symbol: "bty", Execer: "coins"},
RightAsset: &et.Asset{Execer: "token", Symbol: "CCNY"}, Price: types.Coin, Amount: types.Coin, Op: et.OpSell}, PrivKeyA)
assert.Equal(t, nil, err)
txs = append(txs, tx)
}
for i := 0; i < 50; i++ {
tx, err := CreateLimitOrder(&et.LimitOrder{LeftAsset: &et.Asset{Symbol: "bty", Execer: "coins"},
RightAsset: &et.Asset{Execer: "token", Symbol: "CCNY"}, Price: types.Coin, Amount: types.Coin, Op: et.OpBuy}, PrivKeyB)
assert.Equal(t, nil, err)
txs = append(txs, tx)
}
for i := 0; i < 100; i++ {
tx, err := CreateLimitOrder(&et.LimitOrder{LeftAsset: &et.Asset{Symbol: "bty", Execer: "coins"},
RightAsset: &et.Asset{Execer: "token", Symbol: "CCNY"}, Price: types.Coin, Amount: types.Coin, Op: et.OpSell}, PrivKeyA)
assert.Equal(t, nil, err)
txs = append(txs, tx)
}
err = Exec_Block(t, stateDB, kvdb, env, txs...)
assert.Equal(t, nil, err)
acc = accB1.LoadExecAccount(Nodes[1], execAddr)
assert.Equal(t, 890*types.Coin, acc.Balance)
acc = accA.LoadExecAccount(Nodes[0], execAddr)
assert.Equal(t, 860*types.Coin, acc.Balance)
assert.Equal(t, 30*types.Coin, acc.Frozen)
//根据op查询市场深度
marketDepthList, err = Exec_QueryMarketDepth(&et.QueryMarketDepth{LeftAsset: &et.Asset{Symbol: "bty", Execer: "coins"},
RightAsset: &et.Asset{Execer: "token", Symbol: "CCNY"}, Op: et.OpBuy}, stateDB, kvdb)
assert.NotEqual(t, nil, err)
//assert.Equal(t, (200-et.MaxMatchCount)*types.Coin, marketDepthList.List[0].GetAmount())
marketDepthList, err = Exec_QueryMarketDepth(&et.QueryMarketDepth{LeftAsset: &et.Asset{Symbol: "bty", Execer: "coins"},
RightAsset: &et.Asset{Execer: "token", Symbol: "CCNY"}, Op: et.OpSell}, stateDB, kvdb)
assert.Equal(t, nil, err)
assert.Equal(t, 30*types.Coin, marketDepthList.List[0].GetAmount())
//清理环境,重建数据库
util.CloseTestDB(dir, stateDB)
total = 1000 * types.Coin
accountA = types.Account{
Balance: total,
Frozen: 0,
Addr: Nodes[0],
}
accountB = types.Account{
Balance: total,
Frozen: 0,
Addr: Nodes[1],
}
dir, stateDB, kvdb = util.CreateTestDB()
defer util.CloseTestDB(dir, stateDB)
//execAddr := address.ExecAddress(et.ExchangeX)
accA, _ = account.NewAccountDB(cfg, "coins", "bty", stateDB)
accA.SaveExecAccount(execAddr, &accountA)
accB, _ = account.NewAccountDB(cfg, "coins", "bty", stateDB)
accB.SaveExecAccount(execAddr, &accountB)
accA1, _ = account.NewAccountDB(cfg, "token", "CCNY", stateDB)
accA1.SaveExecAccount(execAddr, &accountA)
accB1, _ = account.NewAccountDB(cfg, "token", "CCNY", stateDB)
accB1.SaveExecAccount(execAddr, &accountB)
env = &execEnv{
10,
1,
1539918074,
}
/*
//批量测试,同个区块内出现多笔可以撮合的买卖交易
用例说明:
1.在同一区块内,出现如下:
100笔卖单
50笔买单
20笔卖单
100笔买单
*/
acc = accB1.LoadExecAccount(Nodes[1], execAddr)
assert.Equal(t, 1000*types.Coin, acc.Balance)
acc = accA.LoadExecAccount(Nodes[0], execAddr)
assert.Equal(t, 1000*types.Coin, acc.Balance)
txs = nil
for i := 0; i < 100; i++ {
tx, err := CreateLimitOrder(&et.LimitOrder{LeftAsset: &et.Asset{Symbol: "bty", Execer: "coins"},
RightAsset: &et.Asset{Execer: "token", Symbol: "CCNY"}, Price: types.Coin, Amount: types.Coin, Op: et.OpSell}, PrivKeyA)
assert.Equal(t, nil, err)
txs = append(txs, tx)
}
for i := 0; i < 50; i++ {
tx, err := CreateLimitOrder(&et.LimitOrder{LeftAsset: &et.Asset{Symbol: "bty", Execer: "coins"},
RightAsset: &et.Asset{Execer: "token", Symbol: "CCNY"}, Price: types.Coin, Amount: types.Coin, Op: et.OpBuy}, PrivKeyB)
assert.Equal(t, nil, err)
txs = append(txs, tx)
}
for i := 0; i < 20; i++ {
tx, err := CreateLimitOrder(&et.LimitOrder{LeftAsset: &et.Asset{Symbol: "bty", Execer: "coins"},
RightAsset: &et.Asset{Execer: "token", Symbol: "CCNY"}, Price: types.Coin, Amount: types.Coin, Op: et.OpSell}, PrivKeyA)
assert.Equal(t, nil, err)
txs = append(txs, tx)
}
for i := 0; i < 100; i++ {
tx, err := CreateLimitOrder(&et.LimitOrder{LeftAsset: &et.Asset{Symbol: "bty", Execer: "coins"},
RightAsset: &et.Asset{Execer: "token", Symbol: "CCNY"}, Price: types.Coin, Amount: types.Coin, Op: et.OpBuy}, PrivKeyB)
assert.Equal(t, nil, err)
txs = append(txs, tx)
}
err = Exec_Block(t, stateDB, kvdb, env, txs...)
assert.Equal(t, nil, err)
acc = accB1.LoadExecAccount(Nodes[1], execAddr)
assert.Equal(t, 850*types.Coin, acc.Balance)
assert.Equal(t, 30*types.Coin, acc.Frozen)
acc = accA.LoadExecAccount(Nodes[0], execAddr)
assert.Equal(t, 880*types.Coin, acc.Balance)
//根据op查询市场深度
marketDepthList, err = Exec_QueryMarketDepth(&et.QueryMarketDepth{LeftAsset: &et.Asset{Symbol: "bty", Execer: "coins"},
RightAsset: &et.Asset{Execer: "token", Symbol: "CCNY"}, Op: et.OpSell}, stateDB, kvdb)
assert.NotEqual(t, nil, err)
marketDepthList, err = Exec_QueryMarketDepth(&et.QueryMarketDepth{LeftAsset: &et.Asset{Symbol: "bty", Execer: "coins"},
RightAsset: &et.Asset{Execer: "token", Symbol: "CCNY"}, Op: et.OpBuy}, stateDB, kvdb)
assert.Equal(t, nil, err)
assert.Equal(t, 30*types.Coin, marketDepthList.List[0].GetAmount())
//根据状态地址查询订单信息
//分页查询
count = 0
primaryKey = ""
for {
orderList, err := Exec_QueryOrderList(et.Completed, Nodes[1], primaryKey, stateDB, kvdb)
if err != nil {
break
}
count = count + len(orderList.List)
if orderList.PrimaryKey == "" {
break
}
primaryKey = orderList.PrimaryKey
}
assert.Equal(t, 120, count)
count = 0
primaryKey = ""
for {
orderList, err := Exec_QueryOrderList(et.Ordered, Nodes[1], primaryKey, stateDB, kvdb)
if err != nil {
break
}
count = count + len(orderList.List)
if orderList.PrimaryKey == "" {
break
}
primaryKey = orderList.PrimaryKey
}
assert.Equal(t, 30, count)
}
func Exec_LimitOrder(t *testing.T, limitOrder *et.LimitOrder, privKey string, stateDB db.DB, kvdb db.KVDB, env *execEnv) error {
func CreateLimitOrder(limitOrder *et.LimitOrder, privKey string) (tx *types.Transaction, err error) {
ety := types.LoadExecutorType(et.ExchangeX)
tx, err := ety.Create("LimitOrder", limitOrder)
tx, err = ety.Create("LimitOrder", limitOrder)
if err != nil {
return err
return nil, err
}
cfg := types.NewChain33Config(types.GetDefaultCfgstring())
cfg.SetTitleOnlyForTest("chain33")
tx, err = types.FormatTx(cfg, et.ExchangeX, tx)
if err != nil {
return err
return nil, err
}
tx, err = signTx(tx, privKey)
if err != nil {
return err
}
exec := newExchange()
e := exec.(*exchange)
err = e.CheckTx(tx, 1)
if err != nil {
return err
}
q := queue.New("channel")
q.SetConfig(cfg)
api, _ := client.New(q.Client(), nil)
exec.SetAPI(api)
exec.SetStateDB(stateDB)
exec.SetLocalDB(kvdb)
env.blockHeight = env.blockHeight + 1
env.blockTime = env.blockTime + 20
env.difficulty = env.difficulty + 1
exec.SetEnv(env.blockHeight, env.blockTime, env.difficulty)
receipt, err := exec.Exec(tx, int(1))
if err != nil {
return err
}
for _, kv := range receipt.KV {
stateDB.Set(kv.Key, kv.Value)
}
receiptData := &types.ReceiptData{Ty: receipt.Ty, Logs: receipt.Logs}
set, err := exec.ExecLocal(tx, receiptData, int(1))
if err != nil {
return err
}
for _, kv := range set.KV {
kvdb.Set(kv.Key, kv.Value)
return nil, err
}
//save to database
util.SaveKVList(stateDB, set.KV)
assert.Equal(t, types.ExecOk, int(receipt.Ty))
return nil
return tx, nil
}
func Exec_RevokeOrder(t *testing.T, orderID int64, privKey string, stateDB db.DB, kvdb db.KVDB, env *execEnv) error {
func CreateRevokeOrder(orderID int64, privKey string) (tx *types.Transaction, err error) {
ety := types.LoadExecutorType(et.ExchangeX)
tx, err := ety.Create("RevokeOrder", &et.RevokeOrder{OrderID: orderID})
tx, err = ety.Create("RevokeOrder", &et.RevokeOrder{OrderID: orderID})
if err != nil {
return err
return nil, err
}
cfg := types.NewChain33Config(types.GetDefaultCfgstring())
cfg.SetTitleOnlyForTest("chain33")
tx, err = types.FormatTx(cfg, et.ExchangeX, tx)
if err != nil {
return err
return nil, err
}
tx, err = signTx(tx, privKey)
if err != nil {
return err
return nil, err
}
exec := newExchange()
return tx, nil
}
//模拟区块中交易得执行过程
func Exec_Block(t *testing.T, stateDB db.DB, kvdb db.KVDB, env *execEnv, txs ...*types.Transaction) error {
cfg := types.NewChain33Config(types.GetDefaultCfgstring())
cfg.SetTitleOnlyForTest("chain33")
exec := NewExchange()
e := exec.(*exchange)
err = e.CheckTx(tx, 1)
assert.Nil(t, err)
for index, tx := range txs {
err := e.CheckTx(tx, index)
if err != nil {
t.Log(err.Error())
return err
}
}
q := queue.New("channel")
q.SetConfig(cfg)
api, _ := client.New(q.Client(), nil)
......@@ -522,31 +735,50 @@ func Exec_RevokeOrder(t *testing.T, orderID int64, privKey string, stateDB db.DB
env.blockTime = env.blockTime + 20
env.difficulty = env.difficulty + 1
exec.SetEnv(env.blockHeight, env.blockTime, env.difficulty)
receipt, err := exec.Exec(tx, int(1))
for index, tx := range txs {
receipt, err := exec.Exec(tx, index)
if err != nil {
t.Log(err.Error())
return err
}
for _, kv := range receipt.KV {
stateDB.Set(kv.Key, kv.Value)
}
receiptData := &types.ReceiptData{Ty: receipt.Ty, Logs: receipt.Logs}
set, err := exec.ExecLocal(tx, receiptData, index)
if err != nil {
t.Log(err.Error())
return err
}
for _, kv := range set.KV {
kvdb.Set(kv.Key, kv.Value)
}
//save to database
util.SaveKVList(stateDB, set.KV)
assert.Equal(t, types.ExecOk, int(receipt.Ty))
}
return nil
}
func Exec_LimitOrder(t *testing.T, limitOrder *et.LimitOrder, privKey string, stateDB db.DB, kvdb db.KVDB, env *execEnv) error {
tx, err := CreateLimitOrder(limitOrder, privKey)
if err != nil {
return err
}
for _, kv := range receipt.KV {
stateDB.Set(kv.Key, kv.Value)
}
receiptData := &types.ReceiptData{Ty: receipt.Ty, Logs: receipt.Logs}
set, err := exec.ExecLocal(tx, receiptData, int(1))
return Exec_Block(t, stateDB, kvdb, env, tx)
}
func Exec_RevokeOrder(t *testing.T, orderID int64, privKey string, stateDB db.DB, kvdb db.KVDB, env *execEnv) error {
tx, err := CreateRevokeOrder(orderID, privKey)
if err != nil {
return err
}
for _, kv := range set.KV {
kvdb.Set(kv.Key, kv.Value)
}
//save to database
util.SaveKVList(stateDB, set.KV)
assert.Equal(t, types.ExecOk, int(receipt.Ty))
return nil
return Exec_Block(t, stateDB, kvdb, env, tx)
}
func Exec_QueryOrderList(status int32, addr string, primaryKey string, stateDB db.KV, kvdb db.KVDB) (*et.OrderList, error) {
cfg := types.NewChain33Config(types.GetDefaultCfgstring())
cfg.SetTitleOnlyForTest("chain33")
exec := newExchange()
exec := NewExchange()
q := queue.New("channel")
q.SetConfig(cfg)
api, _ := client.New(q.Client(), nil)
......@@ -563,7 +795,7 @@ func Exec_QueryOrderList(status int32, addr string, primaryKey string, stateDB d
func Exec_QueryOrder(orderID int64, stateDB db.KV, kvdb db.KVDB) (*et.Order, error) {
cfg := types.NewChain33Config(types.GetDefaultCfgstring())
cfg.SetTitleOnlyForTest("chain33")
exec := newExchange()
exec := NewExchange()
q := queue.New("channel")
q.SetConfig(cfg)
api, _ := client.New(q.Client(), nil)
......@@ -581,7 +813,7 @@ func Exec_QueryOrder(orderID int64, stateDB db.KV, kvdb db.KVDB) (*et.Order, err
func Exec_QueryMarketDepth(query *et.QueryMarketDepth, stateDB db.KV, kvdb db.KVDB) (*et.MarketDepthList, error) {
cfg := types.NewChain33Config(types.GetDefaultCfgstring())
cfg.SetTitleOnlyForTest("chain33")
exec := newExchange()
exec := NewExchange()
q := queue.New("channel")
q.SetConfig(cfg)
api, _ := client.New(q.Client(), nil)
......@@ -599,7 +831,7 @@ func Exec_QueryMarketDepth(query *et.QueryMarketDepth, stateDB db.KV, kvdb db.KV
func Exec_QueryHistoryOrder(query *et.QueryHistoryOrderList, stateDB db.KV, kvdb db.KVDB) (*et.OrderList, error) {
cfg := types.NewChain33Config(types.GetDefaultCfgstring())
cfg.SetTitleOnlyForTest("chain33")
exec := newExchange()
exec := NewExchange()
q := queue.New("channel")
q.SetConfig(cfg)
api, _ := client.New(q.Client(), nil)
......
......@@ -45,11 +45,6 @@ func (a *Action) GetKVSet(order *et.Order) (kvset []*types.KeyValue) {
return kvset
}
//缓存
func (a *Action) updateStateDBCache(order *et.Order) {
a.statedb.Set(calcOrderKey(order.OrderID), types.Encode(order))
}
//反转
func (a *Action) OpSwap(op int32) int32 {
if op == et.OpBuy {
......@@ -59,7 +54,7 @@ func (a *Action) OpSwap(op int32) int32 {
}
//计算实际花费
func (a *Action) calcActualCost(op int32, amount int64, price int64) int64 {
func CalcActualCost(op int32, amount int64, price int64) int64 {
if op == et.OpBuy {
return SafeMul(amount, price)
}
......@@ -148,7 +143,7 @@ func (a *Action) LimitOrder(payload *et.LimitOrder) (*types.Receipt, error) {
amount := SafeMul(payload.GetAmount(), payload.GetPrice())
rightAccount := rightAssetDB.LoadExecAccount(a.fromaddr, a.execaddr)
if rightAccount.Balance < amount {
elog.Error("LimitOrder.BalanceCheck", "addr", a.fromaddr, "execaddr", a.execaddr, "amount", amount, "err", et.ErrAssetBalance.Error())
elog.Error("limit check right balance", "addr", a.fromaddr, "avail", rightAccount.Balance, "need", amount)
return nil, et.ErrAssetBalance
}
return a.matchLimitOrder(payload, leftAssetDB, rightAssetDB)
......@@ -158,7 +153,7 @@ func (a *Action) LimitOrder(payload *et.LimitOrder) (*types.Receipt, error) {
amount := payload.GetAmount()
leftAccount := leftAssetDB.LoadExecAccount(a.fromaddr, a.execaddr)
if leftAccount.Balance < amount {
elog.Error("LimitOrder.BalanceCheck", "addr", a.fromaddr, "execaddr", a.execaddr, "amount", amount, "err", et.ErrAssetBalance.Error())
elog.Error("limit check left balance", "addr", a.fromaddr, "avail", leftAccount.Balance, "need", amount)
return nil, et.ErrAssetBalance
}
return a.matchLimitOrder(payload, leftAssetDB, rightAssetDB)
......@@ -174,11 +169,11 @@ func (a *Action) RevokeOrder(payload *et.RevokeOrder) (*types.Receipt, error) {
return nil, err
}
if order.Addr != a.fromaddr {
elog.Error("RevokeOrder.OrderCheck", "addr", a.fromaddr, "order.addr", order.Addr, "order.status", order.Status, "err", et.ErrAddr.Error())
elog.Error("RevokeOrder.OrderCheck", "addr", a.fromaddr, "order.addr", order.Addr, "order.status", order.Status)
return nil, et.ErrAddr
}
if order.Status == et.Completed || order.Status == et.Revoked {
elog.Error("RevokeOrder.OrderCheck", "addr", a.fromaddr, "order.addr", order.Addr, "order.status", order.Status, "err", et.ErrOrderSatus.Error())
elog.Error("RevokeOrder.OrderCheck", "addr", a.fromaddr, "order.addr", order.Addr, "order.status", order.Status)
return nil, et.ErrOrderSatus
}
leftAsset := order.GetLimitOrder().GetLeftAsset()
......@@ -193,15 +188,15 @@ func (a *Action) RevokeOrder(payload *et.RevokeOrder) (*types.Receipt, error) {
if err != nil {
return nil, err
}
amount := a.calcActualCost(et.OpBuy, balance, price)
amount := CalcActualCost(et.OpBuy, balance, price)
rightAccount := rightAssetDB.LoadExecAccount(a.fromaddr, a.execaddr)
if rightAccount.Frozen < amount {
elog.Error("RevokeOrder.BalanceCheck", "addr", a.fromaddr, "execaddr", a.execaddr, "amount", amount, "err", et.ErrAssetBalance.Error())
elog.Error("revoke check right frozen", "addr", a.fromaddr, "avail", rightAccount.Frozen, "amount", amount)
return nil, et.ErrAssetBalance
}
receipt, err := rightAssetDB.ExecActive(a.fromaddr, a.execaddr, amount)
if err != nil {
elog.Error("RevokeOrder.ExecActive", "addr", a.fromaddr, "execaddr", a.execaddr, "amount", amount, "err", err.Error())
elog.Error("RevokeOrder.ExecActive", "addr", a.fromaddr, "amount", amount, "err", err.Error())
return nil, err
}
logs = append(logs, receipt.Logs...)
......@@ -212,15 +207,15 @@ func (a *Action) RevokeOrder(payload *et.RevokeOrder) (*types.Receipt, error) {
if err != nil {
return nil, err
}
amount := a.calcActualCost(et.OpSell, balance, price)
amount := CalcActualCost(et.OpSell, balance, price)
leftAccount := leftAssetDB.LoadExecAccount(a.fromaddr, a.execaddr)
if leftAccount.Frozen < amount {
elog.Error("RevokeOrder.BalanceCheck", "addr", a.fromaddr, "execaddr", a.execaddr, "amount", amount, "err", et.ErrAssetBalance.Error())
elog.Error("revoke check left frozen", "addr", a.fromaddr, "avail", leftAccount.Frozen, "amount", amount)
return nil, et.ErrAssetBalance
}
receipt, err := leftAssetDB.ExecActive(a.fromaddr, a.execaddr, amount)
if err != nil {
elog.Error("RevokeOrder.ExecActive", "addr", a.fromaddr, "execaddr", a.execaddr, "amount", amount, "err", err.Error())
elog.Error("RevokeOrder.ExecActive", "addr", a.fromaddr, "amount", amount, "err", err.Error())
return nil, err
}
logs = append(logs, receipt.Logs...)
......@@ -317,7 +312,7 @@ func (a *Action) matchLimitOrder(payload *et.LimitOrder, leftAccountDB, rightAcc
continue
}
//撮合,指针传递
log, kv, err := a.matchModel(leftAccountDB, rightAccountDB, payload, matchorder, or, re)
log, kv, err := a.matchModel(leftAccountDB, rightAccountDB, payload, matchorder, or, re) // payload, or redundant
if err != nil {
return nil, err
}
......@@ -351,18 +346,20 @@ func (a *Action) matchLimitOrder(payload *et.LimitOrder, leftAccountDB, rightAcc
//未完成的订单需要冻结剩余未成交的资金
if payload.Op == et.OpBuy {
receipt, err := rightAccountDB.ExecFrozen(a.fromaddr, a.execaddr, a.calcActualCost(et.OpBuy, or.Balance, payload.Price))
amount := CalcActualCost(et.OpBuy, or.Balance, payload.Price)
receipt, err := rightAccountDB.ExecFrozen(a.fromaddr, a.execaddr, amount)
if err != nil {
elog.Error("LimitOrder.ExecFrozen", "addr", a.fromaddr, "execaddr", a.execaddr, "amount", a.calcActualCost(et.OpBuy, or.Balance, payload.Price), "err", err.Error())
elog.Error("LimitOrder.ExecFrozen", "addr", a.fromaddr, "amount", amount, "err", err.Error())
return nil, err
}
logs = append(logs, receipt.Logs...)
kvs = append(kvs, receipt.KV...)
}
if payload.Op == et.OpSell {
receipt, err := leftAccountDB.ExecFrozen(a.fromaddr, a.execaddr, a.calcActualCost(et.OpSell, or.Balance, payload.Price))
amount := CalcActualCost(et.OpSell, or.Balance, payload.Price)
receipt, err := leftAccountDB.ExecFrozen(a.fromaddr, a.execaddr, amount)
if err != nil {
elog.Error("LimitOrder.ExecFrozen", "addr", a.fromaddr, "execaddr", a.execaddr, "amount", a.calcActualCost(et.OpSell, or.Balance, payload.Price), "err", err.Error())
elog.Error("LimitOrder.ExecFrozen", "addr", a.fromaddr, "amount", amount, "err", err.Error())
return nil, err
}
logs = append(logs, receipt.Logs...)
......@@ -370,6 +367,7 @@ func (a *Action) matchLimitOrder(payload *et.LimitOrder, leftAccountDB, rightAcc
}
//更新order状态
kvs = append(kvs, a.GetKVSet(or)...)
re.Order = or
receiptlog := &types.ReceiptLog{Ty: et.TyLimitOrderLog, Log: types.Encode(re)}
logs = append(logs, receiptlog)
receipts := &types.Receipt{Ty: types.ExecOk, KV: kvs, Logs: logs}
......@@ -380,140 +378,68 @@ func (a *Action) matchLimitOrder(payload *et.LimitOrder, leftAccountDB, rightAcc
func (a *Action) matchModel(leftAccountDB, rightAccountDB *account.DB, payload *et.LimitOrder, matchorder *et.Order, or *et.Order, re *et.ReceiptExchange) ([]*types.ReceiptLog, []*types.KeyValue, error) {
var logs []*types.ReceiptLog
var kvs []*types.KeyValue
//TODO 这里得逻辑是否需要调整?当匹配的单数过多,会导致receipt日志数量激增,理论上存在日志存储攻击,需要加下最大匹配深度,防止这种攻击发生
var matched int64
//先判断挂单得额度够不够,只有两种状态,大于等于,或者小于
if matchorder.GetBalance() >= or.GetBalance() {
if payload.Op == et.OpSell {
//转移冻结资产
receipt, err := rightAccountDB.ExecTransferFrozen(matchorder.Addr, a.fromaddr, a.execaddr, a.calcActualCost(matchorder.GetLimitOrder().Op, or.GetBalance(), payload.Price))
if err != nil {
elog.Error("matchLimitOrder.ExecTransferFrozen", "addr", matchorder.Addr, "execaddr", a.execaddr, "amount", a.calcActualCost(matchorder.GetLimitOrder().Op, or.GetBalance(), payload.Price), "err", err.Error())
return nil, nil, err
}
logs = append(logs, receipt.Logs...)
kvs = append(kvs, receipt.KV...)
//解冻多余资金
if payload.Price < matchorder.GetLimitOrder().Price {
receipt, err := rightAccountDB.ExecActive(matchorder.Addr, a.execaddr, a.calcActualCost(matchorder.GetLimitOrder().Op, or.GetBalance(), matchorder.GetLimitOrder().Price-payload.Price))
if err != nil {
elog.Error("matchLimitOrder.ExecActive", "addr", matchorder.Addr, "execaddr", a.execaddr, "amount", a.calcActualCost(matchorder.GetLimitOrder().Op, or.GetBalance(), matchorder.GetLimitOrder().Price-payload.Price), "err", err.Error())
return nil, nil, err
}
logs = append(logs, receipt.Logs...)
kvs = append(kvs, receipt.KV...)
}
//将达成交易的相应资产结算
receipt, err = leftAccountDB.ExecTransfer(a.fromaddr, matchorder.Addr, a.execaddr, a.calcActualCost(payload.Op, or.GetBalance(), payload.Price))
if err != nil {
elog.Error("matchLimitOrder.ExecTransfer", "addr", a.fromaddr, "execaddr", a.execaddr, "amount", a.calcActualCost(payload.Op, or.GetBalance(), payload.Price), "err", err.Error())
return nil, nil, err
}
logs = append(logs, receipt.Logs...)
kvs = append(kvs, receipt.KV...)
//卖单成交得平均价格始终与自身挂单价格相同
or.AVGPrice = payload.Price
//计算matchOrder平均成交价格
matchorder.AVGPrice = caclAVGPrice(matchorder, payload.Price, payload.Amount)
}
if payload.Op == et.OpBuy {
//转移冻结资产
receipt, err := leftAccountDB.ExecTransferFrozen(matchorder.Addr, a.fromaddr, a.execaddr, a.calcActualCost(matchorder.GetLimitOrder().Op, or.GetBalance(), matchorder.GetLimitOrder().Price))
if err != nil {
elog.Error("matchLimitOrder.ExecTransferFrozen", "addr", matchorder.Addr, "execaddr", a.execaddr, "amount", a.calcActualCost(matchorder.GetLimitOrder().Op, or.GetBalance(), matchorder.GetLimitOrder().Price), "err", err.Error())
return nil, nil, err
}
logs = append(logs, receipt.Logs...)
kvs = append(kvs, receipt.KV...)
//将达成交易的相应资产结算
receipt, err = rightAccountDB.ExecTransfer(a.fromaddr, matchorder.Addr, a.execaddr, a.calcActualCost(payload.Op, or.GetBalance(), matchorder.GetLimitOrder().Price))
if err != nil {
elog.Error("matchLimitOrder.ExecTransfer", "addr", a.fromaddr, "execaddr", a.execaddr, "amount", a.calcActualCost(payload.Op, or.GetBalance(), matchorder.GetLimitOrder().Price), "err", err.Error())
return nil, nil, err
}
logs = append(logs, receipt.Logs...)
kvs = append(kvs, receipt.KV...)
//买单得话,价格选取卖单的价格
or.AVGPrice = matchorder.GetLimitOrder().Price
//计算matchOrder平均成交价格
matchorder.AVGPrice = caclAVGPrice(matchorder, matchorder.GetLimitOrder().Price, payload.Amount)
}
// match receiptorder,涉及赋值先手顺序,代码顺序不可变
matchorder.Status = func(a, b int64) int32 {
if a > b {
return et.Ordered
}
return et.Completed
}(matchorder.GetBalance(), or.GetBalance())
matchorder.Balance = matchorder.GetBalance() - or.GetBalance()
//记录本次成交得量
matchorder.Executed = or.GetBalance()
a.updateStateDBCache(matchorder)
kvs = append(kvs, a.GetKVSet(matchorder)...)
matched = or.GetBalance()
} else {
matched = matchorder.GetBalance()
}
or.Executed = or.Executed + or.GetBalance()
or.Status = et.Completed
or.Balance = 0
//update receipt order
re.Order = or
re.MatchOrders = append(re.MatchOrders, matchorder)
elog.Info("try match", "activeId", or.OrderID, "passiveId", matchorder.OrderID, "activeAddr", or.Addr, "passiveAddr",
matchorder.Addr, "amount", matched, "price", payload.Price)
a.updateStateDBCache(or)
kvs = append(kvs, a.GetKVSet(or)...)
return logs, kvs, nil
}
if payload.Op == et.OpSell {
//转移冻结资产
receipt, err := rightAccountDB.ExecTransferFrozen(matchorder.Addr, a.fromaddr, a.execaddr, a.calcActualCost(matchorder.GetLimitOrder().Op, matchorder.GetBalance(), payload.Price))
amount := CalcActualCost(matchorder.GetLimitOrder().Op, matched, payload.Price)
receipt, err := rightAccountDB.ExecTransferFrozen(matchorder.Addr, a.fromaddr, a.execaddr, amount)
if err != nil {
elog.Error("matchLimitOrder.ExecTransferFrozen", "addr", matchorder.Addr, "execaddr", a.execaddr, "amount", a.calcActualCost(matchorder.GetLimitOrder().Op, matchorder.GetBalance(), payload.Price), "err", err.Error())
elog.Error("matchModel.ExecTransferFrozen", "from", matchorder.Addr, "to", a.fromaddr, "amount", amount, "err", err)
return nil, nil, err
}
logs = append(logs, receipt.Logs...)
kvs = append(kvs, receipt.KV...)
//解冻成交部分 多余资金
//解冻多余资金
if payload.Price < matchorder.GetLimitOrder().Price {
receipt, err := rightAccountDB.ExecActive(matchorder.Addr, a.execaddr, a.calcActualCost(matchorder.GetLimitOrder().Op, matchorder.GetBalance(), matchorder.GetLimitOrder().Price-payload.Price))
amount := CalcActualCost(matchorder.GetLimitOrder().Op, matched, matchorder.GetLimitOrder().Price-payload.Price)
receipt, err := rightAccountDB.ExecActive(matchorder.Addr, a.execaddr, amount)
if err != nil {
elog.Error("matchLimitOrder.ExecActive", "addr", matchorder.Addr, "execaddr", a.execaddr, "amount", a.calcActualCost(matchorder.GetLimitOrder().Op, or.GetBalance(), matchorder.GetLimitOrder().Price-payload.Price), "err", err.Error())
elog.Error("matchModel.ExecActive", "addr", matchorder.Addr, "amount", amount, "err", err.Error())
return nil, nil, err
}
logs = append(logs, receipt.Logs...)
kvs = append(kvs, receipt.KV...)
}
//将达成交易的相应资产结算
receipt, err = leftAccountDB.ExecTransfer(a.fromaddr, matchorder.Addr, a.execaddr, a.calcActualCost(payload.Op, matchorder.GetBalance(), payload.Price))
amount = CalcActualCost(payload.Op, matched, payload.Price)
receipt, err = leftAccountDB.ExecTransfer(a.fromaddr, matchorder.Addr, a.execaddr, amount)
if err != nil {
elog.Error("matchLimitOrder.ExecTransfer", "addr", a.fromaddr, "execaddr", a.execaddr, "amount", a.calcActualCost(payload.Op, matchorder.GetBalance(), payload.Price), "err", err.Error())
elog.Error("matchModel.ExecTransfer", "from", a.fromaddr, "to", matchorder.Addr, "amount", amount, "err", err.Error())
return nil, nil, err
}
logs = append(logs, receipt.Logs...)
kvs = append(kvs, receipt.KV...)
//买单得话,价格选取卖单的价格
//卖单成交得平均价格始终与自身挂单价格相同
or.AVGPrice = payload.Price
//计算matchOrder平均成交价格
matchorder.AVGPrice = caclAVGPrice(matchorder, payload.Price, matchorder.GetBalance())
matchorder.AVGPrice = caclAVGPrice(matchorder, payload.Price, matched) //TODO
}
if payload.Op == et.OpBuy {
//转移冻结资产
receipt, err := leftAccountDB.ExecTransferFrozen(matchorder.Addr, a.fromaddr, a.execaddr, a.calcActualCost(matchorder.GetLimitOrder().Op, matchorder.GetBalance(), matchorder.GetLimitOrder().Price))
amount := CalcActualCost(matchorder.GetLimitOrder().Op, matched, matchorder.GetLimitOrder().Price)
receipt, err := leftAccountDB.ExecTransferFrozen(matchorder.Addr, a.fromaddr, a.execaddr, amount)
if err != nil {
elog.Error("matchLimitOrder.ExecTransferFrozen", "addr", matchorder.Addr, "execaddr", a.execaddr, "amount", a.calcActualCost(matchorder.GetLimitOrder().Op, matchorder.GetBalance(), matchorder.GetLimitOrder().Price), "err", err.Error())
elog.Error("matchModel.ExecTransferFrozen2", "from", matchorder.Addr, "to", a.fromaddr, "amount", amount, "err", err.Error())
return nil, nil, err
}
logs = append(logs, receipt.Logs...)
kvs = append(kvs, receipt.KV...)
//将达成交易的相应资产结算
receipt, err = rightAccountDB.ExecTransfer(a.fromaddr, matchorder.Addr, a.execaddr, a.calcActualCost(payload.Op, matchorder.GetBalance(), matchorder.GetLimitOrder().Price))
amount = CalcActualCost(payload.Op, matched, matchorder.GetLimitOrder().Price)
receipt, err = rightAccountDB.ExecTransfer(a.fromaddr, matchorder.Addr, a.execaddr, amount)
if err != nil {
elog.Error("matchLimitOrder.ExecTransfer", "addr", a.fromaddr, "execaddr", a.execaddr, "amount", a.calcActualCost(payload.Op, matchorder.GetBalance(), matchorder.GetLimitOrder().Price), "err", err.Error())
elog.Error("matchModel.ExecTransfer2", "from", a.fromaddr, "to", matchorder.Addr, "amount", amount, "err", err.Error())
return nil, nil, err
}
logs = append(logs, receipt.Logs...)
......@@ -522,21 +448,37 @@ func (a *Action) matchModel(leftAccountDB, rightAccountDB *account.DB, payload *
//买单得话,价格选取卖单的价格
or.AVGPrice = matchorder.GetLimitOrder().Price
//计算matchOrder平均成交价格
matchorder.AVGPrice = caclAVGPrice(matchorder, matchorder.GetLimitOrder().Price, matchorder.GetBalance())
matchorder.AVGPrice = caclAVGPrice(matchorder, matchorder.GetLimitOrder().Price, matched) //TODO
}
if matched == matchorder.GetBalance() {
matchorder.Status = et.Completed
} else {
matchorder.Status = et.Ordered
}
//涉及赋值先后顺序,不可颠倒
or.Balance = or.Balance - matchorder.Balance
or.Executed = or.Executed + matchorder.Balance
or.Status = et.Ordered
a.updateStateDBCache(or)
if matched == or.GetBalance() {
or.Status = et.Completed
} else {
or.Status = et.Ordered
}
// match receiptorder
matchorder.Executed = matchorder.Balance
matchorder.Status = et.Completed
matchorder.Balance = 0
a.updateStateDBCache(matchorder)
kvs = append(kvs, a.GetKVSet(matchorder)...)
if matched == or.GetBalance() {
matchorder.Balance -= matched
matchorder.Executed = matched
kvs = append(kvs, a.GetKVSet(matchorder)...)
or.Executed += matched
or.Balance = 0
kvs = append(kvs, a.GetKVSet(or)...) //or complete
} else {
or.Balance -= matched
or.Executed += matched
matchorder.Executed = matched
matchorder.Balance = 0
kvs = append(kvs, a.GetKVSet(matchorder)...) //matchorder complete
}
re.Order = or
re.MatchOrders = append(re.MatchOrders, matchorder)
......@@ -620,7 +562,7 @@ func QueryMarketDepth(localdb dbm.KV, left, right *et.Asset, op int32, primaryKe
rows, err = table.ListIndex("price", prefix, []byte(primaryKey), count, Direction(op))
}
if err != nil {
elog.Error("QueryMarketDepth.", "left", left, "right", right, "err", err.Error())
//elog.Error("QueryMarketDepth.", "left", left, "right", right, "err", err.Error())
return nil, err
}
......
# 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)
}
}
package test
import (
"testing"
"github.com/golang/protobuf/proto"
"github.com/33cn/plugin/plugin/dapp/exchange/executor"
"github.com/33cn/chain33/types"
et "github.com/33cn/plugin/plugin/dapp/exchange/types"
"github.com/stretchr/testify/assert"
)
var (
PrivKeyA = "0x6da92a632ab7deb67d38c0f6560bcfed28167998f6496db64c258d5e8393a81b" // 1KSBd17H7ZK8iT37aJztFB22XGwsPTdwE4
PrivKeyB = "0x19c069234f9d3e61135fefbeb7791b149cdf6af536f26bebb310d4cd22c3fee4" // 1JRNjdEqp4LJ5fqycUBm9ayCKSeeskgMKR
PrivKeyC = "0x7a80a1f75d7360c6123c32a78ecf978c1ac55636f87892df38d8b85a9aeff115" // 1NLHPEcbTWWxxU3dGUZBhayjrCHD3psX7k
PrivKeyD = "0xcacb1f5d51700aea07fca2246ab43b0917d70405c65edea9b5063d72eb5c6b71" // 1MCftFynyvG2F4ED5mdHYgziDxx6vDrScs
coin = "bty"
token = "CCNY"
leftAsset = &et.Asset{Symbol: coin, Execer: "coins"}
rightAsset = &et.Asset{Symbol: token, Execer: "token"}
cli Cli
orderID int64
)
func init() {
cli = NewExecCli()
//cli = NewGRPCCli(":8802")
}
func TestLimitOrder(t *testing.T) {
//A 挂买 4x10
req := &et.LimitOrder{LeftAsset: leftAsset, RightAsset: rightAsset, Price: 4, Amount: 10 * types.Coin, Op: et.OpBuy}
testPlaceLimitOrder(t, req, Nodes[0], PrivKeyA)
}
func TestOrderList(t *testing.T) {
orderList, err := getOrderList(et.Ordered, Nodes[0], "")
assert.Nil(t, err)
t.Log(orderList)
orderID = orderList.List[0].OrderID
}
func TestGetOrder(t *testing.T) {
order, err := getOrder(orderID)
assert.Nil(t, err)
t.Log(order)
}
func TestMarketDepth(t *testing.T) {
depth, err := getMarketDepth(&et.QueryMarketDepth{LeftAsset: leftAsset, RightAsset: rightAsset, Op: et.OpBuy})
t.Log(depth, err)
}
func TestMatch(t *testing.T) {
//B 挂卖 4x5
req := &et.LimitOrder{LeftAsset: leftAsset, RightAsset: rightAsset, Price: 4, Amount: 5 * types.Coin, Op: et.OpSell}
doLimitOrder(req, PrivKeyB)
}
func TestHistoryOrderList(t *testing.T) {
historyq := &et.QueryHistoryOrderList{
LeftAsset: leftAsset,
RightAsset: rightAsset,
}
historyOrderList, err := getHistoryOrderList(historyq)
assert.Nil(t, err)
t.Log(historyOrderList)
}
func TestRevokeOrder(t *testing.T) {
//A 撤回未完成订单
testRevokeLimitOrder(t, orderID, Nodes[0], PrivKeyA)
}
func TestSample0(t *testing.T) {
depth, _ := getMarketDepth(&et.QueryMarketDepth{LeftAsset: leftAsset, RightAsset: rightAsset, Op: et.OpBuy})
assert.Nil(t, depth)
depth, _ = getMarketDepth(&et.QueryMarketDepth{LeftAsset: leftAsset, RightAsset: rightAsset, Op: et.OpBuy})
assert.Nil(t, depth)
}
//买卖单价格相同,测试正常撮合流程,查询功能是否可用
//1.先挂数量是10的买单。
//2.然后再挂数量是5的吃单
//3.最后撤销未成交部分的买单
func TestCase1(t *testing.T) {
//先挂数量是10的买单
req := &et.LimitOrder{LeftAsset: leftAsset, RightAsset: rightAsset, Price: 4, Amount: 10 * types.Coin, Op: et.OpBuy}
_, err := doLimitOrder(req, PrivKeyA)
assert.Nil(t, err)
orderList, err := getOrderList(et.Ordered, Nodes[0], "")
assert.Nil(t, err)
//根据订单号,查询订单详情
orderID1 := orderList.List[0].OrderID
order, err := getOrder(orderID1)
assert.Nil(t, err)
assert.Equal(t, int32(et.Ordered), order.Status)
assert.Equal(t, 10*types.Coin, order.GetBalance())
//根据op查询市场深度
q := &et.QueryMarketDepth{LeftAsset: leftAsset, RightAsset: rightAsset, Op: et.OpBuy}
marketDepthList, err := getMarketDepth(q)
assert.Nil(t, err)
assert.Equal(t, 10*types.Coin, marketDepthList.List[0].GetAmount())
//然后再挂数量是5的吃单
req = &et.LimitOrder{LeftAsset: leftAsset, RightAsset: rightAsset, Price: 4, Amount: 5 * types.Coin, Op: et.OpSell}
_, err = doLimitOrder(req, PrivKeyB)
assert.Nil(t, err)
orderList, err = getOrderList(et.Completed, Nodes[1], "")
assert.Nil(t, err)
orderID2 := orderList.List[0].OrderID
//查询订单1详情
order, err = getOrder(orderID1)
assert.Nil(t, err)
//订单1的状态应该还是ordered
assert.Equal(t, int32(et.Ordered), order.Status)
assert.Equal(t, 5*types.Coin, order.Balance)
//order2状态是completed
order, err = getOrder(orderID2)
assert.Nil(t, err)
assert.Equal(t, int32(et.Completed), order.Status)
//根据op查询市场深度
q = &et.QueryMarketDepth{LeftAsset: leftAsset, RightAsset: rightAsset, Op: et.OpBuy}
marketDepthList, err = getMarketDepth(q)
assert.Nil(t, err)
//市场深度应该改变
assert.Equal(t, 5*types.Coin, marketDepthList.List[0].GetAmount())
//查询历史成交
q2 := &et.QueryHistoryOrderList{LeftAsset: leftAsset, RightAsset: rightAsset}
orderList, err = getHistoryOrderList(q2)
assert.Nil(t, err)
assert.Equal(t, orderID2, orderList.List[0].OrderID)
//撤回未完成的订单
_, err = doRevokeOrder(orderID1, PrivKeyA)
assert.Nil(t, err)
//查询订单1详情
order, err = getOrder(orderID1)
assert.Nil(t, err)
//订单1的状态应该Revoked
assert.Equal(t, int32(et.Revoked), order.Status)
assert.Equal(t, 5*types.Coin, order.Balance)
//根据op查询市场深度
q = &et.QueryMarketDepth{LeftAsset: leftAsset, RightAsset: rightAsset, Op: et.OpBuy}
_, err = getMarketDepth(q)
assert.NotNil(t, err)
//根据原有状态去查看买单是否被改变
//原有ordered状态的数据应该被删除
_, err = getOrderList(et.Ordered, Nodes[0], "")
assert.NotNil(t, err)
}
func BenchmarkOrder(b *testing.B) {
req := &et.LimitOrder{LeftAsset: leftAsset, RightAsset: rightAsset, Price: 1, Amount: 10 * types.Coin, Op: et.OpSell}
ety := types.LoadExecutorType(et.ExchangeX)
tx, _ := ety.Create("LimitOrder", req)
for i := 0; i < b.N; i++ {
cli.Send(tx, PrivKeyA)
}
}
func doLimitOrder(req *et.LimitOrder, privKey string) ([]*types.ReceiptLog, error) {
ety := types.LoadExecutorType(et.ExchangeX)
tx, err := ety.Create("LimitOrder", req)
if err != nil {
return nil, err
}
return cli.Send(tx, privKey)
}
func doRevokeOrder(orderID int64, privKey string) ([]*types.ReceiptLog, error) {
ety := types.LoadExecutorType(et.ExchangeX)
tx, err := ety.Create("RevokeOrder", &et.RevokeOrder{OrderID: orderID})
if err != nil {
return nil, err
}
return cli.Send(tx, privKey)
}
func getOrderList(status int32, addr string, primaryKey string) (*et.OrderList, error) {
msg, err := cli.Query(et.FuncNameQueryOrderList, &et.QueryOrderList{Status: status, Address: addr, PrimaryKey: primaryKey})
if err != nil {
return nil, err
}
var resp et.OrderList
err = types.Decode(msg, &resp)
if err != nil {
return nil, err
}
return &resp, nil
}
func getOrder(orderID int64) (*et.Order, error) {
msg, err := cli.Query(et.FuncNameQueryOrder, &et.QueryOrder{OrderID: orderID})
if err != nil {
return nil, err
}
var resp et.Order
err = types.Decode(msg, &resp)
if err != nil {
return nil, err
}
return &resp, nil
}
func getMarketDepth(q proto.Message) (*et.MarketDepthList, error) {
msg, err := cli.Query(et.FuncNameQueryMarketDepth, q)
if err != nil {
return nil, err
}
var resp et.MarketDepthList
err = types.Decode(msg, &resp)
if err != nil {
return nil, err
}
return &resp, nil
}
func getHistoryOrderList(q proto.Message) (*et.OrderList, error) {
msg, err := cli.Query(et.FuncNameQueryHistoryOrderList, q)
if err != nil {
return nil, err
}
var resp et.OrderList
err = types.Decode(msg, &resp)
if err != nil {
return nil, err
}
return &resp, nil
}
func testPlaceLimitOrder(t *testing.T, req *et.LimitOrder, addr string, privkey string) {
accPrev, err := cli.GetExecAccount(addr, "coins", coin)
assert.Nil(t, err)
t.Log(accPrev)
tokenPrev, err := cli.GetExecAccount(addr, "token", token)
assert.Nil(t, err)
t.Log(tokenPrev)
_, err = doLimitOrder(req, privkey)
assert.Nil(t, err)
accAfter, err := cli.GetExecAccount(addr, "coins", coin)
assert.Nil(t, err)
t.Log(accAfter)
tokenAfter, err := cli.GetExecAccount(addr, "token", token)
assert.Nil(t, err)
t.Log(tokenAfter)
cost := executor.CalcActualCost(req.Op, req.Amount, req.Price)
t.Log(req.Amount, req.Price, cost)
// bty/ccny
if req.Op == et.OpBuy {
// bty
assert.Equal(t, accAfter.Balance, accPrev.Balance)
assert.Equal(t, accAfter.Frozen, accPrev.Frozen)
// ccny
assert.Equal(t, tokenAfter.Balance, tokenPrev.Balance-cost)
assert.Equal(t, tokenAfter.Frozen, tokenPrev.Frozen+cost)
} else {
// bty
assert.Equal(t, accAfter.Balance, accPrev.Balance-cost)
assert.Equal(t, accAfter.Frozen, accPrev.Frozen+cost)
// ccny
assert.Equal(t, tokenAfter.Balance, tokenPrev.Balance)
assert.Equal(t, tokenAfter.Frozen, tokenPrev.Frozen)
}
}
func testRevokeLimitOrder(t *testing.T, orderID int64, addr string, privkey string) {
order, err := getOrder(orderID)
assert.Nil(t, err)
assert.NotNil(t, order)
lo := order.Value.(*et.Order_LimitOrder).LimitOrder
assert.NotNil(t, lo)
accPrev, err := cli.GetExecAccount(addr, "coins", coin)
assert.Nil(t, err)
t.Log(accPrev)
tokenPrev, err := cli.GetExecAccount(addr, "token", token)
assert.Nil(t, err)
t.Log(tokenPrev)
_, err = doRevokeOrder(orderID, privkey)
assert.Nil(t, err)
accAfter, err := cli.GetExecAccount(addr, "coins", coin)
assert.Nil(t, err)
t.Log(accAfter)
tokenAfter, err := cli.GetExecAccount(addr, "token", token)
assert.Nil(t, err)
t.Log(tokenAfter)
cost := executor.CalcActualCost(lo.Op, order.Balance, lo.Price)
// bty/ccny
if lo.Op == et.OpBuy {
// bty
assert.Equal(t, accAfter.Balance, accPrev.Balance)
assert.Equal(t, accAfter.Frozen, accPrev.Frozen)
// ccny
assert.Equal(t, tokenAfter.Balance, tokenPrev.Balance+cost)
assert.Equal(t, tokenAfter.Frozen, tokenPrev.Frozen-cost)
} else {
// bty
assert.Equal(t, accAfter.Balance, accPrev.Balance+cost)
assert.Equal(t, accAfter.Frozen, accPrev.Frozen-cost)
// ccny
assert.Equal(t, tokenAfter.Balance, tokenPrev.Balance)
assert.Equal(t, tokenAfter.Frozen, tokenPrev.Frozen)
}
}
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}"
#!/usr/bin/env bash
# shellcheck disable=SC2128
set -e
set -o pipefail
MAIN_HTTP=""
ISSU_ID=""
DEBT_ID=""
COLL_ID=""
BORROW_ID=""
issuance_addr=""
collateralize_addr=""
SystemManager="0x4257d8692ef7fe13c68b65d6a52f03933db2fa5ce8faf210b5b8b80c721ced01"
TokenSuperManager="0xc34b5d9d44ac7b754806f761d3d4d2c4fe5214f6b074c19f069c4f5c2a29c8cc"
TokenAddr="1Q8hGLfoGe63efeWa8fJ4Pnukhkngt6poK"
IssuanceAddr1="1C9t6uNcmbUgebt9HZfKweNb58hUcq5MZY"
IssuancePriv1="0x6bbfe2c8933ad56d244b68f267da576e9df539bcabc160d2ef29acc2838d5d81"
IssuanceAddr2="16pjXn7vMVPqKjuVnYV44ANQGD1TRaw3ct"
IssuancePriv2="0xa099f50ca616017000f338fb00c8eda133b1616f6d62f2ea3e361cc71e6c92d6"
IssuanceAddr3="1CQMn9B5Rh6s8wtnYEhuQwtVxPjcXSC4qC"
IssuancePriv3="0xb4c158903f373636765a0c6226b91980c5a403a37f21bc8248d45c09569e6ad3"
CollateralizeAddr="1BLfkPaAGqSiXyovx3Pm9xUTMHmusLXtLZ"
CollateralizePriv="0xf860db5178e6436cabd499c142084515966f88f581936ee9ccbfc0a6a77c0e70"
# shellcheck source=/dev/null
source ../dapp-test-common.sh
issuance_Create() {
echo "========== # issuance create begin =========="
tx=$(curl -ksd '{"method":"Chain33.CreateTransaction","params":[{"execer":"issuance","actionName":"IssuanceCreate","payload":{"debtCeiling":1000.1, "totalBalance":10000.1}}]}' ${MAIN_HTTP} | jq -r ".result")
data=$(curl -ksd '{"method":"Chain33.DecodeRawTransaction","params":[{"txHex":"'"$tx"'"}]}' ${MAIN_HTTP} | jq -r ".result.txs[0]")
ok=$(jq '(.execer != "")' <<<"$data")
[ "$ok" == true ]
echo_rst "$FUNCNAME" "$?"
chain33_SignAndSendTx "$tx" "${IssuancePriv1}" ${MAIN_HTTP}
ISSU_ID=$RAW_TX_HASH
chain33_BlockWait 1 ${MAIN_HTTP}
data=$(curl -ksd '{"method":"Chain33.Query","params":[{"execer":"issuance","funcName":"IssuanceInfoByID","payload":{"issuanceId":"'"$ISSU_ID"'"}}]}' ${MAIN_HTTP} | jq -r ".result")
[ "$data" != null ]
data=$(curl -ksd '{"method":"Chain33.Query","params":[{"execer":"issuance","funcName":"IssuanceByStatus","payload":{"status":1}}]}' ${MAIN_HTTP} | jq -r ".result")
[ "$data" != null ]
echo_rst "$FUNCNAME" "$?"
echo "========== # issuance create end =========="
}
issuance_Manage() {
echo "========== # issuance manage begin =========="
tx=$(curl -ksd '{"method":"Chain33.CreateTransaction","params":[{"execer":"issuance","actionName":"IssuanceManage","payload":{"addr":["'"${IssuanceAddr3}"'"]}}]}' ${MAIN_HTTP} | jq -r ".result")
data=$(curl -ksd '{"method":"Chain33.DecodeRawTransaction","params":[{"txHex":"'"$tx"'"}]}' ${MAIN_HTTP} | jq -r ".result.txs[0]")
ok=$(jq '(.execer != "")' <<<"$data")
[ "$ok" == true ]
echo_rst "$FUNCNAME" "$?"
chain33_SignAndSendTx "$tx" "${IssuancePriv1}" ${MAIN_HTTP}
chain33_BlockWait 1 ${MAIN_HTTP}
echo "========== # issuance manage end =========="
}
issuance_Feed() {
echo "========== # issuance feed begin =========="
tx=$(curl -ksd '{"method":"Chain33.CreateTransaction","params":[{"execer":"issuance","actionName":"IssuancePriceFeed","payload":{"Price":[1], "Volume":[100]}}]}' ${MAIN_HTTP} | jq -r ".result")
data=$(curl -ksd '{"method":"Chain33.DecodeRawTransaction","params":[{"txHex":"'"$tx"'"}]}' ${MAIN_HTTP} | jq -r ".result.txs[0]")
ok=$(jq '(.execer != "")' <<<"$data")
[ "$ok" == true ]
echo_rst "$FUNCNAME" "$?"
chain33_SignAndSendTx "$tx" "${IssuancePriv2}" ${MAIN_HTTP}
chain33_BlockWait 1 "${MAIN_HTTP}"
data=$(curl -ksd '{"method":"Chain33.Query","params":[{"execer":"issuance","funcName":"IssuancePrice","payload":{}}]}' ${MAIN_HTTP} | jq -r ".result")
[ "$data" != null ]
echo_rst "$FUNCNAME" "$?"
echo "========== # issuance feed end =========="
}
issuance_Debt() {
echo "========== # issuance debt begin =========="
tx=$(curl -ksd '{"method":"Chain33.CreateTransaction","params":[{"execer":"issuance","actionName":"IssuanceDebt","payload":{"issuanceId":"'"${ISSU_ID}"'", "value":10}}]}' ${MAIN_HTTP} | jq -r ".result")
data=$(curl -ksd '{"method":"Chain33.DecodeRawTransaction","params":[{"txHex":"'"$tx"'"}]}' ${MAIN_HTTP} | jq -r ".result.txs[0]")
ok=$(jq '(.execer != "")' <<<"$data")
[ "$ok" == true ]
echo_rst "$FUNCNAME" "$?"
chain33_SignAndSendTx "$tx" "${IssuancePriv3}" ${MAIN_HTTP}
DEBT_ID=$RAW_TX_HASH
chain33_BlockWait 1 "${MAIN_HTTP}"
data=$(curl -ksd '{"method":"Chain33.Query","params":[{"execer":"issuance","funcName":"IssuanceRecordByID","payload":{"issuanceId": "'"${ISSU_ID}"'", "debtId": "'"${DEBT_ID}"'"}}]}' ${MAIN_HTTP} | jq -r ".result")
[ "$data" != null ]
data=$(curl -ksd '{"method":"Chain33.Query","params":[{"execer":"issuance","funcName":"IssuanceRecordsByAddr","payload":{"issuanceId": "'"${ISSU_ID}"'", "addr": "'"${IssuanceAddr3}"'"}}]}' ${MAIN_HTTP} | jq -r ".result")
[ "$data" != null ]
data=$(curl -ksd '{"method":"Chain33.Query","params":[{"execer":"issuance","funcName":"IssuanceRecordsByStatus","payload":{"issuanceId": "'"${ISSU_ID}"'", "status": 1}}]}' ${MAIN_HTTP} | jq -r ".result")
[ "$data" != null ]
echo_rst "$FUNCNAME" "$?"
echo "========== # issuance debt end =========="
}
issuance_Repay() {
echo "========== # issuance repay begin =========="
tx=$(curl -ksd '{"method":"Chain33.CreateTransaction","params":[{"execer":"issuance","actionName":"IssuanceRepay","payload":{"issuanceId":"'"${ISSU_ID}"'", "debtId":"'"${DEBT_ID}"'"}}]}' ${MAIN_HTTP} | jq -r ".result")
data=$(curl -ksd '{"method":"Chain33.DecodeRawTransaction","params":[{"txHex":"'"$tx"'"}]}' ${MAIN_HTTP} | jq -r ".result.txs[0]")
ok=$(jq '(.execer != "")' <<<"$data")
[ "$ok" == true ]
echo_rst "$FUNCNAME" "$?"
chain33_SignAndSendTx "$tx" "${IssuancePriv3}" ${MAIN_HTTP}
chain33_BlockWait 1 "${MAIN_HTTP}"
data=$(curl -ksd '{"method":"Chain33.Query","params":[{"execer":"issuance","funcName":"IssuanceRecordsByStatus","payload":{"issuanceId": "'"${ISSU_ID}"'", "status": 6}}]}' ${MAIN_HTTP} | jq -r ".result")
[ "$data" != null ]
echo_rst "$FUNCNAME" "$?"
echo "========== # issuance repay end =========="
}
issuance_Close() {
echo "========== # issuance close begin =========="
tx=$(curl -ksd '{"method":"Chain33.CreateTransaction","params":[{"execer":"issuance","actionName":"IssuanceClose","payload":{"issuanceId":"'"${ISSU_ID}"'"}}]}' ${MAIN_HTTP} | jq -r ".result")
data=$(curl -ksd '{"method":"Chain33.DecodeRawTransaction","params":[{"txHex":"'"$tx"'"}]}' ${MAIN_HTTP} | jq -r ".result.txs[0]")
ok=$(jq '(.execer != "")' <<<"$data")
[ "$ok" == true ]
echo_rst "$FUNCNAME" "$?"
chain33_SignAndSendTx "$tx" "${IssuancePriv1}" ${MAIN_HTTP}
chain33_BlockWait 1 "${MAIN_HTTP}"
data=$(curl -ksd '{"method":"Chain33.Query","params":[{"execer":"issuance","funcName":"IssuanceByStatus","payload":{"status": 2}}]}' ${MAIN_HTTP} | jq -r ".result")
[ "$data" != null ]
echo_rst "$FUNCNAME" "$?"
echo "========== # issuance close end =========="
}
collateralize_Manage() {
echo "========== # collateralize manage begin =========="
tx=$(curl -ksd '{"method":"Chain33.CreateTransaction","params":[{"execer":"collateralize","actionName":"CollateralizeManage","payload":{"debtCeiling":1000.1, "totalBalance":10000.1}}]}' ${MAIN_HTTP} | jq -r ".result")
data=$(curl -ksd '{"method":"Chain33.DecodeRawTransaction","params":[{"txHex":"'"$tx"'"}]}' ${MAIN_HTTP} | jq -r ".result.txs[0]")
ok=$(jq '(.execer != "")' <<<"$data")
[ "$ok" == true ]
echo_rst "$FUNCNAME" "$?"
chain33_SignAndSendTx "$tx" "${IssuancePriv1}" ${MAIN_HTTP}
ISSU_ID=$RAW_TX_HASH
chain33_BlockWait 1 ${MAIN_HTTP}
data=$(curl -ksd '{"method":"Chain33.Query","params":[{"execer":"collateralize","funcName":"CollateralizeConfig","payload":{}}]}' ${MAIN_HTTP} | jq -r ".result")
[ "$data" != null ]
echo_rst "$FUNCNAME" "$?"
echo "========== # collateralize manage end =========="
}
collateralize_Create() {
echo "========== # collateralize create begin =========="
tx=$(curl -ksd '{"method":"Chain33.CreateTransaction","params":[{"execer":"collateralize","actionName":"CollateralizeCreate","payload":{"debtCeiling":1000.1, "totalBalance":10000.1}}]}' ${MAIN_HTTP} | jq -r ".result")
data=$(curl -ksd '{"method":"Chain33.DecodeRawTransaction","params":[{"txHex":"'"$tx"'"}]}' ${MAIN_HTTP} | jq -r ".result.txs[0]")
ok=$(jq '(.execer != "")' <<<"$data")
[ "$ok" == true ]
echo_rst "$FUNCNAME" "$?"
chain33_SignAndSendTx "$tx" "${IssuancePriv3}" ${MAIN_HTTP}
COLL_ID=$RAW_TX_HASH
chain33_BlockWait 1 ${MAIN_HTTP}
data=$(curl -ksd '{"method":"Chain33.Query","params":[{"execer":"collateralize","funcName":"CollateralizeInfoByID","payload":{"collateralizeId":"'"${COLL_ID}"'"}}]}' ${MAIN_HTTP} | jq -r ".result")
[ "$data" != null ]
data=$(curl -ksd '{"method":"Chain33.Query","params":[{"execer":"collateralize","funcName":"CollateralizeByStatus","payload":{"status":1}}]}' ${MAIN_HTTP} | jq -r ".result")
[ "$data" != null ]
data=$(curl -ksd '{"method":"Chain33.Query","params":[{"execer":"collateralize","funcName":"CollateralizeByAddr","payload":{"addr":"'"${IssuanceAddr3}"'"}}]}' ${MAIN_HTTP} | jq -r ".result")
[ "$data" != null ]
echo_rst "$FUNCNAME" "$?"
echo "========== # collateralize create end =========="
}
collateralize_Feed() {
echo "========== # collateralize feed begin =========="
tx=$(curl -ksd '{"method":"Chain33.CreateTransaction","params":[{"execer":"collateralize","actionName":"CollateralizePriceFeed","payload":{"Price":[1], "Volume":[100]}}]}' ${MAIN_HTTP} | jq -r ".result")
data=$(curl -ksd '{"method":"Chain33.DecodeRawTransaction","params":[{"txHex":"'"$tx"'"}]}' ${MAIN_HTTP} | jq -r ".result.txs[0]")
ok=$(jq '(.execer != "")' <<<"$data")
[ "$ok" == true ]
echo_rst "$FUNCNAME" "$?"
chain33_SignAndSendTx "$tx" "${IssuancePriv2}" ${MAIN_HTTP}
chain33_BlockWait 1 "${MAIN_HTTP}"
data=$(curl -ksd '{"method":"Chain33.Query","params":[{"execer":"collateralize","funcName":"CollateralizePrice","payload":{}}]}' ${MAIN_HTTP} | jq -r ".result")
[ "$data" != null ]
echo_rst "$FUNCNAME" "$?"
echo "========== # collateralize feed end =========="
}
collateralize_Borrow() {
echo "========== # collateralize borrow begin =========="
tx=$(curl -ksd '{"method":"Chain33.CreateTransaction","params":[{"execer":"collateralize","actionName":"CollateralizeBorrow","payload":{"collateralizeId":"'"${COLL_ID}"'", "value":10.1}}]}' ${MAIN_HTTP} | jq -r ".result")
data=$(curl -ksd '{"method":"Chain33.DecodeRawTransaction","params":[{"txHex":"'"$tx"'"}]}' ${MAIN_HTTP} | jq -r ".result.txs[0]")
ok=$(jq '(.execer != "")' <<<"$data")
[ "$ok" == true ]
echo_rst "$FUNCNAME" "$?"
chain33_SignAndSendTx "$tx" "${CollateralizePriv}" ${MAIN_HTTP}
BORROW_ID=$RAW_TX_HASH
chain33_BlockWait 1 ${MAIN_HTTP}
data=$(curl -ksd '{"method":"Chain33.Query","params":[{"execer":"collateralize","funcName":"CollateralizeRecordByID","payload":{"collateralizeId":"'"${COLL_ID}"'", "recordId":"'"${BORROW_ID}"'"}}]}' ${MAIN_HTTP} | jq -r ".result")
[ "$data" != null ]
data=$(curl -ksd '{"method":"Chain33.Query","params":[{"execer":"collateralize","funcName":"CollateralizeRecordByStatus","payload":{"collateralizeId":"'"${COLL_ID}"'", "status":1}}]}' ${MAIN_HTTP} | jq -r ".result")
[ "$data" != null ]
data=$(curl -ksd '{"method":"Chain33.Query","params":[{"execer":"collateralize","funcName":"CollateralizeRecordByAddr","payload":{"collateralizeId":"'"${COLL_ID}"'", "addr":"'"${CollateralizeAddr}"'"}}]}' ${MAIN_HTTP} | jq -r ".result")
[ "$data" != null ]
echo_rst "$FUNCNAME" "$?"
echo "========== # collateralize borrow end =========="
}
collateralize_Append() {
echo "========== # collateralize append begin =========="
tx=$(curl -ksd '{"method":"Chain33.CreateTransaction","params":[{"execer":"collateralize","actionName":"CollateralizeAppend","payload":{"collateralizeId":"'"${COLL_ID}"'", "recordID":"'"${BORROW_ID}"'", "value":10}}]}' ${MAIN_HTTP} | jq -r ".result")
data=$(curl -ksd '{"method":"Chain33.DecodeRawTransaction","params":[{"txHex":"'"$tx"'"}]}' ${MAIN_HTTP} | jq -r ".result.txs[0]")
ok=$(jq '(.execer != "")' <<<"$data")
[ "$ok" == true ]
echo_rst "$FUNCNAME" "$?"
chain33_SignAndSendTx "$tx" "${CollateralizePriv}" ${MAIN_HTTP}
chain33_BlockWait 1 ${MAIN_HTTP}
echo "========== # collateralize append end =========="
}
collateralize_Repay() {
echo "========== # collateralize repay begin =========="
tx=$(curl -ksd '{"method":"Chain33.CreateTransaction","params":[{"execer":"collateralize","actionName":"CollateralizeRepay","payload":{"collateralizeId":"'"${COLL_ID}"'", "recordID":"'"${BORROW_ID}"'"}}]}' ${MAIN_HTTP} | jq -r ".result")
data=$(curl -ksd '{"method":"Chain33.DecodeRawTransaction","params":[{"txHex":"'"$tx"'"}]}' ${MAIN_HTTP} | jq -r ".result.txs[0]")
ok=$(jq '(.execer != "")' <<<"$data")
[ "$ok" == true ]
echo_rst "$FUNCNAME" "$?"
chain33_SignAndSendTx "$tx" "${CollateralizePriv}" ${MAIN_HTTP}
chain33_BlockWait 1 ${MAIN_HTTP}
data=$(curl -ksd '{"method":"Chain33.Query","params":[{"execer":"collateralize","funcName":"CollateralizeRecordByStatus","payload":{"collateralizeId":"'"${COLL_ID}"'", "status":6}}]}' ${MAIN_HTTP} | jq -r ".result")
[ "$data" != null ]
echo "========== # collateralize repay end =========="
}
collateralize_Retrieve() {
echo "========== # collateralize retrieve begin =========="
tx=$(curl -ksd '{"method":"Chain33.CreateTransaction","params":[{"execer":"collateralize","actionName":"CollateralizeRetrieve","payload":{"collateralizeId":"'"${COLL_ID}"'", "balance":100.1}}]}' ${MAIN_HTTP} | jq -r ".result")
data=$(curl -ksd '{"method":"Chain33.DecodeRawTransaction","params":[{"txHex":"'"$tx"'"}]}' ${MAIN_HTTP} | jq -r ".result.txs[0]")
ok=$(jq '(.execer != "")' <<<"$data")
[ "$ok" == true ]
echo_rst "$FUNCNAME" "$?"
chain33_SignAndSendTx "$tx" "${IssuancePriv3}" ${MAIN_HTTP}
chain33_BlockWait 1 ${MAIN_HTTP}
data=$(curl -ksd '{"method":"Chain33.Query","params":[{"execer":"collateralize","funcName":"CollateralizeRecordByStatus","payload":{"collateralizeId":"'"${COLL_ID}"'", "status":6}}]}' ${MAIN_HTTP} | jq -r ".result")
[ "$data" != null ]
echo "========== # collateralize retrieve end =========="
}
init() {
ispara=$(echo '"'"${MAIN_HTTP}"'"' | jq '.|contains("8901")')
echo "ipara=$ispara"
if [ "$ispara" == true ]; then
issuance_addr=$(curl -ksd '{"method":"Chain33.ConvertExectoAddr","params":[{"execname":"user.p.para.issuance"}]}' ${MAIN_HTTP} | jq -r ".result")
collateralize_addr=$(curl -ksd '{"method":"Chain33.ConvertExectoAddr","params":[{"execname":"user.p.para.collateralize"}]}' ${MAIN_HTTP} | jq -r ".result")
else
issuance_addr=$(curl -ksd '{"method":"Chain33.ConvertExectoAddr","params":[{"execname":"issuance"}]}' ${MAIN_HTTP} | jq -r ".result")
collateralize_addr=$(curl -ksd '{"method":"Chain33.ConvertExectoAddr","params":[{"execname":"collateralize"}]}' ${MAIN_HTTP} | jq -r ".result")
fi
local main_ip=${MAIN_HTTP//8901/8801}
#main chain import pri key
#1C9t6uNcmbUgebt9HZfKweNb58hUcq5MZY
chain33_ImportPrivkey ${IssuancePriv1} ${IssuanceAddr1} "issuance1" "${main_ip}"
#16pjXn7vMVPqKjuVnYV44ANQGD1TRaw3ct
chain33_ImportPrivkey ${IssuancePriv2} ${IssuanceAddr2} "issuance2" "${main_ip}"
#1CQMn9B5Rh6s8wtnYEhuQwtVxPjcXSC4qC
chain33_ImportPrivkey ${IssuancePriv3} ${IssuanceAddr3} "issuance3" "${main_ip}"
#1BLfkPaAGqSiXyovx3Pm9xUTMHmusLXtLZ
chain33_ImportPrivkey ${CollateralizePriv} ${CollateralizeAddr} "coll" "${main_ip}"
if [ "$ispara" == false ]; then
chain33_applyCoins "${IssuanceAddr1}" 12000000000 "${main_ip}"
chain33_QueryBalance "${IssuanceAddr1}" "$main_ip"
chain33_applyCoins "${IssuanceAddr2}" 12000000000 "${main_ip}"
chain33_QueryBalance "${IssuanceAddr2}" "$main_ip"
chain33_applyCoins "${IssuanceAddr3}" 12000000000 "${main_ip}"
chain33_QueryBalance "${IssuanceAddr3}" "$main_ip"
chain33_applyCoins "${CollateralizeAddr}" 12000000000 "${main_ip}"
chain33_QueryBalance "${CollateralizeAddr}" "$main_ip"
chain33_applyCoins "${TokenAddr}" 12000000000 "${main_ip}"
chain33_QueryBalance "${TokenAddr}" "$main_ip"
else
# tx fee
chain33_applyCoins ${IssuanceAddr1} 1000000000 "${main_ip}"
chain33_QueryBalance ${IssuanceAddr1} "$main_ip"
chain33_applyCoins "${IssuanceAddr2}" 1000000000 "${main_ip}"
chain33_QueryBalance "${IssuanceAddr2}" "$main_ip"
chain33_applyCoins "${IssuanceAddr3}" 1000000000 "${main_ip}"
chain33_QueryBalance "${IssuanceAddr3}" "$main_ip"
chain33_applyCoins "${CollateralizeAddr}" 1000000000 "${main_ip}"
chain33_QueryBalance "${CollateralizeAddr}" "$main_ip"
chain33_applyCoins "${TokenAddr}" 1000000000 "${main_ip}"
chain33_QueryBalance "${TokenAddr}" "$main_ip"
local para_ip="${MAIN_HTTP}"
#para chain import pri key
#1C9t6uNcmbUgebt9HZfKweNb58hUcq5MZY
chain33_ImportPrivkey ${IssuancePriv1} ${IssuanceAddr1} "issuance1" "${para_ip}"
#16pjXn7vMVPqKjuVnYV44ANQGD1TRaw3ct
chain33_ImportPrivkey ${IssuancePriv2} ${IssuanceAddr2} "issuance2" "${para_ip}"
#1CQMn9B5Rh6s8wtnYEhuQwtVxPjcXSC4qC
chain33_ImportPrivkey ${IssuancePriv3} ${IssuanceAddr3} "issuance3" "${para_ip}"
#1BLfkPaAGqSiXyovx3Pm9xUTMHmusLXtLZ
chain33_ImportPrivkey ${CollateralizePriv} ${CollateralizeAddr} "coll" "${para_ip}"
chain33_applyCoins "${IssuanceAddr3}" 12000000000 "${para_ip}"
chain33_QueryBalance "${IssuanceAddr3}" "$para_ip"
chain33_applyCoins "${CollateralizeAddr}" 12000000000 "${para_ip}"
chain33_QueryBalance "${CollateralizeAddr}" "$para_ip"
fi
chain33_SendToAddress "${IssuanceAddr3}" "$issuance_addr" 10000000000 ${MAIN_HTTP}
chain33_QueryExecBalance "${IssuanceAddr3}" "issuance" "$MAIN_HTTP"
chain33_BlockWait 1 "${MAIN_HTTP}"
chain33_SendToAddress "${CollateralizeAddr}" "$collateralize_addr" 10000000000 ${MAIN_HTTP}
chain33_QueryExecBalance "${CollateralizeAddr}" "collateralize" "$MAIN_HTTP"
chain33_BlockWait 1 "${MAIN_HTTP}"
}
manage() {
echo "========== # issuance add issuance-manage begin =========="
tx=$(curl -ksd '{"method":"Chain33.CreateTransaction","params":[{"execer":"manage","actionName":"Modify","payload":{"key": "issuance-manage", "value":"'"${IssuanceAddr1}"'", "op":"add"}}]}' ${MAIN_HTTP} | jq -r ".result")
data=$(curl -ksd '{"method":"Chain33.DecodeRawTransaction","params":[{"txHex":"'"$tx"'"}]}' ${MAIN_HTTP} | jq -r ".result.txs[0]")
ok=$(jq '(.execer != "")' <<<"$data")
[ "$ok" == true ]
echo_rst "$FUNCNAME" "$?"
chain33_SignAndSendTx "$tx" ${SystemManager} ${MAIN_HTTP}
echo "========== # issuance add issuance-manage end =========="
chain33_BlockWait 1 ${MAIN_HTTP}
echo "========== # issuance add issuance-price-feed begin =========="
tx=$(curl -ksd '{"method":"Chain33.CreateTransaction","params":[{"execer":"manage","actionName":"Modify","payload":{"key": "issuance-price-feed", "value":"'"${IssuanceAddr2}"'", "op":"add"}}]}' ${MAIN_HTTP} | jq -r ".result")
data=$(curl -ksd '{"method":"Chain33.DecodeRawTransaction","params":[{"txHex":"'"$tx"'"}]}' ${MAIN_HTTP} | jq -r ".result.txs[0]")
ok=$(jq '(.execer != "")' <<<"$data")
[ "$ok" == true ]
echo_rst "$FUNCNAME" "$?"
chain33_SignAndSendTx "$tx" ${SystemManager} ${MAIN_HTTP}
echo "========== # issuance add issuance-price-feed end =========="
chain33_BlockWait 1 ${MAIN_HTTP}
# echo "========== # issuance add issuance-guarantor begin =========="
# tx=$(curl -ksd '{"method":"Chain33.CreateTransaction","params":[{"execer":"manage","actionName":"Modify","payload":{"key": "issuance-guarantor", "value":"'"${IssuanceAddr3}"'", "op":"add"}}]}' ${MAIN_HTTP} | jq -r ".result")
#
# data=$(curl -ksd '{"method":"Chain33.DecodeRawTransaction","params":[{"txHex":"'"$tx"'"}]}' ${MAIN_HTTP} | jq -r ".result.txs[0]")
# ok=$(jq '(.execer != "")' <<<"$data")
#
# [ "$ok" == true ]
# echo_rst "$FUNCNAME" "$?"
#
# chain33_SignAndSendTx "$tx" ${SystemManager} ${MAIN_HTTP}
# echo "========== # issuance add issuance-guarantor end =========="
# chain33_BlockWait 1 ${MAIN_HTTP}
}
token() {
echo "========== # issuance add token begin =========="
echo "========== # issuance add token token-blacklist begin =========="
tx=$(curl -ksd '{"method":"Chain33.CreateTransaction","params":[{"execer":"manage","actionName":"Modify","payload":{"key": "token-blacklist", "value":"BTY", "op":"add"}}]}' ${MAIN_HTTP} | jq -r ".result")
data=$(curl -ksd '{"method":"Chain33.DecodeRawTransaction","params":[{"txHex":"'"$tx"'"}]}' ${MAIN_HTTP} | jq -r ".result.txs[0]")
ok=$(jq '(.execer != "")' <<<"$data")
[ "$ok" == true ]
echo_rst "$FUNCNAME" "$?"
chain33_SignAndSendTx "${tx}" "${TokenSuperManager}" "${MAIN_HTTP}"
echo "========== # issuance add token token-blacklist end =========="
chain33_BlockWait 1 ${MAIN_HTTP}
echo "========== # issuance add token token-finisher begin =========="
tx=$(curl -ksd '{"method":"Chain33.CreateTransaction","params":[{"execer":"manage","actionName":"Modify","payload":{"key": "token-finisher", "value":"'${TokenAddr}'", "op":"add"}}]}' ${MAIN_HTTP} | jq -r ".result")
data=$(curl -ksd '{"method":"Chain33.DecodeRawTransaction","params":[{"txHex":"'"$tx"'"}]}' ${MAIN_HTTP} | jq -r ".result.txs[0]")
ok=$(jq '(.execer != "")' <<<"$data")
[ "$ok" == true ]
echo_rst "$FUNCNAME" "$?"
chain33_SignAndSendTx "${tx}" "${TokenSuperManager}" "${MAIN_HTTP}"
echo "========== # issuance add token token-finisher end =========="
chain33_BlockWait 1 ${MAIN_HTTP}
echo "========== # issuance add token precreate begin =========="
tx=$(curl -ksd '{"method":"token.CreateRawTokenPreCreateTx","params":[{"name": "ccny", "symbol": "CCNY", "total": 10000000000000000, "price": 0, "category": 1,"owner":"'${TokenAddr}'"}]}' ${MAIN_HTTP} | jq -r ".result")
data=$(curl -ksd '{"method":"Chain33.DecodeRawTransaction","params":[{"txHex":"'"$tx"'"}]}' ${MAIN_HTTP} | jq -r ".result.txs[0]")
ok=$(jq '(.execer != "")' <<<"$data")
[ "$ok" == true ]
echo_rst "$FUNCNAME" "$?"
chain33_SignAndSendTx "${tx}" "${TokenSuperManager}" "${MAIN_HTTP}"
echo "========== # issuance add token precreate end =========="
chain33_BlockWait 1 ${MAIN_HTTP}
echo "========== # issuance add token finish begin =========="
tx=$(curl -ksd '{"method":"token.CreateRawTokenFinishTx","params":[{"symbol": "CCNY", "owner":"'${TokenAddr}'"}]}' ${MAIN_HTTP} | jq -r ".result")
data=$(curl -ksd '{"method":"Chain33.DecodeRawTransaction","params":[{"txHex":"'"$tx"'"}]}' ${MAIN_HTTP} | jq -r ".result.txs[0]")
ok=$(jq '(.execer != "")' <<<"$data")
[ "$ok" == true ]
echo_rst "$FUNCNAME" "$?"
chain33_SignAndSendTx "${tx}" "${TokenSuperManager}" "${MAIN_HTTP}"
echo "========== # issuance add token finish end =========="
chain33_BlockWait 1 ${MAIN_HTTP}
echo "========== # issuance add token transfer begin =========="
tx=$(curl -ksd '{"method":"Chain33.CreateTransaction","params":[{"execer": "token","actionName":"Transfer","payload": {"cointoken":"CCNY", "amount": "10000000000000", "note": "", "to": "'"${IssuanceAddr1}"'"}}]}' ${MAIN_HTTP} | jq -r ".result")
data=$(curl -ksd '{"method":"Chain33.DecodeRawTransaction","params":[{"txHex":"'"$tx"'"}]}' ${MAIN_HTTP} | jq -r ".result.txs[0]")
ok=$(jq '(.execer != "")' <<<"$data")
[ "$ok" == true ]
echo_rst "$FUNCNAME" "$?"
chain33_SignAndSendTx "${tx}" "${TokenSuperManager}" "${MAIN_HTTP}"
tx=$(curl -ksd '{"method":"Chain33.CreateTransaction","params":[{"execer": "token","actionName":"Transfer","payload": {"cointoken":"CCNY", "amount": "10000000000000", "note": "", "to": "'"${IssuanceAddr3}"'"}}]}' ${MAIN_HTTP} | jq -r ".result")
data=$(curl -ksd '{"method":"Chain33.DecodeRawTransaction","params":[{"txHex":"'"$tx"'"}]}' ${MAIN_HTTP} | jq -r ".result.txs[0]")
ok=$(jq '(.execer != "")' <<<"$data")
[ "$ok" == true ]
echo_rst "$FUNCNAME" "$?"
chain33_SignAndSendTx "${tx}" "${TokenSuperManager}" "${MAIN_HTTP}"
tx=$(curl -ksd '{"method":"Chain33.CreateTransaction","params":[{"execer": "token","actionName":"Transfer","payload": {"cointoken":"CCNY", "amount": "100000000000", "note": "", "to": "'"${CollateralizeAddr}"'"}}]}' ${MAIN_HTTP} | jq -r ".result")
data=$(curl -ksd '{"method":"Chain33.DecodeRawTransaction","params":[{"txHex":"'"$tx"'"}]}' ${MAIN_HTTP} | jq -r ".result.txs[0]")
ok=$(jq '(.execer != "")' <<<"$data")
[ "$ok" == true ]
echo_rst "$FUNCNAME" "$?"
chain33_SignAndSendTx "${tx}" "${TokenSuperManager}" "${MAIN_HTTP}"
echo "========== # issuance add token transfer end =========="
chain33_BlockWait 1 ${MAIN_HTTP}
echo "========== # issuance add token transfer to issuance begin =========="
tx=$(curl -ksd '{"method":"Chain33.CreateTransaction","params":[{"execer": "token","actionName":"Transfer","payload": {"cointoken":"CCNY", "amount": "10000000000000", "note": "", "to": "'"${issuance_addr}"'"}}]}' ${MAIN_HTTP} | jq -r ".result")
data=$(curl -ksd '{"method":"Chain33.DecodeRawTransaction","params":[{"txHex":"'"$tx"'"}]}' ${MAIN_HTTP} | jq -r ".result.txs[0]")
ok=$(jq '(.execer != "")' <<<"$data")
[ "$ok" == true ]
echo_rst "$FUNCNAME" "$?"
chain33_SignAndSendTx "${tx}" "${IssuancePriv1}" "${MAIN_HTTP}"
tx=$(curl -ksd '{"method":"Chain33.CreateTransaction","params":[{"execer": "token","actionName":"Transfer","payload": {"cointoken":"CCNY", "amount": "10000000000000", "note": "", "to": "'"${collateralize_addr}"'"}}]}' ${MAIN_HTTP} | jq -r ".result")
data=$(curl -ksd '{"method":"Chain33.DecodeRawTransaction","params":[{"txHex":"'"$tx"'"}]}' ${MAIN_HTTP} | jq -r ".result.txs[0]")
ok=$(jq '(.execer != "")' <<<"$data")
[ "$ok" == true ]
echo_rst "$FUNCNAME" "$?"
chain33_SignAndSendTx "${tx}" "${IssuancePriv3}" "${MAIN_HTTP}"
tx=$(curl -ksd '{"method":"Chain33.CreateTransaction","params":[{"execer": "token","actionName":"Transfer","payload": {"cointoken":"CCNY", "amount": "100000000000", "note": "", "to": "'"${collateralize_addr}"'"}}]}' ${MAIN_HTTP} | jq -r ".result")
data=$(curl -ksd '{"method":"Chain33.DecodeRawTransaction","params":[{"txHex":"'"$tx"'"}]}' ${MAIN_HTTP} | jq -r ".result.txs[0]")
ok=$(jq '(.execer != "")' <<<"$data")
[ "$ok" == true ]
echo_rst "$FUNCNAME" "$?"
chain33_SignAndSendTx "${tx}" "${CollateralizePriv}" "${MAIN_HTTP}"
echo "========== # issuance add token transfer to issuance end =========="
chain33_BlockWait 1 ${MAIN_HTTP}
}
function issuance_test() {
issuance_Create
issuance_Manage
issuance_Feed
issuance_Debt
issuance_Repay
issuance_Close
}
function collateralize_test() {
collateralize_Manage
collateralize_Create
collateralize_Feed
collateralize_Borrow
collateralize_Append
collateralize_Repay
collateralize_Retrieve
}
function main() {
chain33_RpcTestBegin "issuance & collateralize"
MAIN_HTTP="$1"
echo "ip=$MAIN_HTTP"
init
manage
token
issuance_test
collateralize_test
chain33_RpcTestRst "issuance & collateralize" "$CASE_ERR"
}
chain33_debug_function main "$1"
package commands
import (
"fmt"
"strconv"
jsonrpc "github.com/33cn/chain33/rpc/jsonclient"
rpctypes "github.com/33cn/chain33/rpc/types"
"github.com/33cn/chain33/types"
pkt "github.com/33cn/plugin/plugin/dapp/issuance/types"
"github.com/spf13/cobra"
)
// IssuanceCmd 斗牛游戏命令行
func IssuanceCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "issuance",
Short: "Issuance command",
Args: cobra.MinimumNArgs(1),
}
cmd.AddCommand(
IssuanceCreateRawTxCmd(),
IssuanceDebtRawTxCmd(),
IssuanceRepayRawTxCmd(),
IssuancePriceFeedRawTxCmd(),
IssuanceCloseRawTxCmd(),
IssuanceManageRawTxCmd(),
IssuanceQueryCmd(),
)
return cmd
}
// IssuanceCreateRawTxCmd 生成开始交易命令行
func IssuanceCreateRawTxCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "create",
Short: "Create a issuance",
Run: IssuanceCreate,
}
addIssuanceCreateFlags(cmd)
return cmd
}
func addIssuanceCreateFlags(cmd *cobra.Command) {
cmd.Flags().Float64P("balance", "b", 0, "balance")
cmd.MarkFlagRequired("balance")
cmd.Flags().Float64P("debtCeiling", "d", 0, "debtCeiling")
cmd.Flags().Float64P("liquidationRatio", "l", 0, "liquidationRatio")
cmd.Flags().Uint64P("period", "p", 0, "period")
}
func IssuanceCreate(cmd *cobra.Command, args []string) {
title, _ := cmd.Flags().GetString("title")
cfg := types.GetCliSysParam(title)
if cfg == nil {
panic(fmt.Sprintln("can not find CliSysParam title", title))
}
rpcLaddr, _ := cmd.Flags().GetString("rpc_laddr")
balance, _ := cmd.Flags().GetFloat64("balance")
debtCeiling, _ := cmd.Flags().GetFloat64("debtCeiling")
liquidationRatio, _ := cmd.Flags().GetFloat64("liquidationRatio")
period, _ := cmd.Flags().GetUint64("period")
params := &rpctypes.CreateTxIn{
Execer: cfg.ExecName(pkt.IssuanceX),
ActionName: "IssuanceCreate",
Payload: []byte(fmt.Sprintf("{\"totalBalance\":%f, \"debtCeiling\":%f, \"liquidationRatio\":%f, \"period\":%d}",
balance, debtCeiling, liquidationRatio, period)),
}
var res string
ctx := jsonrpc.NewRPCCtx(rpcLaddr, "Chain33.CreateTransaction", params, &res)
ctx.RunWithoutMarshal()
}
// IssuanceDebtRawTxCmd 生成开始交易命令行
func IssuanceDebtRawTxCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "debt",
Short: "Debt a issuance",
Run: IssuanceDebt,
}
addIssuanceDebtFlags(cmd)
return cmd
}
func addIssuanceDebtFlags(cmd *cobra.Command) {
cmd.Flags().StringP("issuanceID", "g", "", "issuance ID")
cmd.MarkFlagRequired("issuanceID")
cmd.Flags().Float64P("value", "v", 0, "value")
cmd.MarkFlagRequired("value")
}
func IssuanceDebt(cmd *cobra.Command, args []string) {
title, _ := cmd.Flags().GetString("title")
cfg := types.GetCliSysParam(title)
if cfg == nil {
panic(fmt.Sprintln("can not find CliSysParam title", title))
}
rpcLaddr, _ := cmd.Flags().GetString("rpc_laddr")
issuanceID, _ := cmd.Flags().GetString("issuanceID")
value, _ := cmd.Flags().GetFloat64("value")
params := &rpctypes.CreateTxIn{
Execer: cfg.ExecName(pkt.IssuanceX),
ActionName: "IssuanceDebt",
Payload: []byte(fmt.Sprintf("{\"issuanceID\":\"%s\",\"value\":%f}", issuanceID, value)),
}
var res string
ctx := jsonrpc.NewRPCCtx(rpcLaddr, "Chain33.CreateTransaction", params, &res)
ctx.RunWithoutMarshal()
}
// IssuanceRepayRawTxCmd 生成开始交易命令行
func IssuanceRepayRawTxCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "repay",
Short: "Repay a issuance",
Run: IssuanceRepay,
}
addIssuanceRepayFlags(cmd)
return cmd
}
func addIssuanceRepayFlags(cmd *cobra.Command) {
cmd.Flags().StringP("issuanceID", "g", "", "issuance ID")
cmd.MarkFlagRequired("issuanceID")
cmd.Flags().StringP("debtID", "d", "", "debt ID")
cmd.MarkFlagRequired("debtID")
}
func IssuanceRepay(cmd *cobra.Command, args []string) {
title, _ := cmd.Flags().GetString("title")
cfg := types.GetCliSysParam(title)
if cfg == nil {
panic(fmt.Sprintln("can not find CliSysParam title", title))
}
rpcLaddr, _ := cmd.Flags().GetString("rpc_laddr")
issuanceID, _ := cmd.Flags().GetString("issuanceID")
debtID, _ := cmd.Flags().GetString("debtID")
params := &rpctypes.CreateTxIn{
Execer: cfg.ExecName(pkt.IssuanceX),
ActionName: "IssuanceRepay",
Payload: []byte(fmt.Sprintf("{\"issuanceID\":\"%s\", \"debtID\":\"%s\"}", issuanceID, debtID)),
}
var res string
ctx := jsonrpc.NewRPCCtx(rpcLaddr, "Chain33.CreateTransaction", params, &res)
ctx.RunWithoutMarshal()
}
// IssuancePriceFeedRawTxCmd 生成开始交易命令行
func IssuancePriceFeedRawTxCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "feed",
Short: "price feed",
Run: IssuancePriceFeed,
}
addIssuancePriceFeedFlags(cmd)
return cmd
}
func addIssuancePriceFeedFlags(cmd *cobra.Command) {
cmd.Flags().Float64P("price", "p", 0, "price")
cmd.MarkFlagRequired("price")
cmd.Flags().Uint64P("volume", "v", 0, "volume")
cmd.MarkFlagRequired("volume")
}
func IssuancePriceFeed(cmd *cobra.Command, args []string) {
title, _ := cmd.Flags().GetString("title")
cfg := types.GetCliSysParam(title)
if cfg == nil {
panic(fmt.Sprintln("can not find CliSysParam title", title))
}
rpcLaddr, _ := cmd.Flags().GetString("rpc_laddr")
price, _ := cmd.Flags().GetFloat64("price")
volume, _ := cmd.Flags().GetUint64("volume")
params := &rpctypes.CreateTxIn{
Execer: cfg.ExecName(pkt.IssuanceX),
ActionName: "IssuancePriceFeed",
Payload: []byte(fmt.Sprintf("{\"price\":[ %f ], \"volume\":[ %d ]}", price, volume)),
}
var res string
ctx := jsonrpc.NewRPCCtx(rpcLaddr, "Chain33.CreateTransaction", params, &res)
ctx.RunWithoutMarshal()
}
// IssuanceCloseRawTxCmd 生成开始交易命令行
func IssuanceCloseRawTxCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "close",
Short: "close a issuance",
Run: IssuanceClose,
}
addIssuanceCloseFlags(cmd)
return cmd
}
func addIssuanceCloseFlags(cmd *cobra.Command) {
cmd.Flags().StringP("issuanceID", "g", "", "issuance ID")
cmd.MarkFlagRequired("issuanceID")
}
func IssuanceClose(cmd *cobra.Command, args []string) {
title, _ := cmd.Flags().GetString("title")
cfg := types.GetCliSysParam(title)
if cfg == nil {
panic(fmt.Sprintln("can not find CliSysParam title", title))
}
rpcLaddr, _ := cmd.Flags().GetString("rpc_laddr")
issuanceID, _ := cmd.Flags().GetString("issuanceID")
params := &rpctypes.CreateTxIn{
Execer: cfg.ExecName(pkt.IssuanceX),
ActionName: "IssuanceClose",
Payload: []byte(fmt.Sprintf("{\"issuanceId\":\"%s\"}", issuanceID)),
}
var res string
ctx := jsonrpc.NewRPCCtx(rpcLaddr, "Chain33.CreateTransaction", params, &res)
ctx.RunWithoutMarshal()
}
// IssuanceManageRawTxCmd 生成开始交易命令行
func IssuanceManageRawTxCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "manage",
Short: "manage a issuance",
Run: IssuanceManage,
}
addIssuanceManageFlags(cmd)
return cmd
}
func addIssuanceManageFlags(cmd *cobra.Command) {
cmd.Flags().StringP("addr", "a", "", "addr")
cmd.MarkFlagRequired("addr")
}
func IssuanceManage(cmd *cobra.Command, args []string) {
title, _ := cmd.Flags().GetString("title")
cfg := types.GetCliSysParam(title)
if cfg == nil {
panic(fmt.Sprintln("can not find CliSysParam title", title))
}
rpcLaddr, _ := cmd.Flags().GetString("rpc_laddr")
addr, _ := cmd.Flags().GetString("addr")
params := &rpctypes.CreateTxIn{
Execer: cfg.ExecName(pkt.IssuanceX),
ActionName: "IssuanceManage",
Payload: []byte(fmt.Sprintf("{\"addr\":[\"%s\"]}", addr)),
}
var res string
ctx := jsonrpc.NewRPCCtx(rpcLaddr, "Chain33.CreateTransaction", params, &res)
ctx.RunWithoutMarshal()
}
func IssuacneQueryPriceCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "price",
Short: "Query latest price",
Run: IssuanceQueryPrice,
}
return cmd
}
func IssuanceQueryPrice(cmd *cobra.Command, args []string) {
rpcLaddr, _ := cmd.Flags().GetString("rpc_laddr")
var params rpctypes.Query4Jrpc
params.Execer = pkt.IssuanceX
params.FuncName = "IssuancePrice"
var res pkt.RepIssuancePrice
ctx := jsonrpc.NewRPCCtx(rpcLaddr, "Chain33.Query", params, &res)
ctx.Run()
}
func IssuanceQueryUserBalanceCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "balance",
Short: "Query user balance",
Run: IssuanceQueryUserBalance,
}
addIssuanceQueryBalanceFlags(cmd)
return cmd
}
func addIssuanceQueryBalanceFlags(cmd *cobra.Command) {
cmd.Flags().StringP("address", "a", "", "address")
cmd.MarkFlagRequired("address")
}
func IssuanceQueryUserBalance(cmd *cobra.Command, args []string) {
rpcLaddr, _ := cmd.Flags().GetString("rpc_laddr")
addr, _ := cmd.Flags().GetString("address")
var params rpctypes.Query4Jrpc
params.Execer = pkt.IssuanceX
params.FuncName = "IssuanceUserBalance"
req := &pkt.ReqIssuanceRecords{
Addr: addr,
}
params.Payload = types.MustPBToJSON(req)
var res pkt.RepIssuanceUserBalance
ctx := jsonrpc.NewRPCCtx(rpcLaddr, "Chain33.Query", params, &res)
ctx.Run()
}
// IssuanceQueryCmd 查询命令行
func IssuanceQueryCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "query",
Short: "Query result",
Run: IssuanceQuery,
}
addIssuanceQueryFlags(cmd)
cmd.AddCommand(
IssuacneQueryPriceCmd(),
IssuanceQueryUserBalanceCmd(),
)
return cmd
}
func addIssuanceQueryFlags(cmd *cobra.Command) {
cmd.Flags().StringP("issuanceID", "g", "", "issuance ID")
cmd.Flags().StringP("address", "a", "", "address")
cmd.Flags().StringP("index", "i", "", "index")
cmd.Flags().StringP("status", "s", "", "status")
cmd.Flags().StringP("issuanceIDs", "e", "", "issuance IDs")
cmd.Flags().StringP("debtID", "d", "", "debt ID")
}
func IssuanceQuery(cmd *cobra.Command, args []string) {
rpcLaddr, _ := cmd.Flags().GetString("rpc_laddr")
issuanceID, _ := cmd.Flags().GetString("issuanceID")
address, _ := cmd.Flags().GetString("address")
statusStr, _ := cmd.Flags().GetString("status")
issuanceIDs, _ := cmd.Flags().GetString("issuanceIDs")
debtID, _ := cmd.Flags().GetString("debtID")
var params rpctypes.Query4Jrpc
params.Execer = pkt.IssuanceX
var status int64
var err error
if statusStr != "" {
status, err = strconv.ParseInt(statusStr, 10, 32)
if err != nil {
fmt.Println(err)
cmd.Help()
return
}
}
if issuanceID != "" {
if address != "" {
params.FuncName = "IssuanceRecordsByAddr"
req := &pkt.ReqIssuanceRecords{
IssuanceId: issuanceID,
Status: int32(status),
Addr: address,
}
params.Payload = types.MustPBToJSON(req)
var res pkt.RepIssuanceRecords
ctx := jsonrpc.NewRPCCtx(rpcLaddr, "Chain33.Query", params, &res)
ctx.Run()
} else if statusStr != "" {
params.FuncName = "IssuanceRecordsByStatus"
req := &pkt.ReqIssuanceRecords{
IssuanceId: issuanceID,
Status: int32(status),
}
params.Payload = types.MustPBToJSON(req)
var res pkt.RepIssuanceRecords
ctx := jsonrpc.NewRPCCtx(rpcLaddr, "Chain33.Query", params, &res)
ctx.Run()
} else if debtID != "" {
params.FuncName = "IssuanceRecordByID"
req := &pkt.ReqIssuanceRecords{
IssuanceId: issuanceID,
DebtId: debtID,
}
params.Payload = types.MustPBToJSON(req)
var res pkt.RepIssuanceDebtInfo
ctx := jsonrpc.NewRPCCtx(rpcLaddr, "Chain33.Query", params, &res)
ctx.Run()
} else {
params.FuncName = "IssuanceInfoByID"
req := &pkt.ReqIssuanceInfo{
IssuanceId: issuanceID,
}
params.Payload = types.MustPBToJSON(req)
var res pkt.RepIssuanceCurrentInfo
ctx := jsonrpc.NewRPCCtx(rpcLaddr, "Chain33.Query", params, &res)
ctx.Run()
}
} else if statusStr != "" {
params.FuncName = "IssuanceByStatus"
req := &pkt.ReqIssuanceByStatus{Status: int32(status)}
params.Payload = types.MustPBToJSON(req)
var res pkt.RepIssuanceIDs
ctx := jsonrpc.NewRPCCtx(rpcLaddr, "Chain33.Query", params, &res)
ctx.Run()
} else if issuanceIDs != "" {
params.FuncName = "IssuanceInfoByIDs"
var issuanceIDsS []string
issuanceIDsS = append(issuanceIDsS, issuanceIDs)
issuanceIDsS = append(issuanceIDsS, issuanceIDs)
req := &pkt.ReqIssuanceInfos{IssuanceIds: issuanceIDsS}
params.Payload = types.MustPBToJSON(req)
fmt.Println(params.Payload)
var res pkt.RepIssuanceCurrentInfos
ctx := jsonrpc.NewRPCCtx(rpcLaddr, "Chain33.Query", params, &res)
ctx.Run()
} else {
cmd.Help()
}
}
// 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()
}
package executor
import (
"testing"
"time"
"github.com/33cn/chain33/client"
"github.com/33cn/chain33/account"
apimock "github.com/33cn/chain33/client/mocks"
"github.com/33cn/chain33/common"
"github.com/33cn/chain33/common/crypto"
dbm "github.com/33cn/chain33/common/db"
"github.com/33cn/chain33/system/dapp"
pty "github.com/33cn/chain33/system/dapp/manage/types"
"github.com/33cn/chain33/types"
"github.com/33cn/chain33/util"
pkt "github.com/33cn/plugin/plugin/dapp/issuance/types"
tokenE "github.com/33cn/plugin/plugin/dapp/token/executor"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
)
type execEnv struct {
blockTime int64
blockHeight int64
difficulty uint64
kvdb dbm.KVDB
api client.QueueProtocolAPI
db dbm.KV
execAddr string
cfg *types.Chain33Config
}
var (
PrivKeyA = "0x6da92a632ab7deb67d38c0f6560bcfed28167998f6496db64c258d5e8393a81b" // 1KSBd17H7ZK8iT37aJztFB22XGwsPTdwE4
PrivKeyB = "0x19c069234f9d3e61135fefbeb7791b149cdf6af536f26bebb310d4cd22c3fee4" // 1JRNjdEqp4LJ5fqycUBm9ayCKSeeskgMKR
PrivKeyC = "0xc2b31057b8692a56c7dd18199df71c1d21b781c0b6858c52997c9dbf778e8550" // 12evczYyX9ZKPYvwSEvRkRyTjpSrJuLudg
Nodes = [][]byte{
[]byte("1KSBd17H7ZK8iT37aJztFB22XGwsPTdwE4"),
[]byte("1JRNjdEqp4LJ5fqycUBm9ayCKSeeskgMKR"),
[]byte("12evczYyX9ZKPYvwSEvRkRyTjpSrJuLudg"),
}
total = 10000 * types.Coin
totalToken = 100000 * types.Coin
)
func manageKeySet(key string, value string, db dbm.KV) {
var item types.ConfigItem
item.Key = key
item.Addr = value
item.Ty = pty.ConfigItemArrayConfig
emptyValue := &types.ArrayConfig{Value: make([]string, 0)}
arr := types.ConfigItem_Arr{Arr: emptyValue}
item.Value = &arr
item.GetArr().Value = append(item.GetArr().Value, value)
manageKey := types.ManageKey(key)
valueSave := types.Encode(&item)
db.Set([]byte(manageKey), valueSave)
}
func initEnv() *execEnv {
cfg := types.NewChain33Config(types.GetDefaultCfgstring())
cfg.SetTitleOnlyForTest("chain33")
Init(pkt.IssuanceX, cfg, nil)
_, _, kvdb := util.CreateTestDB()
accountA := types.Account{
Balance: total,
Frozen: 0,
Addr: string(Nodes[0]),
}
accountAToken := types.Account{
Balance: totalToken,
Frozen: 0,
Addr: string(Nodes[0]),
}
accountB := types.Account{
Balance: total,
Frozen: 0,
Addr: string(Nodes[1]),
}
accountC := types.Account{
Balance: total,
Frozen: 0,
Addr: string(Nodes[2]),
}
api := new(apimock.QueueProtocolAPI)
api.On("GetConfig", mock.Anything).Return(cfg, nil)
execAddr := dapp.ExecAddress(pkt.IssuanceX)
stateDB, _ := dbm.NewGoMemDB("1", "2", 100)
accA := account.NewCoinsAccount(cfg)
accA.SetDB(stateDB)
accA.SaveExecAccount(execAddr, &accountA)
manageKeySet("issuance-manage", accountA.Addr, stateDB)
tokenAccA, _ := account.NewAccountDB(cfg, tokenE.GetName(), pkt.CCNYTokenName, stateDB)
tokenAccA.SaveExecAccount(execAddr, &accountAToken)
accB := account.NewCoinsAccount(cfg)
accB.SetDB(stateDB)
accB.SaveExecAccount(execAddr, &accountB)
manageKeySet("issuance-price-feed", accountB.Addr, stateDB)
accC := account.NewCoinsAccount(cfg)
accC.SetDB(stateDB)
accC.SaveExecAccount(execAddr, &accountC)
manageKeySet("issuance-guarantor", accountC.Addr, stateDB)
return &execEnv{
blockTime: time.Now().Unix(),
blockHeight: cfg.GetDappFork(pkt.IssuanceX, "Enable"),
difficulty: 1539918074,
kvdb: kvdb,
api: api,
db: stateDB,
execAddr: execAddr,
cfg: cfg,
}
}
func TestIssuance(t *testing.T) {
env := initEnv()
// issuance create
p1 := &pkt.IssuanceCreateTx{
TotalBalance: 1000,
DebtCeiling: 100,
LiquidationRatio: 0.25,
Period: 5,
}
createTx, err := pkt.CreateRawIssuanceCreateTx(env.cfg, p1)
if err != nil {
t.Error("RPC_Default_Process", "err", err)
}
createTx.Execer = []byte(pkt.IssuanceX)
createTx, err = signTx(createTx, PrivKeyA)
if err != nil {
t.Error("RPC_Default_Process sign", "err", err)
}
exec := newIssuance()
exec.SetAPI(env.api)
exec.SetStateDB(env.db)
assert.Equal(t, exec.GetCoinsAccount().LoadExecAccount(string(Nodes[0]), env.execAddr).GetBalance(), total)
exec.SetLocalDB(env.kvdb)
exec.SetEnv(env.blockHeight, env.blockTime, env.difficulty)
receipt, err := exec.Exec(createTx, int(1))
assert.Nil(t, err)
assert.NotNil(t, receipt)
for _, kv := range receipt.KV {
env.db.Set(kv.Key, kv.Value)
}
receiptData := &types.ReceiptData{Ty: receipt.Ty, Logs: receipt.Logs}
set, err := exec.ExecLocal(createTx, receiptData, int(1))
assert.Nil(t, err)
assert.NotNil(t, set)
for _, kv := range set.KV {
env.kvdb.Set(kv.Key, kv.Value)
}
issuanceID := createTx.Hash()
// query issuance by id
res, err := exec.Query("IssuanceInfoByID", types.Encode(&pkt.ReqIssuanceInfo{IssuanceId: common.ToHex(issuanceID)}))
assert.Nil(t, err)
assert.NotNil(t, res)
// query issuance by status
res, err = exec.Query("IssuanceByStatus", types.Encode(&pkt.ReqIssuanceByStatus{Status: 1}))
assert.Nil(t, err)
assert.NotNil(t, res)
// query issuances by ids
var issuanceIDsS []string
issuanceIDsS = append(issuanceIDsS, common.ToHex(issuanceID))
res, err = exec.Query("IssuanceInfoByIDs", types.Encode(&pkt.ReqIssuanceInfos{IssuanceIds: issuanceIDsS}))
assert.Nil(t, err)
assert.NotNil(t, res)
// issuance price
p2 := &pkt.IssuanceFeedTx{}
p2.Price = append(p2.Price, 1)
p2.Volume = append(p2.Volume, 100)
createTx, err = pkt.CreateRawIssuanceFeedTx(env.cfg, p2)
if err != nil {
t.Error("RPC_Default_Process", "err", err)
}
createTx.Execer = []byte(pkt.IssuanceX)
createTx, err = signTx(createTx, PrivKeyB)
if err != nil {
t.Error("RPC_Default_Process sign", "err", err)
}
exec.SetEnv(env.blockHeight+1, env.blockTime+1, env.difficulty)
receipt, err = exec.Exec(createTx, int(1))
assert.Nil(t, err)
assert.NotNil(t, receipt)
t.Log(receipt)
for _, kv := range receipt.KV {
env.db.Set(kv.Key, kv.Value)
}
receiptData = &types.ReceiptData{Ty: receipt.Ty, Logs: receipt.Logs}
set, err = exec.ExecLocal(createTx, receiptData, int(1))
assert.Nil(t, err)
assert.NotNil(t, set)
for _, kv := range set.KV {
env.kvdb.Set(kv.Key, kv.Value)
}
// query issuance by id
res, err = exec.Query("IssuancePrice", nil)
assert.Nil(t, err)
assert.NotNil(t, res)
// issuance manage
p3 := &pkt.IssuanceManageTx{}
p3.Addr = append(p3.Addr, string(Nodes[1]))
createTx, err = pkt.CreateRawIssuanceManageTx(env.cfg, p3)
if err != nil {
t.Error("RPC_Default_Process", "err", err)
}
createTx.Execer = []byte(pkt.IssuanceX)
createTx, err = signTx(createTx, PrivKeyA)
if err != nil {
t.Error("RPC_Default_Process sign", "err", err)
}
exec.SetEnv(env.blockHeight+1, env.blockTime+1, env.difficulty)
receipt, err = exec.Exec(createTx, int(1))
assert.Nil(t, err)
assert.NotNil(t, receipt)
t.Log(receipt)
for _, kv := range receipt.KV {
env.db.Set(kv.Key, kv.Value)
}
receiptData = &types.ReceiptData{Ty: receipt.Ty, Logs: receipt.Logs}
set, err = exec.ExecLocal(createTx, receiptData, int(1))
assert.Nil(t, err)
assert.NotNil(t, set)
for _, kv := range set.KV {
env.kvdb.Set(kv.Key, kv.Value)
}
// issuance debt
p4 := &pkt.IssuanceDebtTx{
IssuanceID: common.ToHex(issuanceID),
Value: 100,
}
createTx, err = pkt.CreateRawIssuanceDebtTx(env.cfg, p4)
if err != nil {
t.Error("RPC_Default_Process", "err", err)
}
createTx.Execer = []byte(pkt.IssuanceX)
createTx, err = signTx(createTx, PrivKeyB)
if err != nil {
t.Error("RPC_Default_Process sign", "err", err)
}
exec.SetEnv(env.blockHeight+1, env.blockTime+1, env.difficulty)
receipt, err = exec.Exec(createTx, int(1))
assert.Nil(t, err)
assert.NotNil(t, receipt)
t.Log(receipt)
for _, kv := range receipt.KV {
env.db.Set(kv.Key, kv.Value)
}
receiptData = &types.ReceiptData{Ty: receipt.Ty, Logs: receipt.Logs}
set, err = exec.ExecLocal(createTx, receiptData, int(1))
assert.Nil(t, err)
assert.NotNil(t, set)
for _, kv := range set.KV {
env.kvdb.Set(kv.Key, kv.Value)
}
debtID := createTx.Hash()
// query issuance by id
res, err = exec.Query("IssuanceRecordByID",
types.Encode(&pkt.ReqIssuanceRecords{IssuanceId: common.ToHex(issuanceID), DebtId: common.ToHex(debtID)}))
assert.Nil(t, err)
assert.NotNil(t, res)
// query issuance by status
res, err = exec.Query("IssuanceRecordsByStatus",
types.Encode(&pkt.ReqIssuanceRecords{Status: 1}))
assert.Nil(t, err)
assert.NotNil(t, res)
// query issuance by addr
res, err = exec.Query("IssuanceRecordsByAddr",
types.Encode(&pkt.ReqIssuanceRecords{Addr: string(Nodes[1])}))
assert.Nil(t, err)
assert.NotNil(t, res)
res, err = exec.Query("IssuanceRecordsByAddr",
types.Encode(&pkt.ReqIssuanceRecords{Addr: string(Nodes[1]), Status: 1}))
assert.Nil(t, err)
assert.NotNil(t, res)
// query issuance user balance
res, err = exec.Query("IssuanceUserBalance",
types.Encode(&pkt.ReqIssuanceRecords{Addr: string(Nodes[1]), Status: 1}))
assert.Nil(t, err)
assert.Equal(t, 100*types.Coin, res.(*pkt.RepIssuanceUserBalance).Balance)
// issuance repay
p5 := &pkt.IssuanceRepayTx{
IssuanceID: common.ToHex(issuanceID),
DebtID: common.ToHex(debtID),
}
createTx, err = pkt.CreateRawIssuanceRepayTx(env.cfg, p5)
if err != nil {
t.Error("RPC_Default_Process", "err", err)
}
createTx.Execer = []byte(pkt.IssuanceX)
createTx, err = signTx(createTx, PrivKeyB)
if err != nil {
t.Error("RPC_Default_Process sign", "err", err)
}
exec.SetEnv(env.blockHeight+1, env.blockTime+1, env.difficulty)
receipt, err = exec.Exec(createTx, int(1))
assert.Nil(t, err)
assert.NotNil(t, receipt)
t.Log(receipt)
for _, kv := range receipt.KV {
env.db.Set(kv.Key, kv.Value)
}
receiptData = &types.ReceiptData{Ty: receipt.Ty, Logs: receipt.Logs}
set, err = exec.ExecLocal(createTx, receiptData, int(1))
assert.Nil(t, err)
assert.NotNil(t, set)
for _, kv := range set.KV {
env.kvdb.Set(kv.Key, kv.Value)
}
// query issuance by status
res, err = exec.Query("IssuanceRecordsByStatus",
types.Encode(&pkt.ReqIssuanceRecords{Status: 6}))
assert.Nil(t, err)
assert.NotNil(t, res)
// query issuance by addr
res, err = exec.Query("IssuanceRecordsByAddr",
types.Encode(&pkt.ReqIssuanceRecords{Addr: string(Nodes[1])}))
assert.Nil(t, err)
assert.NotNil(t, res)
res, err = exec.Query("IssuanceRecordsByAddr",
types.Encode(&pkt.ReqIssuanceRecords{Addr: string(Nodes[1]), Status: 6}))
assert.Nil(t, err)
assert.NotNil(t, res)
// query issuance user balance
res, err = exec.Query("IssuanceUserBalance",
types.Encode(&pkt.ReqIssuanceRecords{Addr: string(Nodes[1]), Status: 1}))
assert.Nil(t, err)
assert.Equal(t, int64(0), res.(*pkt.RepIssuanceUserBalance).Balance)
// issuance liquidate
p6 := &pkt.IssuanceDebtTx{
IssuanceID: common.ToHex(issuanceID),
Value: 100,
}
createTx, err = pkt.CreateRawIssuanceDebtTx(env.cfg, p6)
if err != nil {
t.Error("RPC_Default_Process", "err", err)
}
createTx.Execer = []byte(pkt.IssuanceX)
createTx, err = signTx(createTx, PrivKeyB)
if err != nil {
t.Error("RPC_Default_Process sign", "err", err)
}
exec.SetEnv(env.blockHeight+1, env.blockTime+1, env.difficulty)
receipt, err = exec.Exec(createTx, int(1))
assert.Nil(t, err)
assert.NotNil(t, receipt)
t.Log(receipt)
for _, kv := range receipt.KV {
env.db.Set(kv.Key, kv.Value)
}
receiptData = &types.ReceiptData{Ty: receipt.Ty, Logs: receipt.Logs}
set, err = exec.ExecLocal(createTx, receiptData, int(1))
assert.Nil(t, err)
assert.NotNil(t, set)
for _, kv := range set.KV {
env.kvdb.Set(kv.Key, kv.Value)
}
p7 := &pkt.IssuanceFeedTx{}
p7.Price = append(p7.Price, 0.28)
p7.Volume = append(p7.Volume, 100)
createTx, err = pkt.CreateRawIssuanceFeedTx(env.cfg, p7)
if err != nil {
t.Error("RPC_Default_Process", "err", err)
}
createTx.Execer = []byte(pkt.IssuanceX)
createTx, err = signTx(createTx, PrivKeyB)
if err != nil {
t.Error("RPC_Default_Process sign", "err", err)
}
exec.SetEnv(env.blockHeight+1, env.blockTime+1, env.difficulty)
receipt, err = exec.Exec(createTx, int(1))
assert.Nil(t, err)
assert.NotNil(t, receipt)
t.Log(receipt)
for _, kv := range receipt.KV {
env.db.Set(kv.Key, kv.Value)
}
receiptData = &types.ReceiptData{Ty: receipt.Ty, Logs: receipt.Logs}
set, err = exec.ExecLocal(createTx, receiptData, int(1))
assert.Nil(t, err)
assert.NotNil(t, set)
for _, kv := range set.KV {
env.kvdb.Set(kv.Key, kv.Value)
}
// query issuance by status
res, err = exec.Query("IssuanceRecordsByStatus",
types.Encode(&pkt.ReqIssuanceRecords{Status: 2}))
assert.Nil(t, err)
assert.NotNil(t, res)
res, err = exec.Query("IssuanceRecordsByStatus",
types.Encode(&pkt.ReqIssuanceRecords{Status: 4}))
assert.Nil(t, res)
p8 := &pkt.IssuanceFeedTx{}
p8.Price = append(p8.Price, 0.5)
p8.Volume = append(p8.Volume, 100)
createTx, err = pkt.CreateRawIssuanceFeedTx(env.cfg, p8)
if err != nil {
t.Error("RPC_Default_Process", "err", err)
}
createTx.Execer = []byte(pkt.IssuanceX)
createTx, err = signTx(createTx, PrivKeyB)
if err != nil {
t.Error("RPC_Default_Process sign", "err", err)
}
exec.SetEnv(env.blockHeight+1, env.blockTime+1, env.difficulty)
receipt, err = exec.Exec(createTx, int(1))
assert.Nil(t, err)
assert.NotNil(t, receipt)
t.Log(receipt)
for _, kv := range receipt.KV {
env.db.Set(kv.Key, kv.Value)
}
receiptData = &types.ReceiptData{Ty: receipt.Ty, Logs: receipt.Logs}
set, err = exec.ExecLocal(createTx, receiptData, int(1))
assert.Nil(t, err)
assert.NotNil(t, set)
for _, kv := range set.KV {
env.kvdb.Set(kv.Key, kv.Value)
}
// query issuance by status
res, err = exec.Query("IssuanceRecordsByStatus", types.Encode(&pkt.ReqIssuanceRecords{Status: 4}))
assert.Nil(t, err)
assert.NotNil(t, res)
p81 := &pkt.IssuanceFeedTx{}
p81.Price = append(p81.Price, 0.25)
p81.Volume = append(p81.Volume, 100)
createTx, err = pkt.CreateRawIssuanceFeedTx(env.cfg, p81)
if err != nil {
t.Error("RPC_Default_Process", "err", err)
}
createTx.Execer = []byte(pkt.IssuanceX)
createTx, err = signTx(createTx, PrivKeyB)
if err != nil {
t.Error("RPC_Default_Process sign", "err", err)
}
exec.SetEnv(env.blockHeight+1, env.blockTime+1, env.difficulty)
receipt, err = exec.Exec(createTx, int(1))
assert.Nil(t, err)
assert.NotNil(t, receipt)
t.Log(receipt)
for _, kv := range receipt.KV {
env.db.Set(kv.Key, kv.Value)
}
receiptData = &types.ReceiptData{Ty: receipt.Ty, Logs: receipt.Logs}
set, err = exec.ExecLocal(createTx, receiptData, int(1))
assert.Nil(t, err)
assert.NotNil(t, set)
for _, kv := range set.KV {
env.kvdb.Set(kv.Key, kv.Value)
}
// query issuance by status
res, err = exec.Query("IssuanceRecordsByStatus",
types.Encode(&pkt.ReqIssuanceRecords{Status: 3}))
assert.Nil(t, err)
assert.NotNil(t, res)
res, err = exec.Query("IssuanceRecordsByStatus",
types.Encode(&pkt.ReqIssuanceRecords{Status: 4}))
assert.Nil(t, res)
// expire liquidate
p9 := &pkt.IssuanceDebtTx{
IssuanceID: common.ToHex(issuanceID),
Value: 100,
}
createTx, err = pkt.CreateRawIssuanceDebtTx(env.cfg, p9)
if err != nil {
t.Error("RPC_Default_Process", "err", err)
}
createTx.Execer = []byte(pkt.IssuanceX)
createTx, err = signTx(createTx, PrivKeyB)
if err != nil {
t.Error("RPC_Default_Process sign", "err", err)
}
exec.SetEnv(env.blockHeight+1, env.blockTime+1, env.difficulty)
receipt, err = exec.Exec(createTx, int(1))
assert.Nil(t, err)
assert.NotNil(t, receipt)
t.Log(receipt)
for _, kv := range receipt.KV {
env.db.Set(kv.Key, kv.Value)
}
receiptData = &types.ReceiptData{Ty: receipt.Ty, Logs: receipt.Logs}
set, err = exec.ExecLocal(createTx, receiptData, int(1))
assert.Nil(t, err)
assert.NotNil(t, set)
for _, kv := range set.KV {
env.kvdb.Set(kv.Key, kv.Value)
}
p10 := &pkt.IssuanceFeedTx{}
p10.Price = append(p10.Price, 1)
p10.Volume = append(p10.Volume, 100)
createTx, err = pkt.CreateRawIssuanceFeedTx(env.cfg, p10)
if err != nil {
t.Error("RPC_Default_Process", "err", err)
}
createTx.Execer = []byte(pkt.IssuanceX)
createTx, err = signTx(createTx, PrivKeyB)
if err != nil {
t.Error("RPC_Default_Process sign", "err", err)
}
exec.SetEnv(env.blockHeight+1, env.blockTime+6, env.difficulty)
receipt, err = exec.Exec(createTx, int(1))
assert.Nil(t, err)
assert.NotNil(t, receipt)
t.Log(receipt)
for _, kv := range receipt.KV {
env.db.Set(kv.Key, kv.Value)
}
receiptData = &types.ReceiptData{Ty: receipt.Ty, Logs: receipt.Logs}
set, err = exec.ExecLocal(createTx, receiptData, int(1))
assert.Nil(t, err)
assert.NotNil(t, set)
for _, kv := range set.KV {
env.kvdb.Set(kv.Key, kv.Value)
}
// query issuance by status
res, err = exec.Query("IssuanceRecordsByStatus",
types.Encode(&pkt.ReqIssuanceRecords{Status: 5}))
assert.Nil(t, err)
assert.NotNil(t, res)
// issuance close
p11 := &pkt.IssuanceCloseTx{
IssuanceID: common.ToHex(issuanceID),
}
createTx, err = pkt.CreateRawIssuanceCloseTx(env.cfg, p11)
if err != nil {
t.Error("RPC_Default_Process", "err", err)
}
createTx.Execer = []byte(pkt.IssuanceX)
createTx, err = signTx(createTx, PrivKeyA)
if err != nil {
t.Error("RPC_Default_Process sign", "err", err)
}
exec.SetEnv(env.blockHeight+2, env.blockTime+2, env.difficulty)
receipt, err = exec.Exec(createTx, int(1))
assert.Nil(t, err)
assert.NotNil(t, receipt)
for _, kv := range receipt.KV {
env.db.Set(kv.Key, kv.Value)
}
receiptData = &types.ReceiptData{Ty: receipt.Ty, Logs: receipt.Logs}
set, err = exec.ExecLocal(createTx, receiptData, int(1))
assert.Nil(t, err)
assert.NotNil(t, set)
for _, kv := range set.KV {
env.kvdb.Set(kv.Key, kv.Value)
}
// query issuance by status
res, err = exec.Query("IssuanceByStatus", types.Encode(&pkt.ReqIssuanceByStatus{Status: 2}))
assert.Nil(t, err)
assert.NotNil(t, res)
}
func signTx(tx *types.Transaction, hexPrivKey string) (*types.Transaction, error) {
signType := types.SECP256K1
c, err := crypto.New(types.GetSignName(pkt.IssuanceX, 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
}
// 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/account"
"github.com/33cn/chain33/common"
dbm "github.com/33cn/chain33/common/db"
"github.com/33cn/chain33/common/db/table"
"github.com/33cn/chain33/system/dapp"
"github.com/33cn/chain33/types"
pty "github.com/33cn/plugin/plugin/dapp/issuance/types"
tokenE "github.com/33cn/plugin/plugin/dapp/token/executor"
)
// List control
const (
ListDESC = int32(0) // list降序
ListASC = int32(1) // list升序
DefaultCount = int32(20) // 默认一次取多少条记录
MaxCount = int32(100) // 最多取100条
)
const (
Coin = types.Coin // 1e8
DefaultDebtCeiling = 100000 * Coin // 默认借贷限额
DefaultLiquidationRatio = 0.25 * 1e4 // 默认质押比
DefaultPeriod = 3600 * 24 * 365 // 默认合约限期
PriceWarningRate = 1.3 * 1e4 // 价格提前预警率
ExpireWarningTime = 3600 * 24 * 10 // 提前10天超时预警
)
func getManageKey(key string, db dbm.KV) ([]byte, error) {
manageKey := types.ManageKey(key)
value, err := db.Get([]byte(manageKey))
if err != nil {
return nil, err
}
return value, nil
}
func getGuarantorAddr(db dbm.KV) (string, error) {
value, err := getManageKey(pty.GuarantorKey, db)
if err != nil {
clog.Error("IssuancePriceFeed", "getGuarantorAddr", err)
return "", err
}
if value == nil {
clog.Error("IssuancePriceFeed guarantorKey found nil value")
return "", err
}
var item types.ConfigItem
err = types.Decode(value, &item)
if err != nil {
clog.Error("IssuancePriceFeed", "getGuarantorAddr", err)
return "", err
}
return item.GetArr().Value[0], nil
}
func isRightAddr(key string, addr string, db dbm.KV) bool {
value, err := getManageKey(key, db)
if err != nil {
clog.Error("isRightAddr", "Key", key)
return false
}
if value == nil {
clog.Error("isRightAddr", "key", key, "error", "Found key nil value")
return false
}
var item types.ConfigItem
err = types.Decode(value, &item)
if err != nil {
clog.Error("isRightAddr", "Decode", value)
return false
}
for _, op := range item.GetArr().Value {
if op == addr {
return true
}
}
return false
}
func isSuperAddr(addr string, db dbm.KV) bool {
data, err := db.Get(AddrKey())
if err != nil {
clog.Error("getSuperAddr", "error", err)
return false
}
var item types.ConfigItem
err = types.Decode(data, &item)
if err != nil {
clog.Error("isSuperAddr", "Decode", data)
return false
}
for _, op := range item.GetArr().Value {
if op == addr {
return true
}
}
return false
}
// IssuanceDB def
type IssuanceDB struct {
pty.Issuance
}
// GetKVSet for IssuanceDB
func (issu *IssuanceDB) GetKVSet() (kvset []*types.KeyValue) {
value := types.Encode(&issu.Issuance)
kvset = append(kvset, &types.KeyValue{Key: Key(issu.IssuanceId), Value: value})
return kvset
}
// Save for IssuanceDB
func (issu *IssuanceDB) Save(db dbm.KV) {
set := issu.GetKVSet()
for i := 0; i < len(set); i++ {
db.Set(set[i].GetKey(), set[i].Value)
}
}
// Key for Issuance
func Key(id string) (key []byte) {
key = append(key, []byte("mavl-"+pty.IssuanceX+"-")...)
key = append(key, []byte(id)...)
return key
}
// Key for IssuanceAddrConfig
func AddrKey() (key []byte) {
key = append(key, []byte("mavl-"+pty.IssuanceX+"-addr")...)
return key
}
// Key for IssuancePriceFeed
func PriceKey() (key []byte) {
key = append(key, []byte("mavl-"+pty.IssuanceX+"-price")...)
return key
}
// Action struct
type Action struct {
coinsAccount *account.DB // bty账户
tokenAccount *account.DB // ccny账户
db dbm.KV
localDB dbm.KVDB
txhash []byte
fromaddr string
blocktime int64
height int64
execaddr string
difficulty uint64
index int
Issuance *Issuance
}
// NewIssuanceAction generate New Action
func NewIssuanceAction(c *Issuance, tx *types.Transaction, index int) *Action {
hash := tx.Hash()
fromaddr := tx.From()
cfg := c.GetAPI().GetConfig()
tokenDb, err := account.NewAccountDB(cfg, tokenE.GetName(), pty.CCNYTokenName, c.GetStateDB())
if err != nil {
clog.Error("NewIssuanceAction", "Get Account DB error", "error", err)
return nil
}
return &Action{
coinsAccount: c.GetCoinsAccount(), tokenAccount: tokenDb, db: c.GetStateDB(), localDB: c.GetLocalDB(),
txhash: hash, fromaddr: fromaddr, blocktime: c.GetBlockTime(), height: c.GetHeight(),
execaddr: dapp.ExecAddress(string(tx.Execer)), difficulty: c.GetDifficulty(), index: index, Issuance: c}
}
// GetCreateReceiptLog generate logs for Issuance create action
func (action *Action) GetCreateReceiptLog(issuance *pty.Issuance) *types.ReceiptLog {
log := &types.ReceiptLog{}
log.Ty = pty.TyLogIssuanceCreate
c := &pty.ReceiptIssuance{}
c.IssuanceId = issuance.IssuanceId
c.Status = issuance.Status
log.Log = types.Encode(c)
return log
}
// GetDebtReceiptLog generate logs for Issuance debt action
func (action *Action) GetDebtReceiptLog(issuance *pty.Issuance, debtRecord *pty.DebtRecord) *types.ReceiptLog {
log := &types.ReceiptLog{}
log.Ty = pty.TyLogIssuanceDebt
c := &pty.ReceiptIssuance{}
c.IssuanceId = issuance.IssuanceId
c.AccountAddr = action.fromaddr
c.DebtId = debtRecord.DebtId
c.Status = debtRecord.Status
log.Log = types.Encode(c)
return log
}
// GetRepayReceiptLog generate logs for Issuance Repay action
func (action *Action) GetRepayReceiptLog(issuance *pty.Issuance, debtRecord *pty.DebtRecord) *types.ReceiptLog {
log := &types.ReceiptLog{}
log.Ty = pty.TyLogIssuanceRepay
c := &pty.ReceiptIssuance{}
c.IssuanceId = issuance.IssuanceId
c.AccountAddr = action.fromaddr
c.DebtId = debtRecord.DebtId
c.Status = debtRecord.Status
log.Log = types.Encode(c)
return log
}
// GetFeedReceiptLog generate logs for Issuance price feed action
func (action *Action) GetFeedReceiptLog(issuance *pty.Issuance, debtRecord *pty.DebtRecord) *types.ReceiptLog {
log := &types.ReceiptLog{}
log.Ty = pty.TyLogIssuanceFeed
c := &pty.ReceiptIssuance{}
c.IssuanceId = issuance.IssuanceId
c.AccountAddr = debtRecord.AccountAddr
c.DebtId = debtRecord.DebtId
c.Status = debtRecord.Status
log.Log = types.Encode(c)
return log
}
// GetCloseReceiptLog generate logs for Issuance close action
func (action *Action) GetCloseReceiptLog(issuance *pty.Issuance) *types.ReceiptLog {
log := &types.ReceiptLog{}
log.Ty = pty.TyLogIssuanceClose
c := &pty.ReceiptIssuance{}
c.IssuanceId = issuance.IssuanceId
c.Status = issuance.Status
log.Log = types.Encode(c)
return log
}
// GetIndex returns index in block
func (action *Action) GetIndex() int64 {
return action.height*types.MaxTxsPerBlock + int64(action.index)
}
func getLatestLiquidationPrice(issu *pty.Issuance) int64 {
var latest int64
for _, collRecord := range issu.DebtRecords {
if collRecord.LiquidationPrice > latest {
latest = collRecord.LiquidationPrice
}
}
return latest
}
func getLatestExpireTime(issu *pty.Issuance) int64 {
var latest int64 = 0x7fffffffffffffff
for _, collRecord := range issu.DebtRecords {
if collRecord.ExpireTime < latest {
latest = collRecord.ExpireTime
}
}
return latest
}
// IssuanceConfig 设置全局借贷参数(管理员权限)
func (action *Action) IssuanceManage(manage *pty.IssuanceManage) (*types.Receipt, error) {
var kv []*types.KeyValue
var receipt *types.Receipt
// 是否配置管理用户
if !isRightAddr(pty.ManageKey, action.fromaddr, action.db) {
clog.Error("IssuanceManage", "addr", action.fromaddr, "error", "Address has no permission to config")
return nil, pty.ErrPermissionDeny
}
// 添加大户地址
var item types.ConfigItem
data, err := action.db.Get(AddrKey())
if err != nil {
if err != types.ErrNotFound {
clog.Error("IssuanceManage", "error", err)
return nil, err
}
emptyValue := &types.ArrayConfig{Value: make([]string, 0)}
arr := types.ConfigItem_Arr{Arr: emptyValue}
item.Value = &arr
item.GetArr().Value = append(item.GetArr().Value, manage.SuperAddrs...)
value := types.Encode(&item)
action.db.Set(AddrKey(), value)
kv = append(kv, &types.KeyValue{Key: AddrKey(), Value: value})
} else {
err = types.Decode(data, &item)
if err != nil {
clog.Debug("IssuanceManage", "decode", err)
return nil, err
}
item.GetArr().Value = append(item.GetArr().Value, manage.SuperAddrs...)
value := types.Encode(&item)
action.db.Set(AddrKey(), value)
kv = append(kv, &types.KeyValue{Key: AddrKey(), Value: value})
}
receipt = &types.Receipt{Ty: types.ExecOk, KV: kv, Logs: nil}
return receipt, nil
}
func (action *Action) getSuperAddr() []string {
data, err := action.db.Get(AddrKey())
if err != nil {
clog.Error("getSuperAddr", "error", err)
return nil
}
var addrStore pty.IssuanceManage
err = types.Decode(data, &addrStore)
if err != nil {
clog.Debug("getSuperAddr", "decode", err)
return nil
}
return addrStore.SuperAddrs
}
// IssuanceCreate 创建借贷,持有一定数量ccny的用户可创建借贷,提供给其他用户借贷
func (action *Action) IssuanceCreate(create *pty.IssuanceCreate) (*types.Receipt, error) {
var logs []*types.ReceiptLog
var kv []*types.KeyValue
var receipt *types.Receipt
// 是否配置管理用户
if !isRightAddr(pty.ManageKey, action.fromaddr, action.db) {
clog.Error("IssuanceCreate", "addr", action.fromaddr, "error", "Address has no permission to create")
return nil, pty.ErrPermissionDeny
}
// 参数检查
if create.GetTotalBalance() <= 0 {
clog.Error("IssuanceCreate", "addr", action.fromaddr, "execaddr", action.execaddr, "total balance", create.GetTotalBalance(), "error", types.ErrAmount)
return nil, types.ErrAmount
}
if create.DebtCeiling < 0 || create.LiquidationRatio < 0 || create.Period < 0 {
clog.Error("IssuanceCreate", "addr", action.fromaddr, "execaddr", action.execaddr, "error", types.ErrInvalidParam)
return nil, types.ErrInvalidParam
}
// 检查ccny余额
if !action.CheckExecTokenAccount(action.fromaddr, create.TotalBalance, false) {
return nil, types.ErrInsufficientBalance
}
// 查找ID是否重复
issuanceID := common.ToHex(action.txhash)
_, err := queryIssuanceByID(action.db, issuanceID)
if err != types.ErrNotFound {
clog.Error("IssuanceCreate", "IssuanceCreate repeated", issuanceID)
return nil, pty.ErrIssuanceRepeatHash
}
// 冻结ccny
receipt, err = action.tokenAccount.ExecFrozen(action.fromaddr, action.execaddr, create.TotalBalance)
if err != nil {
clog.Error("IssuanceCreate.Frozen", "addr", action.fromaddr, "execaddr", action.execaddr, "amount", create.TotalBalance)
return nil, err
}
logs = append(logs, receipt.Logs...)
kv = append(kv, receipt.KV...)
// 构造coll结构
issu := &IssuanceDB{}
issu.IssuanceId = issuanceID
issu.TotalBalance = create.TotalBalance
if create.LiquidationRatio != 0 {
issu.LiquidationRatio = create.LiquidationRatio
} else {
issu.LiquidationRatio = DefaultLiquidationRatio
}
if create.DebtCeiling != 0 {
issu.DebtCeiling = create.DebtCeiling
} else {
issu.DebtCeiling = DefaultDebtCeiling
}
if create.Period != 0 {
issu.Period = create.Period
} else {
issu.Period = DefaultPeriod
}
issu.Balance = create.TotalBalance
issu.CreateTime = action.blocktime
issu.IssuerAddr = action.fromaddr
issu.Status = pty.IssuanceActionCreate
clog.Debug("IssuanceCreate created", "IssuanceID", issuanceID, "TotalBalance", issu.TotalBalance)
// 保存
issu.Save(action.db)
kv = append(kv, issu.GetKVSet()...)
receiptLog := action.GetCreateReceiptLog(&issu.Issuance)
logs = append(logs, receiptLog)
receipt = &types.Receipt{Ty: types.ExecOk, KV: kv, Logs: logs}
return receipt, nil
}
// 根据最近抵押物价格计算需要冻结的BTY数量
func getBtyNumToFrozen(value int64, price int64, ratio int64) (int64, error) {
if price == 0 {
clog.Error("Bty price should greate to 0")
return 0, pty.ErrPriceInvalid
}
btyValue := (value * 1e4) / (price * ratio)
return btyValue * 1e4, nil
}
// 获取最近抵押物价格
func getLatestPrice(db dbm.KV) (int64, error) {
data, err := db.Get(PriceKey())
if err != nil {
clog.Error("getLatestPrice", "get", err)
return -1, err
}
var price pty.IssuanceAssetPriceRecord
//decode
err = types.Decode(data, &price)
if err != nil {
clog.Error("getLatestPrice", "decode", err)
return -1, err
}
return price.BtyPrice, nil
}
// CheckExecAccountBalance 检查账户抵押物余额
func (action *Action) CheckExecAccountBalance(fromAddr string, ToFrozen, ToActive int64) bool {
acc := action.coinsAccount.LoadExecAccount(fromAddr, action.execaddr)
if acc.GetBalance() >= ToFrozen && acc.GetFrozen() >= ToActive {
return true
}
return false
}
// CheckExecAccount 检查账户token余额
func (action *Action) CheckExecTokenAccount(addr string, amount int64, isFrozen bool) bool {
acc := action.tokenAccount.LoadExecAccount(addr, action.execaddr)
if isFrozen {
if acc.GetFrozen() >= amount {
return true
}
} else {
if acc.GetBalance() >= amount {
return true
}
}
return false
}
// IssuanceDebt 大户质押bty借出ccny
func (action *Action) IssuanceDebt(debt *pty.IssuanceDebt) (*types.Receipt, error) {
var logs []*types.ReceiptLog
var kv []*types.KeyValue
if !isSuperAddr(action.fromaddr, action.db) {
clog.Error("IssuanceDebt", "error", "IssuanceDebt need super address")
return nil, pty.ErrPermissionDeny
}
// 查找对应的借贷ID
issuance, err := queryIssuanceByID(action.db, debt.IssuanceId)
if err != nil {
clog.Error("IssuanceDebt", "IssuanceId", debt.IssuanceId, "error", err)
return nil, err
}
// 状态检查
if issuance.Status == pty.IssuanceStatusClose {
clog.Error("IssuanceDebt", "CollID", issuance.IssuanceId, "addr", action.fromaddr, "execaddr", action.execaddr, "status", issuance.Status, "error", pty.ErrIssuanceStatus)
return nil, pty.ErrIssuanceStatus
}
issu := &IssuanceDB{*issuance}
// 借贷金额检查
if debt.GetValue() <= 0 {
clog.Error("IssuanceDebt", "CollID", issu.IssuanceId, "addr", action.fromaddr, "execaddr", action.execaddr, "debt value", debt.GetValue(), "error", types.ErrInvalidParam)
return nil, types.ErrInvalidParam
}
// 借贷金额不超过个人限额
userBalance, _ := queryIssuanceUserBalance(action.db, action.localDB, action.fromaddr)
if debt.GetValue()+userBalance > issu.DebtCeiling {
clog.Error("IssuanceDebt", "CollID", issu.IssuanceId, "addr", action.fromaddr, "execaddr", action.execaddr,
"debt value", debt.GetValue(), "current balance", userBalance, "error", pty.ErrIssuanceExceedDebtCeiling)
return nil, pty.ErrIssuanceExceedDebtCeiling
}
// 借贷金额不超过当前可借贷金额
if debt.GetValue() > issu.Balance {
clog.Error("IssuanceDebt", "CollID", issu.IssuanceId, "addr", action.fromaddr, "execaddr", action.execaddr, "debt value", debt.GetValue(), "error", pty.ErrIssuanceLowBalance)
return nil, pty.ErrIssuanceLowBalance
}
clog.Debug("IssuanceDebt", "value", debt.GetValue())
// 获取抵押物价格
lastPrice, err := getLatestPrice(action.db)
if err != nil {
clog.Error("IssuanceDebt.getLatestPrice", "CollID", issu.IssuanceId, "addr", action.fromaddr, "execaddr", action.execaddr, "error", err)
return nil, err
}
// 根据价格和需要借贷的金额,计算需要质押的抵押物数量
btyFrozen, err := getBtyNumToFrozen(debt.Value, lastPrice, issu.LiquidationRatio)
if err != nil {
clog.Error("IssuanceDebt.getBtyNumToFrozen", "CollID", issu.IssuanceId, "addr", action.fromaddr, "execaddr", action.execaddr, "error", err)
return nil, err
}
// 检查抵押物账户余额
if !action.CheckExecAccountBalance(action.fromaddr, btyFrozen, 0) {
clog.Error("IssuanceDebt.CheckExecAccountBalance", "CollID", issu.IssuanceId, "addr", action.fromaddr, "execaddr", action.execaddr, "btyFrozen", btyFrozen, "error", types.ErrNoBalance)
return nil, types.ErrNoBalance
}
// 抵押物转账
receipt, err := action.coinsAccount.ExecTransfer(action.fromaddr, issu.IssuerAddr, action.execaddr, btyFrozen)
if err != nil {
clog.Error("IssuanceDebt.ExecTransfer", "addr", action.fromaddr, "execaddr", action.execaddr, "amount", btyFrozen)
return nil, err
}
logs = append(logs, receipt.Logs...)
kv = append(kv, receipt.KV...)
// 抵押物冻结
receipt, err = action.coinsAccount.ExecFrozen(issu.IssuerAddr, action.execaddr, btyFrozen)
if err != nil {
clog.Error("IssuanceDebt.Frozen", "addr", issu.IssuerAddr, "execaddr", action.execaddr, "amount", btyFrozen)
return nil, err
}
logs = append(logs, receipt.Logs...)
kv = append(kv, receipt.KV...)
// 借出ccny
receipt, err = action.tokenAccount.ExecTransferFrozen(issu.IssuerAddr, action.fromaddr, action.execaddr, debt.Value)
if err != nil {
clog.Error("IssuanceDebt.ExecTokenTransfer", "addr", action.fromaddr, "execaddr", action.execaddr, "amount", debt.Value)
return nil, err
}
logs = append(logs, receipt.Logs...)
kv = append(kv, receipt.KV...)
// 构造借出记录
debtRecord := &pty.DebtRecord{}
debtRecord.AccountAddr = action.fromaddr
debtRecord.DebtId = common.ToHex(action.txhash)
debtRecord.IssuId = issu.IssuanceId
debtRecord.CollateralValue = btyFrozen
debtRecord.StartTime = action.blocktime
debtRecord.CollateralPrice = lastPrice
debtRecord.DebtValue = debt.Value
debtRecord.LiquidationPrice = (issu.LiquidationRatio * lastPrice * pty.IssuancePreLiquidationRatio) / 1e8
debtRecord.Status = pty.IssuanceUserStatusCreate
debtRecord.ExpireTime = action.blocktime + issu.Period
// 记录当前借贷的最高自动清算价格
if issu.LatestLiquidationPrice < debtRecord.LiquidationPrice {
issu.LatestLiquidationPrice = debtRecord.LiquidationPrice
}
// 保存
issu.DebtRecords = append(issu.DebtRecords, debtRecord)
issu.CollateralValue += btyFrozen
issu.DebtValue += debt.Value
issu.Balance -= debt.Value
issu.LatestExpireTime = getLatestExpireTime(&issu.Issuance)
issu.Save(action.db)
kv = append(kv, issu.GetKVSet()...)
receiptLog := action.GetDebtReceiptLog(&issu.Issuance, debtRecord)
logs = append(logs, receiptLog)
receipt = &types.Receipt{Ty: types.ExecOk, KV: kv, Logs: logs}
return receipt, nil
}
// IssuanceRepay 用户主动清算
func (action *Action) IssuanceRepay(repay *pty.IssuanceRepay) (*types.Receipt, error) {
var logs []*types.ReceiptLog
var kv []*types.KeyValue
var receipt *types.Receipt
// 找到相应的借贷
issuance, err := queryIssuanceByID(action.db, repay.IssuanceId)
if err != nil {
clog.Error("IssuanceRepay", "CollID", repay.IssuanceId, "error", err)
return nil, err
}
issu := &IssuanceDB{*issuance}
// 状态检查
if issu.Status != pty.IssuanceStatusCreated {
clog.Error("IssuanceRepay", "CollID", repay.IssuanceId, "addr", action.fromaddr, "execaddr", action.execaddr, "error", "status error", "Status", issu.Status)
return nil, pty.ErrIssuanceStatus
}
// 查找借出记录
var debtRecord *pty.DebtRecord
var index int
for i, record := range issu.DebtRecords {
if record.DebtId == repay.DebtId {
debtRecord = record
index = i
break
}
}
if debtRecord == nil {
clog.Error("IssuanceRepay", "CollID", repay.IssuanceId, "addr", action.fromaddr, "execaddr", action.execaddr, "error", "Can not find debt record")
return nil, pty.ErrRecordNotExist
}
// 检查
if !action.CheckExecTokenAccount(action.fromaddr, debtRecord.DebtValue, false) {
clog.Error("IssuanceRepay", "CollID", issu.IssuanceId, "addr", action.fromaddr, "execaddr", action.execaddr, "error", types.ErrInsufficientBalance)
return nil, types.ErrNoBalance
}
// ccny转移
receipt, err = action.tokenAccount.ExecTransfer(action.fromaddr, issu.IssuerAddr, action.execaddr, debtRecord.DebtValue)
if err != nil {
clog.Error("IssuanceRepay.ExecTokenTransfer", "addr", action.fromaddr, "execaddr", action.execaddr, "amount", debtRecord.DebtValue)
return nil, err
}
logs = append(logs, receipt.Logs...)
kv = append(kv, receipt.KV...)
// 冻结ccny
receipt, err = action.tokenAccount.ExecFrozen(issu.IssuerAddr, action.execaddr, debtRecord.DebtValue)
if err != nil {
clog.Error("IssuanceCreate.Frozen", "addr", action.fromaddr, "execaddr", action.execaddr, "amount", debtRecord.DebtValue)
return nil, err
}
logs = append(logs, receipt.Logs...)
kv = append(kv, receipt.KV...)
// 抵押物归还
receipt, err = action.coinsAccount.ExecTransferFrozen(issu.IssuerAddr, action.fromaddr, action.execaddr, debtRecord.CollateralValue)
if err != nil {
clog.Error("IssuanceRepay.ExecTransferFrozen", "addr", issu.IssuerAddr, "execaddr", action.execaddr, "amount", debtRecord.CollateralValue)
return nil, err
}
logs = append(logs, receipt.Logs...)
kv = append(kv, receipt.KV...)
// 借贷记录关闭
debtRecord.PreStatus = debtRecord.Status
debtRecord.Status = pty.IssuanceUserStatusClose
// 保存
issu.Balance += debtRecord.DebtValue
issu.CollateralValue -= debtRecord.CollateralValue
issu.DebtValue -= debtRecord.DebtValue
issu.DebtRecords = append(issu.DebtRecords[:index], issu.DebtRecords[index+1:]...)
issu.InvalidRecords = append(issu.InvalidRecords, debtRecord)
issu.LatestLiquidationPrice = getLatestLiquidationPrice(&issu.Issuance)
issu.LatestExpireTime = getLatestExpireTime(&issu.Issuance)
issu.Save(action.db)
kv = append(kv, issu.GetKVSet()...)
receiptLog := action.GetRepayReceiptLog(&issu.Issuance, debtRecord)
logs = append(logs, receiptLog)
receipt = &types.Receipt{Ty: types.ExecOk, KV: kv, Logs: logs}
return receipt, nil
}
// 系统清算
func (action *Action) systemLiquidation(issu *pty.Issuance, price int64) (*types.Receipt, error) {
var logs []*types.ReceiptLog
var kv []*types.KeyValue
for index, debtRecord := range issu.DebtRecords {
if (debtRecord.LiquidationPrice*PriceWarningRate)/1e4 < price {
// 价格恢复,告警记录恢复
if debtRecord.Status == pty.IssuanceUserStatusWarning {
debtRecord.PreStatus = debtRecord.Status
debtRecord.Status = pty.IssuanceUserStatusCreate
log := action.GetFeedReceiptLog(issu, debtRecord)
logs = append(logs, log)
}
continue
}
// 价格低于清算线,记录清算
if debtRecord.LiquidationPrice >= price {
getGuarantorAddr, err := getGuarantorAddr(action.db)
if err != nil {
if err != nil {
clog.Error("systemLiquidation", "getGuarantorAddr", err)
continue
}
}
// 抵押物转移
receipt, err := action.coinsAccount.ExecTransferFrozen(issu.IssuerAddr, getGuarantorAddr, action.execaddr, debtRecord.CollateralValue)
if err != nil {
clog.Error("systemLiquidation", "addr", action.fromaddr, "execaddr", action.execaddr, "amount", debtRecord.CollateralValue, "error", err)
continue
}
logs = append(logs, receipt.Logs...)
kv = append(kv, receipt.KV...)
// 借贷记录清算
debtRecord.LiquidateTime = action.blocktime
debtRecord.PreStatus = debtRecord.Status
debtRecord.Status = pty.IssuanceUserStatusSystemLiquidate
issu.InvalidRecords = append(issu.InvalidRecords, debtRecord)
issu.DebtRecords = append(issu.DebtRecords[:index], issu.DebtRecords[index+1:]...)
log := action.GetFeedReceiptLog(issu, debtRecord)
logs = append(logs, log)
continue
}
// 价格高于清算线,且还不处于告警状态,记录告警
if debtRecord.Status != pty.IssuanceUserStatusWarning {
debtRecord.PreStatus = debtRecord.Status
debtRecord.Status = pty.IssuanceUserStatusWarning
log := action.GetFeedReceiptLog(issu, debtRecord)
logs = append(logs, log)
}
}
// 保存
issu.LatestLiquidationPrice = getLatestLiquidationPrice(issu)
issu.LatestExpireTime = getLatestExpireTime(issu)
collDB := &IssuanceDB{*issu}
collDB.Save(action.db)
kv = append(kv, collDB.GetKVSet()...)
receipt := &types.Receipt{Ty: types.ExecOk, KV: kv, Logs: logs}
return receipt, nil
}
// 超时清算
func (action *Action) expireLiquidation(issu *pty.Issuance) (*types.Receipt, error) {
var logs []*types.ReceiptLog
var kv []*types.KeyValue
for index, debtRecord := range issu.DebtRecords {
if debtRecord.ExpireTime-ExpireWarningTime > action.blocktime {
continue
}
// 超过超时时间,记录清算
if debtRecord.ExpireTime <= action.blocktime {
getGuarantorAddr, err := getGuarantorAddr(action.db)
if err != nil {
if err != nil {
clog.Error("systemLiquidation", "getGuarantorAddr", err)
continue
}
}
// 抵押物转移
receipt, err := action.coinsAccount.ExecTransferFrozen(issu.IssuerAddr, getGuarantorAddr, action.execaddr, debtRecord.CollateralValue)
if err != nil {
clog.Error("systemLiquidation", "addr", action.fromaddr, "execaddr", action.execaddr, "amount", debtRecord.CollateralValue, "error", err)
continue
}
logs = append(logs, receipt.Logs...)
kv = append(kv, receipt.KV...)
// 借贷记录清算
debtRecord.LiquidateTime = action.blocktime
debtRecord.PreStatus = debtRecord.Status
debtRecord.Status = pty.IssuanceUserStatusExpireLiquidate
issu.InvalidRecords = append(issu.InvalidRecords, debtRecord)
issu.DebtRecords = append(issu.DebtRecords[:index], issu.DebtRecords[index+1:]...)
log := action.GetFeedReceiptLog(issu, debtRecord)
logs = append(logs, log)
continue
}
// 还没记录超时告警,记录告警
if debtRecord.Status != pty.IssuanceUserStatusExpire {
debtRecord.PreStatus = debtRecord.Status
debtRecord.Status = pty.IssuanceUserStatusExpire
log := action.GetFeedReceiptLog(issu, debtRecord)
logs = append(logs, log)
}
}
// 保存
issu.LatestLiquidationPrice = getLatestLiquidationPrice(issu)
issu.LatestExpireTime = getLatestExpireTime(issu)
collDB := &IssuanceDB{*issu}
collDB.Save(action.db)
kv = append(kv, collDB.GetKVSet()...)
receipt := &types.Receipt{Ty: types.ExecOk, KV: kv, Logs: logs}
return receipt, nil
}
// 价格计算策略
func pricePolicy(feed *pty.IssuanceFeed) int64 {
var totalPrice int64
var totalVolume int64
for _, volume := range feed.Volume {
totalVolume += volume
}
if totalVolume == 0 {
clog.Error("issuance price feed volume empty")
return 0
}
for i, price := range feed.Price {
totalPrice += (price * feed.Volume[i]) / totalVolume
}
return totalPrice
}
// IssuanceFeed 喂价
func (action *Action) IssuanceFeed(feed *pty.IssuanceFeed) (*types.Receipt, error) {
var logs []*types.ReceiptLog
var kv []*types.KeyValue
if feed == nil || len(feed.Price) == 0 || len(feed.Price) != len(feed.Volume) {
clog.Error("IssuancePriceFeed", types.ErrInvalidParam)
return nil, types.ErrInvalidParam
}
// 是否后台管理用户
if !isRightAddr(pty.PriceFeedKey, action.fromaddr, action.db) {
clog.Error("IssuancePriceFeed", "addr", action.fromaddr, "error", "Address has no permission to feed price")
return nil, pty.ErrPermissionDeny
}
price := pricePolicy(feed)
if price <= 0 {
clog.Error("IssuancePriceFeed", "price", price, "error", pty.ErrPriceInvalid)
return nil, pty.ErrPriceInvalid
}
ids, err := queryIssuanceByStatus(action.localDB, pty.IssuanceStatusCreated, "")
if err != nil {
clog.Debug("IssuancePriceFeed", "get issuance record error", err)
}
for _, collID := range ids {
issu, err := queryIssuanceByID(action.db, collID)
if err != nil {
clog.Error("IssuancePriceFeed", "Issuance ID", issu.IssuanceId, "get issuance record by id error", err)
continue
}
// 超时清算判断
if issu.LatestExpireTime-ExpireWarningTime <= action.blocktime {
receipt, err := action.expireLiquidation(issu)
if err != nil {
clog.Error("IssuancePriceFeed", "Issuance ID", issu.IssuanceId, "expire liquidation error", err)
continue
}
logs = append(logs, receipt.Logs...)
kv = append(kv, receipt.KV...)
}
// 系统清算判断
receipt, err := action.systemLiquidation(issu, price)
if err != nil {
clog.Error("IssuancePriceFeed", "Issuance ID", issu.IssuanceId, "system liquidation error", err)
continue
}
logs = append(logs, receipt.Logs...)
kv = append(kv, receipt.KV...)
}
var priceRecord pty.IssuanceAssetPriceRecord
priceRecord.BtyPrice = price
priceRecord.RecordTime = action.blocktime
// 最近喂价记录
pricekv := &types.KeyValue{Key: PriceKey(), Value: types.Encode(&priceRecord)}
action.db.Set(pricekv.Key, pricekv.Value)
kv = append(kv, pricekv)
receipt := &types.Receipt{Ty: types.ExecOk, KV: kv, Logs: logs}
return receipt, nil
}
// IssuanceClose 终止借贷
func (action *Action) IssuanceClose(close *pty.IssuanceClose) (*types.Receipt, error) {
var logs []*types.ReceiptLog
var kv []*types.KeyValue
var receipt *types.Receipt
issuance, err := queryIssuanceByID(action.db, close.IssuanceId)
if err != nil {
clog.Error("IssuanceClose", "IssuanceId", close.IssuanceId, "error", err)
return nil, err
}
if !isRightAddr(pty.ManageKey, action.fromaddr, action.db) {
clog.Error("IssuanceClose", "addr", action.fromaddr, "error", "Address has no permission to close")
return nil, pty.ErrPermissionDeny
}
for _, debtRecord := range issuance.DebtRecords {
if debtRecord.Status != pty.IssuanceUserStatusClose {
clog.Error("IssuanceClose", "IssuanceId", close.IssuanceId, "addr", action.fromaddr, "execaddr", action.execaddr, "error", pty.ErrIssuanceRecordNotEmpty)
return nil, pty.ErrIssuanceRecordNotEmpty
}
}
// 解冻ccny
receipt, err = action.tokenAccount.ExecActive(action.fromaddr, action.execaddr, issuance.Balance)
if err != nil {
clog.Error("IssuanceClose.ExecActive", "addr", action.fromaddr, "execaddr", action.execaddr, "amount", issuance.Balance, "error", err)
return nil, err
}
logs = append(logs, receipt.Logs...)
kv = append(kv, receipt.KV...)
clog.Debug("IssuanceClose", "ID", close.IssuanceId)
issu := &IssuanceDB{*issuance}
issu.Status = pty.IssuanceStatusClose
issu.Save(action.db)
kv = append(kv, issu.GetKVSet()...)
receiptLog := action.GetCloseReceiptLog(&issu.Issuance)
logs = append(logs, receiptLog)
return &types.Receipt{Ty: types.ExecOk, KV: kv, Logs: logs}, nil
}
// 根据ID查找发行信息
func queryIssuanceByID(db dbm.KV, issuanceID string) (*pty.Issuance, error) {
data, err := db.Get(Key(issuanceID))
if err != nil {
return nil, err
}
var issu pty.Issuance
err = types.Decode(data, &issu)
if err != nil {
clog.Error("queryIssuanceByID", "decode", err)
return nil, err
}
return &issu, nil
}
// 根据发行状态查找发行ID
func queryIssuanceByStatus(localdb dbm.KVDB, status int32, issuanceID string) ([]string, error) {
query := pty.NewIssuanceTable(localdb).GetQuery(localdb)
var primary []byte
if len(issuanceID) > 0 {
primary = []byte(issuanceID)
}
var data = &pty.ReceiptIssuanceID{
IssuanceId: issuanceID,
Status: status,
}
rows, err := query.List("status", data, primary, DefaultCount, ListDESC)
if err != nil {
clog.Error("queryIssuanceByStatus.List", "error", err)
return nil, err
}
var ids []string
for _, row := range rows {
ids = append(ids, string(row.Primary))
}
return ids, nil
}
// 精确查找发行记录
func queryIssuanceRecordByID(db dbm.KV, issuanceID string, debtID string) (*pty.DebtRecord, error) {
issu, err := queryIssuanceByID(db, issuanceID)
if err != nil {
clog.Error("queryIssuanceRecordByID", "error", err)
return nil, err
}
for _, record := range issu.DebtRecords {
if record.DebtId == debtID {
return record, nil
}
}
for _, record := range issu.InvalidRecords {
if record.DebtId == debtID {
return record, nil
}
}
return nil, types.ErrNotFound
}
// 根据发行状态查找
func queryIssuanceRecordsByStatus(db dbm.KV, localdb dbm.KVDB, status int32, debtID string) ([]*pty.DebtRecord, error) {
query := pty.NewRecordTable(localdb).GetQuery(localdb)
var primary []byte
if len(debtID) > 0 {
primary = []byte(debtID)
}
var data = &pty.ReceiptIssuance{
Status: status,
}
rows, err := query.List("status", data, primary, DefaultCount, ListDESC)
if err != nil {
clog.Error("queryIssuanceRecordsByStatus.List", "index", "status", "error", err)
return nil, err
}
var records []*pty.DebtRecord
for _, row := range rows {
record, err := queryIssuanceRecordByID(db, row.Data.(*pty.ReceiptIssuance).IssuanceId, row.Data.(*pty.ReceiptIssuance).DebtId)
if err != nil {
clog.Error("queryIssuanceRecordsByStatus", "decode", err)
continue
}
records = append(records, record)
}
return records, nil
}
// 根据用户地址查找
func queryIssuanceRecordByAddr(db dbm.KV, localdb dbm.KVDB, addr string, status int32, debtID string) ([]*pty.DebtRecord, error) {
query := pty.NewRecordTable(localdb).GetQuery(localdb)
var primary []byte
if len(debtID) > 0 {
primary = []byte(debtID)
}
var data = &pty.ReceiptIssuance{
AccountAddr: addr,
Status: status,
}
var rows []*table.Row
var err error
if status == 0 {
rows, err = query.List("addr", data, primary, DefaultCount, ListDESC)
if err != nil {
clog.Error("queryIssuanceRecordByAddr.List", "index", "addr", "error", err)
return nil, err
}
} else {
rows, err = query.List("addr_status", data, primary, DefaultCount, ListDESC)
if err != nil {
clog.Error("queryIssuanceRecordByAddr.List", "index", "addr_status", "error", err)
return nil, err
}
}
var records []*pty.DebtRecord
for _, row := range rows {
record, err := queryIssuanceRecordByID(db, row.Data.(*pty.ReceiptIssuance).IssuanceId, row.Data.(*pty.ReceiptIssuance).DebtId)
if err != nil {
clog.Error("queryIssuanceRecordByAddr", "decode", err)
continue
}
records = append(records, record)
}
return records, nil
}
func queryIssuanceUserBalanceStatus(db dbm.KV, localdb dbm.KVDB, addr string, status int32) (int64, error) {
var totalBalance int64
query := pty.NewRecordTable(localdb).GetQuery(localdb)
var primary []byte
var data = &pty.ReceiptIssuance{
AccountAddr: addr,
Status: status,
}
var rows []*table.Row
var err error
for {
rows, err = query.List("addr_status", data, primary, DefaultCount, ListDESC)
if err != nil {
return -1, err
}
for _, row := range rows {
record, err := queryIssuanceRecordByID(db, row.Data.(*pty.ReceiptIssuance).IssuanceId, row.Data.(*pty.ReceiptIssuance).DebtId)
if err != nil {
continue
}
totalBalance += record.DebtValue
}
if len(rows) < int(DefaultCount) {
break
}
primary = []byte(rows[DefaultCount-1].Data.(*pty.ReceiptIssuance).DebtId)
}
return totalBalance, nil
}
func queryIssuanceUserBalance(db dbm.KV, localdb dbm.KVDB, addr string) (int64, error) {
var totalBalance int64
balance, err := queryIssuanceUserBalanceStatus(db, localdb, addr, pty.IssuanceUserStatusCreate)
if err != nil {
if err != types.ErrNotFound {
clog.Error("queryIssuanceUserBalance", "err", err)
}
} else {
totalBalance += balance
}
balance, err = queryIssuanceUserBalanceStatus(db, localdb, addr, pty.IssuanceUserStatusWarning)
if err != nil {
if err != types.ErrNotFound {
clog.Error("queryIssuanceUserBalance", "err", err)
}
} else {
totalBalance += balance
}
balance, err = queryIssuanceUserBalanceStatus(db, localdb, addr, pty.IssuanceUserStatusExpire)
if err != nil {
if err != types.ErrNotFound {
clog.Error("queryIssuanceUserBalance", "err", err)
}
} else {
totalBalance += balance
}
return totalBalance, nil
}
// Copyright Fuzamei Corp. 2018 All Rights Reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package executor
import (
"github.com/33cn/chain33/types"
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
}
// Code generated by protoc-gen-go. DO NOT EDIT.
// source: issuance.proto
package types
import (
fmt "fmt"
proto "github.com/golang/protobuf/proto"
math "math"
)
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
// 发行信息
type Issuance struct {
IssuanceId string `protobuf:"bytes,1,opt,name=issuanceId,proto3" json:"issuanceId,omitempty"`
TotalBalance int64 `protobuf:"varint,2,opt,name=totalBalance,proto3" json:"totalBalance,omitempty"`
DebtCeiling int64 `protobuf:"varint,3,opt,name=debtCeiling,proto3" json:"debtCeiling,omitempty"`
LiquidationRatio int64 `protobuf:"varint,4,opt,name=liquidationRatio,proto3" json:"liquidationRatio,omitempty"`
CollateralValue int64 `protobuf:"varint,5,opt,name=collateralValue,proto3" json:"collateralValue,omitempty"`
DebtValue int64 `protobuf:"varint,6,opt,name=debtValue,proto3" json:"debtValue,omitempty"`
DebtRecords []*DebtRecord `protobuf:"bytes,7,rep,name=debtRecords,proto3" json:"debtRecords,omitempty"`
InvalidRecords []*DebtRecord `protobuf:"bytes,8,rep,name=invalidRecords,proto3" json:"invalidRecords,omitempty"`
Status int32 `protobuf:"varint,9,opt,name=status,proto3" json:"status,omitempty"`
LatestLiquidationPrice int64 `protobuf:"varint,10,opt,name=latestLiquidationPrice,proto3" json:"latestLiquidationPrice,omitempty"`
Period int64 `protobuf:"varint,11,opt,name=period,proto3" json:"period,omitempty"`
LatestExpireTime int64 `protobuf:"varint,12,opt,name=latestExpireTime,proto3" json:"latestExpireTime,omitempty"`
CreateTime int64 `protobuf:"varint,13,opt,name=createTime,proto3" json:"createTime,omitempty"`
Balance int64 `protobuf:"varint,14,opt,name=balance,proto3" json:"balance,omitempty"`
IssuerAddr string `protobuf:"bytes,15,opt,name=issuerAddr,proto3" json:"issuerAddr,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *Issuance) Reset() { *m = Issuance{} }
func (m *Issuance) String() string { return proto.CompactTextString(m) }
func (*Issuance) ProtoMessage() {}
func (*Issuance) Descriptor() ([]byte, []int) {
return fileDescriptor_issuance_4d8bb77ed2bb92a1, []int{0}
}
func (m *Issuance) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_Issuance.Unmarshal(m, b)
}
func (m *Issuance) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_Issuance.Marshal(b, m, deterministic)
}
func (dst *Issuance) XXX_Merge(src proto.Message) {
xxx_messageInfo_Issuance.Merge(dst, src)
}
func (m *Issuance) XXX_Size() int {
return xxx_messageInfo_Issuance.Size(m)
}
func (m *Issuance) XXX_DiscardUnknown() {
xxx_messageInfo_Issuance.DiscardUnknown(m)
}
var xxx_messageInfo_Issuance proto.InternalMessageInfo
func (m *Issuance) GetIssuanceId() string {
if m != nil {
return m.IssuanceId
}
return ""
}
func (m *Issuance) GetTotalBalance() int64 {
if m != nil {
return m.TotalBalance
}
return 0
}
func (m *Issuance) GetDebtCeiling() int64 {
if m != nil {
return m.DebtCeiling
}
return 0
}
func (m *Issuance) GetLiquidationRatio() int64 {
if m != nil {
return m.LiquidationRatio
}
return 0
}
func (m *Issuance) GetCollateralValue() int64 {
if m != nil {
return m.CollateralValue
}
return 0
}
func (m *Issuance) GetDebtValue() int64 {
if m != nil {
return m.DebtValue
}
return 0
}
func (m *Issuance) GetDebtRecords() []*DebtRecord {
if m != nil {
return m.DebtRecords
}
return nil
}
func (m *Issuance) GetInvalidRecords() []*DebtRecord {
if m != nil {
return m.InvalidRecords
}
return nil
}
func (m *Issuance) GetStatus() int32 {
if m != nil {
return m.Status
}
return 0
}
func (m *Issuance) GetLatestLiquidationPrice() int64 {
if m != nil {
return m.LatestLiquidationPrice
}
return 0
}
func (m *Issuance) GetPeriod() int64 {
if m != nil {
return m.Period
}
return 0
}
func (m *Issuance) GetLatestExpireTime() int64 {
if m != nil {
return m.LatestExpireTime
}
return 0
}
func (m *Issuance) GetCreateTime() int64 {
if m != nil {
return m.CreateTime
}
return 0
}
func (m *Issuance) GetBalance() int64 {
if m != nil {
return m.Balance
}
return 0
}
func (m *Issuance) GetIssuerAddr() string {
if m != nil {
return m.IssuerAddr
}
return ""
}
// 抵押记录
type DebtRecord struct {
AccountAddr string `protobuf:"bytes,1,opt,name=accountAddr,proto3" json:"accountAddr,omitempty"`
StartTime int64 `protobuf:"varint,2,opt,name=startTime,proto3" json:"startTime,omitempty"`
CollateralValue int64 `protobuf:"varint,3,opt,name=collateralValue,proto3" json:"collateralValue,omitempty"`
CollateralPrice int64 `protobuf:"varint,4,opt,name=collateralPrice,proto3" json:"collateralPrice,omitempty"`
DebtValue int64 `protobuf:"varint,5,opt,name=debtValue,proto3" json:"debtValue,omitempty"`
LiquidationPrice int64 `protobuf:"varint,6,opt,name=liquidationPrice,proto3" json:"liquidationPrice,omitempty"`
Status int32 `protobuf:"varint,7,opt,name=status,proto3" json:"status,omitempty"`
LiquidateTime int64 `protobuf:"varint,8,opt,name=liquidateTime,proto3" json:"liquidateTime,omitempty"`
ExpireTime int64 `protobuf:"varint,9,opt,name=expireTime,proto3" json:"expireTime,omitempty"`
PreStatus int32 `protobuf:"varint,10,opt,name=preStatus,proto3" json:"preStatus,omitempty"`
DebtId string `protobuf:"bytes,11,opt,name=debtId,proto3" json:"debtId,omitempty"`
IssuId string `protobuf:"bytes,12,opt,name=issuId,proto3" json:"issuId,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *DebtRecord) Reset() { *m = DebtRecord{} }
func (m *DebtRecord) String() string { return proto.CompactTextString(m) }
func (*DebtRecord) ProtoMessage() {}
func (*DebtRecord) Descriptor() ([]byte, []int) {
return fileDescriptor_issuance_4d8bb77ed2bb92a1, []int{1}
}
func (m *DebtRecord) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_DebtRecord.Unmarshal(m, b)
}
func (m *DebtRecord) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_DebtRecord.Marshal(b, m, deterministic)
}
func (dst *DebtRecord) XXX_Merge(src proto.Message) {
xxx_messageInfo_DebtRecord.Merge(dst, src)
}
func (m *DebtRecord) XXX_Size() int {
return xxx_messageInfo_DebtRecord.Size(m)
}
func (m *DebtRecord) XXX_DiscardUnknown() {
xxx_messageInfo_DebtRecord.DiscardUnknown(m)
}
var xxx_messageInfo_DebtRecord proto.InternalMessageInfo
func (m *DebtRecord) GetAccountAddr() string {
if m != nil {
return m.AccountAddr
}
return ""
}
func (m *DebtRecord) GetStartTime() int64 {
if m != nil {
return m.StartTime
}
return 0
}
func (m *DebtRecord) GetCollateralValue() int64 {
if m != nil {
return m.CollateralValue
}
return 0
}
func (m *DebtRecord) GetCollateralPrice() int64 {
if m != nil {
return m.CollateralPrice
}
return 0
}
func (m *DebtRecord) GetDebtValue() int64 {
if m != nil {
return m.DebtValue
}
return 0
}
func (m *DebtRecord) GetLiquidationPrice() int64 {
if m != nil {
return m.LiquidationPrice
}
return 0
}
func (m *DebtRecord) GetStatus() int32 {
if m != nil {
return m.Status
}
return 0
}
func (m *DebtRecord) GetLiquidateTime() int64 {
if m != nil {
return m.LiquidateTime
}
return 0
}
func (m *DebtRecord) GetExpireTime() int64 {
if m != nil {
return m.ExpireTime
}
return 0
}
func (m *DebtRecord) GetPreStatus() int32 {
if m != nil {
return m.PreStatus
}
return 0
}
func (m *DebtRecord) GetDebtId() string {
if m != nil {
return m.DebtId
}
return ""
}
func (m *DebtRecord) GetIssuId() string {
if m != nil {
return m.IssuId
}
return ""
}
// 资产价格记录
type IssuanceAssetPriceRecord struct {
RecordTime int64 `protobuf:"varint,1,opt,name=recordTime,proto3" json:"recordTime,omitempty"`
BtyPrice int64 `protobuf:"varint,2,opt,name=btyPrice,proto3" json:"btyPrice,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *IssuanceAssetPriceRecord) Reset() { *m = IssuanceAssetPriceRecord{} }
func (m *IssuanceAssetPriceRecord) String() string { return proto.CompactTextString(m) }
func (*IssuanceAssetPriceRecord) ProtoMessage() {}
func (*IssuanceAssetPriceRecord) Descriptor() ([]byte, []int) {
return fileDescriptor_issuance_4d8bb77ed2bb92a1, []int{2}
}
func (m *IssuanceAssetPriceRecord) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_IssuanceAssetPriceRecord.Unmarshal(m, b)
}
func (m *IssuanceAssetPriceRecord) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_IssuanceAssetPriceRecord.Marshal(b, m, deterministic)
}
func (dst *IssuanceAssetPriceRecord) XXX_Merge(src proto.Message) {
xxx_messageInfo_IssuanceAssetPriceRecord.Merge(dst, src)
}
func (m *IssuanceAssetPriceRecord) XXX_Size() int {
return xxx_messageInfo_IssuanceAssetPriceRecord.Size(m)
}
func (m *IssuanceAssetPriceRecord) XXX_DiscardUnknown() {
xxx_messageInfo_IssuanceAssetPriceRecord.DiscardUnknown(m)
}
var xxx_messageInfo_IssuanceAssetPriceRecord proto.InternalMessageInfo
func (m *IssuanceAssetPriceRecord) GetRecordTime() int64 {
if m != nil {
return m.RecordTime
}
return 0
}
func (m *IssuanceAssetPriceRecord) GetBtyPrice() int64 {
if m != nil {
return m.BtyPrice
}
return 0
}
// action
type IssuanceAction struct {
// Types that are valid to be assigned to Value:
// *IssuanceAction_Create
// *IssuanceAction_Debt
// *IssuanceAction_Repay
// *IssuanceAction_Feed
// *IssuanceAction_Close
// *IssuanceAction_Manage
Value isIssuanceAction_Value `protobuf_oneof:"value"`
Ty int32 `protobuf:"varint,10,opt,name=ty,proto3" json:"ty,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *IssuanceAction) Reset() { *m = IssuanceAction{} }
func (m *IssuanceAction) String() string { return proto.CompactTextString(m) }
func (*IssuanceAction) ProtoMessage() {}
func (*IssuanceAction) Descriptor() ([]byte, []int) {
return fileDescriptor_issuance_4d8bb77ed2bb92a1, []int{3}
}
func (m *IssuanceAction) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_IssuanceAction.Unmarshal(m, b)
}
func (m *IssuanceAction) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_IssuanceAction.Marshal(b, m, deterministic)
}
func (dst *IssuanceAction) XXX_Merge(src proto.Message) {
xxx_messageInfo_IssuanceAction.Merge(dst, src)
}
func (m *IssuanceAction) XXX_Size() int {
return xxx_messageInfo_IssuanceAction.Size(m)
}
func (m *IssuanceAction) XXX_DiscardUnknown() {
xxx_messageInfo_IssuanceAction.DiscardUnknown(m)
}
var xxx_messageInfo_IssuanceAction proto.InternalMessageInfo
type isIssuanceAction_Value interface {
isIssuanceAction_Value()
}
type IssuanceAction_Create struct {
Create *IssuanceCreate `protobuf:"bytes,1,opt,name=create,proto3,oneof"`
}
type IssuanceAction_Debt struct {
Debt *IssuanceDebt `protobuf:"bytes,2,opt,name=debt,proto3,oneof"`
}
type IssuanceAction_Repay struct {
Repay *IssuanceRepay `protobuf:"bytes,3,opt,name=repay,proto3,oneof"`
}
type IssuanceAction_Feed struct {
Feed *IssuanceFeed `protobuf:"bytes,4,opt,name=feed,proto3,oneof"`
}
type IssuanceAction_Close struct {
Close *IssuanceClose `protobuf:"bytes,5,opt,name=close,proto3,oneof"`
}
type IssuanceAction_Manage struct {
Manage *IssuanceManage `protobuf:"bytes,6,opt,name=manage,proto3,oneof"`
}
func (*IssuanceAction_Create) isIssuanceAction_Value() {}
func (*IssuanceAction_Debt) isIssuanceAction_Value() {}
func (*IssuanceAction_Repay) isIssuanceAction_Value() {}
func (*IssuanceAction_Feed) isIssuanceAction_Value() {}
func (*IssuanceAction_Close) isIssuanceAction_Value() {}
func (*IssuanceAction_Manage) isIssuanceAction_Value() {}
func (m *IssuanceAction) GetValue() isIssuanceAction_Value {
if m != nil {
return m.Value
}
return nil
}
func (m *IssuanceAction) GetCreate() *IssuanceCreate {
if x, ok := m.GetValue().(*IssuanceAction_Create); ok {
return x.Create
}
return nil
}
func (m *IssuanceAction) GetDebt() *IssuanceDebt {
if x, ok := m.GetValue().(*IssuanceAction_Debt); ok {
return x.Debt
}
return nil
}
func (m *IssuanceAction) GetRepay() *IssuanceRepay {
if x, ok := m.GetValue().(*IssuanceAction_Repay); ok {
return x.Repay
}
return nil
}
func (m *IssuanceAction) GetFeed() *IssuanceFeed {
if x, ok := m.GetValue().(*IssuanceAction_Feed); ok {
return x.Feed
}
return nil
}
func (m *IssuanceAction) GetClose() *IssuanceClose {
if x, ok := m.GetValue().(*IssuanceAction_Close); ok {
return x.Close
}
return nil
}
func (m *IssuanceAction) GetManage() *IssuanceManage {
if x, ok := m.GetValue().(*IssuanceAction_Manage); ok {
return x.Manage
}
return nil
}
func (m *IssuanceAction) GetTy() int32 {
if m != nil {
return m.Ty
}
return 0
}
// XXX_OneofFuncs is for the internal use of the proto package.
func (*IssuanceAction) XXX_OneofFuncs() (func(msg proto.Message, b *proto.Buffer) error, func(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error), func(msg proto.Message) (n int), []interface{}) {
return _IssuanceAction_OneofMarshaler, _IssuanceAction_OneofUnmarshaler, _IssuanceAction_OneofSizer, []interface{}{
(*IssuanceAction_Create)(nil),
(*IssuanceAction_Debt)(nil),
(*IssuanceAction_Repay)(nil),
(*IssuanceAction_Feed)(nil),
(*IssuanceAction_Close)(nil),
(*IssuanceAction_Manage)(nil),
}
}
func _IssuanceAction_OneofMarshaler(msg proto.Message, b *proto.Buffer) error {
m := msg.(*IssuanceAction)
// value
switch x := m.Value.(type) {
case *IssuanceAction_Create:
b.EncodeVarint(1<<3 | proto.WireBytes)
if err := b.EncodeMessage(x.Create); err != nil {
return err
}
case *IssuanceAction_Debt:
b.EncodeVarint(2<<3 | proto.WireBytes)
if err := b.EncodeMessage(x.Debt); err != nil {
return err
}
case *IssuanceAction_Repay:
b.EncodeVarint(3<<3 | proto.WireBytes)
if err := b.EncodeMessage(x.Repay); err != nil {
return err
}
case *IssuanceAction_Feed:
b.EncodeVarint(4<<3 | proto.WireBytes)
if err := b.EncodeMessage(x.Feed); err != nil {
return err
}
case *IssuanceAction_Close:
b.EncodeVarint(5<<3 | proto.WireBytes)
if err := b.EncodeMessage(x.Close); err != nil {
return err
}
case *IssuanceAction_Manage:
b.EncodeVarint(6<<3 | proto.WireBytes)
if err := b.EncodeMessage(x.Manage); err != nil {
return err
}
case nil:
default:
return fmt.Errorf("IssuanceAction.Value has unexpected type %T", x)
}
return nil
}
func _IssuanceAction_OneofUnmarshaler(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error) {
m := msg.(*IssuanceAction)
switch tag {
case 1: // value.create
if wire != proto.WireBytes {
return true, proto.ErrInternalBadWireType
}
msg := new(IssuanceCreate)
err := b.DecodeMessage(msg)
m.Value = &IssuanceAction_Create{msg}
return true, err
case 2: // value.debt
if wire != proto.WireBytes {
return true, proto.ErrInternalBadWireType
}
msg := new(IssuanceDebt)
err := b.DecodeMessage(msg)
m.Value = &IssuanceAction_Debt{msg}
return true, err
case 3: // value.repay
if wire != proto.WireBytes {
return true, proto.ErrInternalBadWireType
}
msg := new(IssuanceRepay)
err := b.DecodeMessage(msg)
m.Value = &IssuanceAction_Repay{msg}
return true, err
case 4: // value.feed
if wire != proto.WireBytes {
return true, proto.ErrInternalBadWireType
}
msg := new(IssuanceFeed)
err := b.DecodeMessage(msg)
m.Value = &IssuanceAction_Feed{msg}
return true, err
case 5: // value.close
if wire != proto.WireBytes {
return true, proto.ErrInternalBadWireType
}
msg := new(IssuanceClose)
err := b.DecodeMessage(msg)
m.Value = &IssuanceAction_Close{msg}
return true, err
case 6: // value.manage
if wire != proto.WireBytes {
return true, proto.ErrInternalBadWireType
}
msg := new(IssuanceManage)
err := b.DecodeMessage(msg)
m.Value = &IssuanceAction_Manage{msg}
return true, err
default:
return false, nil
}
}
func _IssuanceAction_OneofSizer(msg proto.Message) (n int) {
m := msg.(*IssuanceAction)
// value
switch x := m.Value.(type) {
case *IssuanceAction_Create:
s := proto.Size(x.Create)
n += 1 // tag and wire
n += proto.SizeVarint(uint64(s))
n += s
case *IssuanceAction_Debt:
s := proto.Size(x.Debt)
n += 1 // tag and wire
n += proto.SizeVarint(uint64(s))
n += s
case *IssuanceAction_Repay:
s := proto.Size(x.Repay)
n += 1 // tag and wire
n += proto.SizeVarint(uint64(s))
n += s
case *IssuanceAction_Feed:
s := proto.Size(x.Feed)
n += 1 // tag and wire
n += proto.SizeVarint(uint64(s))
n += s
case *IssuanceAction_Close:
s := proto.Size(x.Close)
n += 1 // tag and wire
n += proto.SizeVarint(uint64(s))
n += s
case *IssuanceAction_Manage:
s := proto.Size(x.Manage)
n += 1 // tag and wire
n += proto.SizeVarint(uint64(s))
n += s
case nil:
default:
panic(fmt.Sprintf("proto: unexpected type %T in oneof", x))
}
return n
}
type IssuanceManage struct {
SuperAddrs []string `protobuf:"bytes,1,rep,name=superAddrs,proto3" json:"superAddrs,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *IssuanceManage) Reset() { *m = IssuanceManage{} }
func (m *IssuanceManage) String() string { return proto.CompactTextString(m) }
func (*IssuanceManage) ProtoMessage() {}
func (*IssuanceManage) Descriptor() ([]byte, []int) {
return fileDescriptor_issuance_4d8bb77ed2bb92a1, []int{4}
}
func (m *IssuanceManage) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_IssuanceManage.Unmarshal(m, b)
}
func (m *IssuanceManage) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_IssuanceManage.Marshal(b, m, deterministic)
}
func (dst *IssuanceManage) XXX_Merge(src proto.Message) {
xxx_messageInfo_IssuanceManage.Merge(dst, src)
}
func (m *IssuanceManage) XXX_Size() int {
return xxx_messageInfo_IssuanceManage.Size(m)
}
func (m *IssuanceManage) XXX_DiscardUnknown() {
xxx_messageInfo_IssuanceManage.DiscardUnknown(m)
}
var xxx_messageInfo_IssuanceManage proto.InternalMessageInfo
func (m *IssuanceManage) GetSuperAddrs() []string {
if m != nil {
return m.SuperAddrs
}
return nil
}
// 创建发行
type IssuanceCreate struct {
TotalBalance int64 `protobuf:"varint,1,opt,name=totalBalance,proto3" json:"totalBalance,omitempty"`
DebtCeiling int64 `protobuf:"varint,2,opt,name=debtCeiling,proto3" json:"debtCeiling,omitempty"`
LiquidationRatio int64 `protobuf:"varint,3,opt,name=liquidationRatio,proto3" json:"liquidationRatio,omitempty"`
Period int64 `protobuf:"varint,4,opt,name=period,proto3" json:"period,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *IssuanceCreate) Reset() { *m = IssuanceCreate{} }
func (m *IssuanceCreate) String() string { return proto.CompactTextString(m) }
func (*IssuanceCreate) ProtoMessage() {}
func (*IssuanceCreate) Descriptor() ([]byte, []int) {
return fileDescriptor_issuance_4d8bb77ed2bb92a1, []int{5}
}
func (m *IssuanceCreate) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_IssuanceCreate.Unmarshal(m, b)
}
func (m *IssuanceCreate) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_IssuanceCreate.Marshal(b, m, deterministic)
}
func (dst *IssuanceCreate) XXX_Merge(src proto.Message) {
xxx_messageInfo_IssuanceCreate.Merge(dst, src)
}
func (m *IssuanceCreate) XXX_Size() int {
return xxx_messageInfo_IssuanceCreate.Size(m)
}
func (m *IssuanceCreate) XXX_DiscardUnknown() {
xxx_messageInfo_IssuanceCreate.DiscardUnknown(m)
}
var xxx_messageInfo_IssuanceCreate proto.InternalMessageInfo
func (m *IssuanceCreate) GetTotalBalance() int64 {
if m != nil {
return m.TotalBalance
}
return 0
}
func (m *IssuanceCreate) GetDebtCeiling() int64 {
if m != nil {
return m.DebtCeiling
}
return 0
}
func (m *IssuanceCreate) GetLiquidationRatio() int64 {
if m != nil {
return m.LiquidationRatio
}
return 0
}
func (m *IssuanceCreate) GetPeriod() int64 {
if m != nil {
return m.Period
}
return 0
}
// 抵押
type IssuanceDebt struct {
IssuanceId string `protobuf:"bytes,1,opt,name=issuanceId,proto3" json:"issuanceId,omitempty"`
Value int64 `protobuf:"varint,2,opt,name=value,proto3" json:"value,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *IssuanceDebt) Reset() { *m = IssuanceDebt{} }
func (m *IssuanceDebt) String() string { return proto.CompactTextString(m) }
func (*IssuanceDebt) ProtoMessage() {}
func (*IssuanceDebt) Descriptor() ([]byte, []int) {
return fileDescriptor_issuance_4d8bb77ed2bb92a1, []int{6}
}
func (m *IssuanceDebt) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_IssuanceDebt.Unmarshal(m, b)
}
func (m *IssuanceDebt) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_IssuanceDebt.Marshal(b, m, deterministic)
}
func (dst *IssuanceDebt) XXX_Merge(src proto.Message) {
xxx_messageInfo_IssuanceDebt.Merge(dst, src)
}
func (m *IssuanceDebt) XXX_Size() int {
return xxx_messageInfo_IssuanceDebt.Size(m)
}
func (m *IssuanceDebt) XXX_DiscardUnknown() {
xxx_messageInfo_IssuanceDebt.DiscardUnknown(m)
}
var xxx_messageInfo_IssuanceDebt proto.InternalMessageInfo
func (m *IssuanceDebt) GetIssuanceId() string {
if m != nil {
return m.IssuanceId
}
return ""
}
func (m *IssuanceDebt) GetValue() int64 {
if m != nil {
return m.Value
}
return 0
}
// 质押清算
type IssuanceRepay struct {
IssuanceId string `protobuf:"bytes,1,opt,name=issuanceId,proto3" json:"issuanceId,omitempty"`
DebtId string `protobuf:"bytes,2,opt,name=debtId,proto3" json:"debtId,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *IssuanceRepay) Reset() { *m = IssuanceRepay{} }
func (m *IssuanceRepay) String() string { return proto.CompactTextString(m) }
func (*IssuanceRepay) ProtoMessage() {}
func (*IssuanceRepay) Descriptor() ([]byte, []int) {
return fileDescriptor_issuance_4d8bb77ed2bb92a1, []int{7}
}
func (m *IssuanceRepay) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_IssuanceRepay.Unmarshal(m, b)
}
func (m *IssuanceRepay) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_IssuanceRepay.Marshal(b, m, deterministic)
}
func (dst *IssuanceRepay) XXX_Merge(src proto.Message) {
xxx_messageInfo_IssuanceRepay.Merge(dst, src)
}
func (m *IssuanceRepay) XXX_Size() int {
return xxx_messageInfo_IssuanceRepay.Size(m)
}
func (m *IssuanceRepay) XXX_DiscardUnknown() {
xxx_messageInfo_IssuanceRepay.DiscardUnknown(m)
}
var xxx_messageInfo_IssuanceRepay proto.InternalMessageInfo
func (m *IssuanceRepay) GetIssuanceId() string {
if m != nil {
return m.IssuanceId
}
return ""
}
func (m *IssuanceRepay) GetDebtId() string {
if m != nil {
return m.DebtId
}
return ""
}
// 喂价
type IssuanceFeed struct {
CollType int32 `protobuf:"varint,1,opt,name=collType,proto3" json:"collType,omitempty"`
Price []int64 `protobuf:"varint,2,rep,packed,name=price,proto3" json:"price,omitempty"`
Volume []int64 `protobuf:"varint,3,rep,packed,name=volume,proto3" json:"volume,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *IssuanceFeed) Reset() { *m = IssuanceFeed{} }
func (m *IssuanceFeed) String() string { return proto.CompactTextString(m) }
func (*IssuanceFeed) ProtoMessage() {}
func (*IssuanceFeed) Descriptor() ([]byte, []int) {
return fileDescriptor_issuance_4d8bb77ed2bb92a1, []int{8}
}
func (m *IssuanceFeed) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_IssuanceFeed.Unmarshal(m, b)
}
func (m *IssuanceFeed) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_IssuanceFeed.Marshal(b, m, deterministic)
}
func (dst *IssuanceFeed) XXX_Merge(src proto.Message) {
xxx_messageInfo_IssuanceFeed.Merge(dst, src)
}
func (m *IssuanceFeed) XXX_Size() int {
return xxx_messageInfo_IssuanceFeed.Size(m)
}
func (m *IssuanceFeed) XXX_DiscardUnknown() {
xxx_messageInfo_IssuanceFeed.DiscardUnknown(m)
}
var xxx_messageInfo_IssuanceFeed proto.InternalMessageInfo
func (m *IssuanceFeed) GetCollType() int32 {
if m != nil {
return m.CollType
}
return 0
}
func (m *IssuanceFeed) GetPrice() []int64 {
if m != nil {
return m.Price
}
return nil
}
func (m *IssuanceFeed) GetVolume() []int64 {
if m != nil {
return m.Volume
}
return nil
}
// 借贷关闭
type IssuanceClose struct {
IssuanceId string `protobuf:"bytes,1,opt,name=issuanceId,proto3" json:"issuanceId,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *IssuanceClose) Reset() { *m = IssuanceClose{} }
func (m *IssuanceClose) String() string { return proto.CompactTextString(m) }
func (*IssuanceClose) ProtoMessage() {}
func (*IssuanceClose) Descriptor() ([]byte, []int) {
return fileDescriptor_issuance_4d8bb77ed2bb92a1, []int{9}
}
func (m *IssuanceClose) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_IssuanceClose.Unmarshal(m, b)
}
func (m *IssuanceClose) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_IssuanceClose.Marshal(b, m, deterministic)
}
func (dst *IssuanceClose) XXX_Merge(src proto.Message) {
xxx_messageInfo_IssuanceClose.Merge(dst, src)
}
func (m *IssuanceClose) XXX_Size() int {
return xxx_messageInfo_IssuanceClose.Size(m)
}
func (m *IssuanceClose) XXX_DiscardUnknown() {
xxx_messageInfo_IssuanceClose.DiscardUnknown(m)
}
var xxx_messageInfo_IssuanceClose proto.InternalMessageInfo
func (m *IssuanceClose) GetIssuanceId() string {
if m != nil {
return m.IssuanceId
}
return ""
}
// exec_local 发行信息
type ReceiptIssuance struct {
IssuanceId string `protobuf:"bytes,1,opt,name=issuanceId,proto3" json:"issuanceId,omitempty"`
AccountAddr string `protobuf:"bytes,2,opt,name=accountAddr,proto3" json:"accountAddr,omitempty"`
DebtId string `protobuf:"bytes,3,opt,name=debtId,proto3" json:"debtId,omitempty"`
Status int32 `protobuf:"varint,4,opt,name=status,proto3" json:"status,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *ReceiptIssuance) Reset() { *m = ReceiptIssuance{} }
func (m *ReceiptIssuance) String() string { return proto.CompactTextString(m) }
func (*ReceiptIssuance) ProtoMessage() {}
func (*ReceiptIssuance) Descriptor() ([]byte, []int) {
return fileDescriptor_issuance_4d8bb77ed2bb92a1, []int{10}
}
func (m *ReceiptIssuance) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ReceiptIssuance.Unmarshal(m, b)
}
func (m *ReceiptIssuance) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_ReceiptIssuance.Marshal(b, m, deterministic)
}
func (dst *ReceiptIssuance) XXX_Merge(src proto.Message) {
xxx_messageInfo_ReceiptIssuance.Merge(dst, src)
}
func (m *ReceiptIssuance) XXX_Size() int {
return xxx_messageInfo_ReceiptIssuance.Size(m)
}
func (m *ReceiptIssuance) XXX_DiscardUnknown() {
xxx_messageInfo_ReceiptIssuance.DiscardUnknown(m)
}
var xxx_messageInfo_ReceiptIssuance proto.InternalMessageInfo
func (m *ReceiptIssuance) GetIssuanceId() string {
if m != nil {
return m.IssuanceId
}
return ""
}
func (m *ReceiptIssuance) GetAccountAddr() string {
if m != nil {
return m.AccountAddr
}
return ""
}
func (m *ReceiptIssuance) GetDebtId() string {
if m != nil {
return m.DebtId
}
return ""
}
func (m *ReceiptIssuance) GetStatus() int32 {
if m != nil {
return m.Status
}
return 0
}
// exec_local issuid记录信息
type ReceiptIssuanceID struct {
IssuanceId string `protobuf:"bytes,1,opt,name=issuanceId,proto3" json:"issuanceId,omitempty"`
Status int32 `protobuf:"varint,2,opt,name=status,proto3" json:"status,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *ReceiptIssuanceID) Reset() { *m = ReceiptIssuanceID{} }
func (m *ReceiptIssuanceID) String() string { return proto.CompactTextString(m) }
func (*ReceiptIssuanceID) ProtoMessage() {}
func (*ReceiptIssuanceID) Descriptor() ([]byte, []int) {
return fileDescriptor_issuance_4d8bb77ed2bb92a1, []int{11}
}
func (m *ReceiptIssuanceID) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ReceiptIssuanceID.Unmarshal(m, b)
}
func (m *ReceiptIssuanceID) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_ReceiptIssuanceID.Marshal(b, m, deterministic)
}
func (dst *ReceiptIssuanceID) XXX_Merge(src proto.Message) {
xxx_messageInfo_ReceiptIssuanceID.Merge(dst, src)
}
func (m *ReceiptIssuanceID) XXX_Size() int {
return xxx_messageInfo_ReceiptIssuanceID.Size(m)
}
func (m *ReceiptIssuanceID) XXX_DiscardUnknown() {
xxx_messageInfo_ReceiptIssuanceID.DiscardUnknown(m)
}
var xxx_messageInfo_ReceiptIssuanceID proto.InternalMessageInfo
func (m *ReceiptIssuanceID) GetIssuanceId() string {
if m != nil {
return m.IssuanceId
}
return ""
}
func (m *ReceiptIssuanceID) GetStatus() int32 {
if m != nil {
return m.Status
}
return 0
}
// exec_local 抵押记录信息列表
type IssuanceRecords struct {
Records []*ReceiptIssuance `protobuf:"bytes,1,rep,name=records,proto3" json:"records,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *IssuanceRecords) Reset() { *m = IssuanceRecords{} }
func (m *IssuanceRecords) String() string { return proto.CompactTextString(m) }
func (*IssuanceRecords) ProtoMessage() {}
func (*IssuanceRecords) Descriptor() ([]byte, []int) {
return fileDescriptor_issuance_4d8bb77ed2bb92a1, []int{12}
}
func (m *IssuanceRecords) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_IssuanceRecords.Unmarshal(m, b)
}
func (m *IssuanceRecords) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_IssuanceRecords.Marshal(b, m, deterministic)
}
func (dst *IssuanceRecords) XXX_Merge(src proto.Message) {
xxx_messageInfo_IssuanceRecords.Merge(dst, src)
}
func (m *IssuanceRecords) XXX_Size() int {
return xxx_messageInfo_IssuanceRecords.Size(m)
}
func (m *IssuanceRecords) XXX_DiscardUnknown() {
xxx_messageInfo_IssuanceRecords.DiscardUnknown(m)
}
var xxx_messageInfo_IssuanceRecords proto.InternalMessageInfo
func (m *IssuanceRecords) GetRecords() []*ReceiptIssuance {
if m != nil {
return m.Records
}
return nil
}
// 根据ID查询发行信息
type ReqIssuanceInfo struct {
IssuanceId string `protobuf:"bytes,1,opt,name=issuanceId,proto3" json:"issuanceId,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *ReqIssuanceInfo) Reset() { *m = ReqIssuanceInfo{} }
func (m *ReqIssuanceInfo) String() string { return proto.CompactTextString(m) }
func (*ReqIssuanceInfo) ProtoMessage() {}
func (*ReqIssuanceInfo) Descriptor() ([]byte, []int) {
return fileDescriptor_issuance_4d8bb77ed2bb92a1, []int{13}
}
func (m *ReqIssuanceInfo) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ReqIssuanceInfo.Unmarshal(m, b)
}
func (m *ReqIssuanceInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_ReqIssuanceInfo.Marshal(b, m, deterministic)
}
func (dst *ReqIssuanceInfo) XXX_Merge(src proto.Message) {
xxx_messageInfo_ReqIssuanceInfo.Merge(dst, src)
}
func (m *ReqIssuanceInfo) XXX_Size() int {
return xxx_messageInfo_ReqIssuanceInfo.Size(m)
}
func (m *ReqIssuanceInfo) XXX_DiscardUnknown() {
xxx_messageInfo_ReqIssuanceInfo.DiscardUnknown(m)
}
var xxx_messageInfo_ReqIssuanceInfo proto.InternalMessageInfo
func (m *ReqIssuanceInfo) GetIssuanceId() string {
if m != nil {
return m.IssuanceId
}
return ""
}
// 返回一期发行信息
type RepIssuanceCurrentInfo struct {
Status int32 `protobuf:"varint,1,opt,name=status,proto3" json:"status,omitempty"`
TotalBalance int64 `protobuf:"varint,2,opt,name=totalBalance,proto3" json:"totalBalance,omitempty"`
DebtCeiling int64 `protobuf:"varint,3,opt,name=debtCeiling,proto3" json:"debtCeiling,omitempty"`
LiquidationRatio int64 `protobuf:"varint,4,opt,name=liquidationRatio,proto3" json:"liquidationRatio,omitempty"`
Balance int64 `protobuf:"varint,5,opt,name=balance,proto3" json:"balance,omitempty"`
CollateralValue int64 `protobuf:"varint,6,opt,name=collateralValue,proto3" json:"collateralValue,omitempty"`
DebtValue int64 `protobuf:"varint,7,opt,name=debtValue,proto3" json:"debtValue,omitempty"`
Period int64 `protobuf:"varint,8,opt,name=period,proto3" json:"period,omitempty"`
IssuId string `protobuf:"bytes,9,opt,name=issuId,proto3" json:"issuId,omitempty"`
CreateTime int64 `protobuf:"varint,10,opt,name=createTime,proto3" json:"createTime,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *RepIssuanceCurrentInfo) Reset() { *m = RepIssuanceCurrentInfo{} }
func (m *RepIssuanceCurrentInfo) String() string { return proto.CompactTextString(m) }
func (*RepIssuanceCurrentInfo) ProtoMessage() {}
func (*RepIssuanceCurrentInfo) Descriptor() ([]byte, []int) {
return fileDescriptor_issuance_4d8bb77ed2bb92a1, []int{14}
}
func (m *RepIssuanceCurrentInfo) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_RepIssuanceCurrentInfo.Unmarshal(m, b)
}
func (m *RepIssuanceCurrentInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_RepIssuanceCurrentInfo.Marshal(b, m, deterministic)
}
func (dst *RepIssuanceCurrentInfo) XXX_Merge(src proto.Message) {
xxx_messageInfo_RepIssuanceCurrentInfo.Merge(dst, src)
}
func (m *RepIssuanceCurrentInfo) XXX_Size() int {
return xxx_messageInfo_RepIssuanceCurrentInfo.Size(m)
}
func (m *RepIssuanceCurrentInfo) XXX_DiscardUnknown() {
xxx_messageInfo_RepIssuanceCurrentInfo.DiscardUnknown(m)
}
var xxx_messageInfo_RepIssuanceCurrentInfo proto.InternalMessageInfo
func (m *RepIssuanceCurrentInfo) GetStatus() int32 {
if m != nil {
return m.Status
}
return 0
}
func (m *RepIssuanceCurrentInfo) GetTotalBalance() int64 {
if m != nil {
return m.TotalBalance
}
return 0
}
func (m *RepIssuanceCurrentInfo) GetDebtCeiling() int64 {
if m != nil {
return m.DebtCeiling
}
return 0
}
func (m *RepIssuanceCurrentInfo) GetLiquidationRatio() int64 {
if m != nil {
return m.LiquidationRatio
}
return 0
}
func (m *RepIssuanceCurrentInfo) GetBalance() int64 {
if m != nil {
return m.Balance
}
return 0
}
func (m *RepIssuanceCurrentInfo) GetCollateralValue() int64 {
if m != nil {
return m.CollateralValue
}
return 0
}
func (m *RepIssuanceCurrentInfo) GetDebtValue() int64 {
if m != nil {
return m.DebtValue
}
return 0
}
func (m *RepIssuanceCurrentInfo) GetPeriod() int64 {
if m != nil {
return m.Period
}
return 0
}
func (m *RepIssuanceCurrentInfo) GetIssuId() string {
if m != nil {
return m.IssuId
}
return ""
}
func (m *RepIssuanceCurrentInfo) GetCreateTime() int64 {
if m != nil {
return m.CreateTime
}
return 0
}
// 根据ID列表查询多期发行信息
type ReqIssuanceInfos struct {
IssuanceIds []string `protobuf:"bytes,1,rep,name=issuanceIds,proto3" json:"issuanceIds,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *ReqIssuanceInfos) Reset() { *m = ReqIssuanceInfos{} }
func (m *ReqIssuanceInfos) String() string { return proto.CompactTextString(m) }
func (*ReqIssuanceInfos) ProtoMessage() {}
func (*ReqIssuanceInfos) Descriptor() ([]byte, []int) {
return fileDescriptor_issuance_4d8bb77ed2bb92a1, []int{15}
}
func (m *ReqIssuanceInfos) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ReqIssuanceInfos.Unmarshal(m, b)
}
func (m *ReqIssuanceInfos) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_ReqIssuanceInfos.Marshal(b, m, deterministic)
}
func (dst *ReqIssuanceInfos) XXX_Merge(src proto.Message) {
xxx_messageInfo_ReqIssuanceInfos.Merge(dst, src)
}
func (m *ReqIssuanceInfos) XXX_Size() int {
return xxx_messageInfo_ReqIssuanceInfos.Size(m)
}
func (m *ReqIssuanceInfos) XXX_DiscardUnknown() {
xxx_messageInfo_ReqIssuanceInfos.DiscardUnknown(m)
}
var xxx_messageInfo_ReqIssuanceInfos proto.InternalMessageInfo
func (m *ReqIssuanceInfos) GetIssuanceIds() []string {
if m != nil {
return m.IssuanceIds
}
return nil
}
// 返回多期发行信息
type RepIssuanceCurrentInfos struct {
Infos []*RepIssuanceCurrentInfo `protobuf:"bytes,1,rep,name=infos,proto3" json:"infos,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *RepIssuanceCurrentInfos) Reset() { *m = RepIssuanceCurrentInfos{} }
func (m *RepIssuanceCurrentInfos) String() string { return proto.CompactTextString(m) }
func (*RepIssuanceCurrentInfos) ProtoMessage() {}
func (*RepIssuanceCurrentInfos) Descriptor() ([]byte, []int) {
return fileDescriptor_issuance_4d8bb77ed2bb92a1, []int{16}
}
func (m *RepIssuanceCurrentInfos) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_RepIssuanceCurrentInfos.Unmarshal(m, b)
}
func (m *RepIssuanceCurrentInfos) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_RepIssuanceCurrentInfos.Marshal(b, m, deterministic)
}
func (dst *RepIssuanceCurrentInfos) XXX_Merge(src proto.Message) {
xxx_messageInfo_RepIssuanceCurrentInfos.Merge(dst, src)
}
func (m *RepIssuanceCurrentInfos) XXX_Size() int {
return xxx_messageInfo_RepIssuanceCurrentInfos.Size(m)
}
func (m *RepIssuanceCurrentInfos) XXX_DiscardUnknown() {
xxx_messageInfo_RepIssuanceCurrentInfos.DiscardUnknown(m)
}
var xxx_messageInfo_RepIssuanceCurrentInfos proto.InternalMessageInfo
func (m *RepIssuanceCurrentInfos) GetInfos() []*RepIssuanceCurrentInfo {
if m != nil {
return m.Infos
}
return nil
}
// 根据发行状态查询
type ReqIssuanceByStatus struct {
Status int32 `protobuf:"varint,1,opt,name=status,proto3" json:"status,omitempty"`
IssuanceId string `protobuf:"bytes,2,opt,name=issuanceId,proto3" json:"issuanceId,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *ReqIssuanceByStatus) Reset() { *m = ReqIssuanceByStatus{} }
func (m *ReqIssuanceByStatus) String() string { return proto.CompactTextString(m) }
func (*ReqIssuanceByStatus) ProtoMessage() {}
func (*ReqIssuanceByStatus) Descriptor() ([]byte, []int) {
return fileDescriptor_issuance_4d8bb77ed2bb92a1, []int{17}
}
func (m *ReqIssuanceByStatus) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ReqIssuanceByStatus.Unmarshal(m, b)
}
func (m *ReqIssuanceByStatus) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_ReqIssuanceByStatus.Marshal(b, m, deterministic)
}
func (dst *ReqIssuanceByStatus) XXX_Merge(src proto.Message) {
xxx_messageInfo_ReqIssuanceByStatus.Merge(dst, src)
}
func (m *ReqIssuanceByStatus) XXX_Size() int {
return xxx_messageInfo_ReqIssuanceByStatus.Size(m)
}
func (m *ReqIssuanceByStatus) XXX_DiscardUnknown() {
xxx_messageInfo_ReqIssuanceByStatus.DiscardUnknown(m)
}
var xxx_messageInfo_ReqIssuanceByStatus proto.InternalMessageInfo
func (m *ReqIssuanceByStatus) GetStatus() int32 {
if m != nil {
return m.Status
}
return 0
}
func (m *ReqIssuanceByStatus) GetIssuanceId() string {
if m != nil {
return m.IssuanceId
}
return ""
}
// 返回发行ID列表
type RepIssuanceIDs struct {
IDs []string `protobuf:"bytes,1,rep,name=IDs,proto3" json:"IDs,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *RepIssuanceIDs) Reset() { *m = RepIssuanceIDs{} }
func (m *RepIssuanceIDs) String() string { return proto.CompactTextString(m) }
func (*RepIssuanceIDs) ProtoMessage() {}
func (*RepIssuanceIDs) Descriptor() ([]byte, []int) {
return fileDescriptor_issuance_4d8bb77ed2bb92a1, []int{18}
}
func (m *RepIssuanceIDs) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_RepIssuanceIDs.Unmarshal(m, b)
}
func (m *RepIssuanceIDs) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_RepIssuanceIDs.Marshal(b, m, deterministic)
}
func (dst *RepIssuanceIDs) XXX_Merge(src proto.Message) {
xxx_messageInfo_RepIssuanceIDs.Merge(dst, src)
}
func (m *RepIssuanceIDs) XXX_Size() int {
return xxx_messageInfo_RepIssuanceIDs.Size(m)
}
func (m *RepIssuanceIDs) XXX_DiscardUnknown() {
xxx_messageInfo_RepIssuanceIDs.DiscardUnknown(m)
}
var xxx_messageInfo_RepIssuanceIDs proto.InternalMessageInfo
func (m *RepIssuanceIDs) GetIDs() []string {
if m != nil {
return m.IDs
}
return nil
}
// 根据用户地址查询抵押记录
type ReqIssuanceRecords struct {
IssuanceId string `protobuf:"bytes,1,opt,name=issuanceId,proto3" json:"issuanceId,omitempty"`
Addr string `protobuf:"bytes,2,opt,name=addr,proto3" json:"addr,omitempty"`
Status int32 `protobuf:"varint,3,opt,name=status,proto3" json:"status,omitempty"`
DebtId string `protobuf:"bytes,4,opt,name=debtId,proto3" json:"debtId,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *ReqIssuanceRecords) Reset() { *m = ReqIssuanceRecords{} }
func (m *ReqIssuanceRecords) String() string { return proto.CompactTextString(m) }
func (*ReqIssuanceRecords) ProtoMessage() {}
func (*ReqIssuanceRecords) Descriptor() ([]byte, []int) {
return fileDescriptor_issuance_4d8bb77ed2bb92a1, []int{19}
}
func (m *ReqIssuanceRecords) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ReqIssuanceRecords.Unmarshal(m, b)
}
func (m *ReqIssuanceRecords) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_ReqIssuanceRecords.Marshal(b, m, deterministic)
}
func (dst *ReqIssuanceRecords) XXX_Merge(src proto.Message) {
xxx_messageInfo_ReqIssuanceRecords.Merge(dst, src)
}
func (m *ReqIssuanceRecords) XXX_Size() int {
return xxx_messageInfo_ReqIssuanceRecords.Size(m)
}
func (m *ReqIssuanceRecords) XXX_DiscardUnknown() {
xxx_messageInfo_ReqIssuanceRecords.DiscardUnknown(m)
}
var xxx_messageInfo_ReqIssuanceRecords proto.InternalMessageInfo
func (m *ReqIssuanceRecords) GetIssuanceId() string {
if m != nil {
return m.IssuanceId
}
return ""
}
func (m *ReqIssuanceRecords) GetAddr() string {
if m != nil {
return m.Addr
}
return ""
}
func (m *ReqIssuanceRecords) GetStatus() int32 {
if m != nil {
return m.Status
}
return 0
}
func (m *ReqIssuanceRecords) GetDebtId() string {
if m != nil {
return m.DebtId
}
return ""
}
// 返回记录列表
type RepIssuanceRecords struct {
Records []*DebtRecord `protobuf:"bytes,1,rep,name=records,proto3" json:"records,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *RepIssuanceRecords) Reset() { *m = RepIssuanceRecords{} }
func (m *RepIssuanceRecords) String() string { return proto.CompactTextString(m) }
func (*RepIssuanceRecords) ProtoMessage() {}
func (*RepIssuanceRecords) Descriptor() ([]byte, []int) {
return fileDescriptor_issuance_4d8bb77ed2bb92a1, []int{20}
}
func (m *RepIssuanceRecords) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_RepIssuanceRecords.Unmarshal(m, b)
}
func (m *RepIssuanceRecords) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_RepIssuanceRecords.Marshal(b, m, deterministic)
}
func (dst *RepIssuanceRecords) XXX_Merge(src proto.Message) {
xxx_messageInfo_RepIssuanceRecords.Merge(dst, src)
}
func (m *RepIssuanceRecords) XXX_Size() int {
return xxx_messageInfo_RepIssuanceRecords.Size(m)
}
func (m *RepIssuanceRecords) XXX_DiscardUnknown() {
xxx_messageInfo_RepIssuanceRecords.DiscardUnknown(m)
}
var xxx_messageInfo_RepIssuanceRecords proto.InternalMessageInfo
func (m *RepIssuanceRecords) GetRecords() []*DebtRecord {
if m != nil {
return m.Records
}
return nil
}
// 返回记录
type RepIssuanceDebtInfo struct {
Record *DebtRecord `protobuf:"bytes,1,opt,name=record,proto3" json:"record,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *RepIssuanceDebtInfo) Reset() { *m = RepIssuanceDebtInfo{} }
func (m *RepIssuanceDebtInfo) String() string { return proto.CompactTextString(m) }
func (*RepIssuanceDebtInfo) ProtoMessage() {}
func (*RepIssuanceDebtInfo) Descriptor() ([]byte, []int) {
return fileDescriptor_issuance_4d8bb77ed2bb92a1, []int{21}
}
func (m *RepIssuanceDebtInfo) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_RepIssuanceDebtInfo.Unmarshal(m, b)
}
func (m *RepIssuanceDebtInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_RepIssuanceDebtInfo.Marshal(b, m, deterministic)
}
func (dst *RepIssuanceDebtInfo) XXX_Merge(src proto.Message) {
xxx_messageInfo_RepIssuanceDebtInfo.Merge(dst, src)
}
func (m *RepIssuanceDebtInfo) XXX_Size() int {
return xxx_messageInfo_RepIssuanceDebtInfo.Size(m)
}
func (m *RepIssuanceDebtInfo) XXX_DiscardUnknown() {
xxx_messageInfo_RepIssuanceDebtInfo.DiscardUnknown(m)
}
var xxx_messageInfo_RepIssuanceDebtInfo proto.InternalMessageInfo
func (m *RepIssuanceDebtInfo) GetRecord() *DebtRecord {
if m != nil {
return m.Record
}
return nil
}
// 返回最新抵押物价格
type RepIssuancePrice struct {
Price int64 `protobuf:"varint,1,opt,name=price,proto3" json:"price,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *RepIssuancePrice) Reset() { *m = RepIssuancePrice{} }
func (m *RepIssuancePrice) String() string { return proto.CompactTextString(m) }
func (*RepIssuancePrice) ProtoMessage() {}
func (*RepIssuancePrice) Descriptor() ([]byte, []int) {
return fileDescriptor_issuance_4d8bb77ed2bb92a1, []int{22}
}
func (m *RepIssuancePrice) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_RepIssuancePrice.Unmarshal(m, b)
}
func (m *RepIssuancePrice) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_RepIssuancePrice.Marshal(b, m, deterministic)
}
func (dst *RepIssuancePrice) XXX_Merge(src proto.Message) {
xxx_messageInfo_RepIssuancePrice.Merge(dst, src)
}
func (m *RepIssuancePrice) XXX_Size() int {
return xxx_messageInfo_RepIssuancePrice.Size(m)
}
func (m *RepIssuancePrice) XXX_DiscardUnknown() {
xxx_messageInfo_RepIssuancePrice.DiscardUnknown(m)
}
var xxx_messageInfo_RepIssuancePrice proto.InternalMessageInfo
func (m *RepIssuancePrice) GetPrice() int64 {
if m != nil {
return m.Price
}
return 0
}
// 返回用户发行总额
type RepIssuanceUserBalance struct {
Balance int64 `protobuf:"varint,1,opt,name=balance,proto3" json:"balance,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *RepIssuanceUserBalance) Reset() { *m = RepIssuanceUserBalance{} }
func (m *RepIssuanceUserBalance) String() string { return proto.CompactTextString(m) }
func (*RepIssuanceUserBalance) ProtoMessage() {}
func (*RepIssuanceUserBalance) Descriptor() ([]byte, []int) {
return fileDescriptor_issuance_4d8bb77ed2bb92a1, []int{23}
}
func (m *RepIssuanceUserBalance) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_RepIssuanceUserBalance.Unmarshal(m, b)
}
func (m *RepIssuanceUserBalance) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_RepIssuanceUserBalance.Marshal(b, m, deterministic)
}
func (dst *RepIssuanceUserBalance) XXX_Merge(src proto.Message) {
xxx_messageInfo_RepIssuanceUserBalance.Merge(dst, src)
}
func (m *RepIssuanceUserBalance) XXX_Size() int {
return xxx_messageInfo_RepIssuanceUserBalance.Size(m)
}
func (m *RepIssuanceUserBalance) XXX_DiscardUnknown() {
xxx_messageInfo_RepIssuanceUserBalance.DiscardUnknown(m)
}
var xxx_messageInfo_RepIssuanceUserBalance proto.InternalMessageInfo
func (m *RepIssuanceUserBalance) GetBalance() int64 {
if m != nil {
return m.Balance
}
return 0
}
func init() {
proto.RegisterType((*Issuance)(nil), "types.Issuance")
proto.RegisterType((*DebtRecord)(nil), "types.DebtRecord")
proto.RegisterType((*IssuanceAssetPriceRecord)(nil), "types.IssuanceAssetPriceRecord")
proto.RegisterType((*IssuanceAction)(nil), "types.IssuanceAction")
proto.RegisterType((*IssuanceManage)(nil), "types.IssuanceManage")
proto.RegisterType((*IssuanceCreate)(nil), "types.IssuanceCreate")
proto.RegisterType((*IssuanceDebt)(nil), "types.IssuanceDebt")
proto.RegisterType((*IssuanceRepay)(nil), "types.IssuanceRepay")
proto.RegisterType((*IssuanceFeed)(nil), "types.IssuanceFeed")
proto.RegisterType((*IssuanceClose)(nil), "types.IssuanceClose")
proto.RegisterType((*ReceiptIssuance)(nil), "types.ReceiptIssuance")
proto.RegisterType((*ReceiptIssuanceID)(nil), "types.ReceiptIssuanceID")
proto.RegisterType((*IssuanceRecords)(nil), "types.IssuanceRecords")
proto.RegisterType((*ReqIssuanceInfo)(nil), "types.ReqIssuanceInfo")
proto.RegisterType((*RepIssuanceCurrentInfo)(nil), "types.RepIssuanceCurrentInfo")
proto.RegisterType((*ReqIssuanceInfos)(nil), "types.ReqIssuanceInfos")
proto.RegisterType((*RepIssuanceCurrentInfos)(nil), "types.RepIssuanceCurrentInfos")
proto.RegisterType((*ReqIssuanceByStatus)(nil), "types.ReqIssuanceByStatus")
proto.RegisterType((*RepIssuanceIDs)(nil), "types.RepIssuanceIDs")
proto.RegisterType((*ReqIssuanceRecords)(nil), "types.ReqIssuanceRecords")
proto.RegisterType((*RepIssuanceRecords)(nil), "types.RepIssuanceRecords")
proto.RegisterType((*RepIssuanceDebtInfo)(nil), "types.RepIssuanceDebtInfo")
proto.RegisterType((*RepIssuancePrice)(nil), "types.RepIssuancePrice")
proto.RegisterType((*RepIssuanceUserBalance)(nil), "types.RepIssuanceUserBalance")
}
func init() { proto.RegisterFile("issuance.proto", fileDescriptor_issuance_4d8bb77ed2bb92a1) }
var fileDescriptor_issuance_4d8bb77ed2bb92a1 = []byte{
// 1041 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x57, 0x5f, 0x6f, 0xe3, 0x44,
0x10, 0xaf, 0xed, 0x38, 0x7f, 0x26, 0x6d, 0xda, 0xdb, 0x3b, 0x8a, 0x85, 0xe0, 0x14, 0xad, 0x78,
0xc8, 0x01, 0xea, 0x1d, 0x29, 0x42, 0xe2, 0x8d, 0xb6, 0x01, 0x1a, 0xc1, 0x21, 0x64, 0x8e, 0x13,
0xaf, 0xae, 0xbd, 0x77, 0xb2, 0xe4, 0xc6, 0x3e, 0xef, 0xa6, 0xba, 0x3c, 0xf3, 0x1d, 0x78, 0xe0,
0xbb, 0xf0, 0xc2, 0x67, 0xe0, 0x03, 0xa1, 0xd9, 0x5d, 0x7b, 0xd7, 0x9b, 0x54, 0xe9, 0x13, 0x2f,
0x55, 0x76, 0xf6, 0xb7, 0xb3, 0xb3, 0xf3, 0xfb, 0xcd, 0x8c, 0x0b, 0x93, 0x9c, 0xf3, 0x75, 0xb2,
0x4a, 0xd9, 0x59, 0x55, 0x97, 0xa2, 0x24, 0xa1, 0xd8, 0x54, 0x8c, 0xd3, 0x7f, 0x7a, 0x30, 0x5c,
0xea, 0x1d, 0xf2, 0x14, 0xa0, 0x41, 0x2d, 0xb3, 0xc8, 0x9b, 0x7a, 0xb3, 0x51, 0x6c, 0x59, 0x08,
0x85, 0x43, 0x51, 0x8a, 0xa4, 0xb8, 0x4c, 0x0a, 0xb4, 0x44, 0xfe, 0xd4, 0x9b, 0x05, 0x71, 0xc7,
0x46, 0xa6, 0x30, 0xce, 0xd8, 0x8d, 0xb8, 0x62, 0x79, 0x91, 0xaf, 0xde, 0x46, 0x81, 0x84, 0xd8,
0x26, 0xf2, 0x19, 0x9c, 0x14, 0xf9, 0xbb, 0x75, 0x9e, 0x25, 0x22, 0x2f, 0x57, 0x31, 0xfe, 0x8d,
0x7a, 0x12, 0xb6, 0x65, 0x27, 0x33, 0x38, 0x4e, 0xcb, 0xa2, 0x48, 0x04, 0xab, 0x93, 0xe2, 0x75,
0x52, 0xac, 0x59, 0x14, 0x4a, 0xa8, 0x6b, 0x26, 0x1f, 0xc3, 0x08, 0x2f, 0x51, 0x98, 0xbe, 0xc4,
0x18, 0x03, 0x39, 0x57, 0x51, 0xc5, 0x2c, 0x2d, 0xeb, 0x8c, 0x47, 0x83, 0x69, 0x30, 0x1b, 0xcf,
0x1f, 0x9d, 0xc9, 0x1c, 0x9c, 0x2d, 0xda, 0x9d, 0xd8, 0x46, 0x91, 0x6f, 0x60, 0x92, 0xaf, 0xee,
0x92, 0x22, 0xcf, 0x9a, 0x73, 0xc3, 0xfb, 0xce, 0x39, 0x40, 0x72, 0x0a, 0x7d, 0x2e, 0x12, 0xb1,
0xe6, 0xd1, 0x68, 0xea, 0xcd, 0xc2, 0x58, 0xaf, 0xc8, 0xd7, 0x70, 0x8a, 0x51, 0x73, 0xf1, 0x93,
0x79, 0xe9, 0x2f, 0x75, 0x9e, 0xb2, 0x08, 0x64, 0xc8, 0xf7, 0xec, 0xa2, 0xbf, 0x8a, 0xd5, 0x79,
0x99, 0x45, 0x63, 0x89, 0xd3, 0x2b, 0x99, 0x4b, 0x79, 0xe2, 0xbb, 0xf7, 0x55, 0x5e, 0xb3, 0x57,
0xf9, 0x2d, 0x8b, 0x0e, 0x75, 0x2e, 0x1d, 0x3b, 0xb2, 0x9b, 0xd6, 0x2c, 0x11, 0x0a, 0x75, 0x24,
0x51, 0x96, 0x85, 0x44, 0x30, 0xb8, 0xd1, 0xc4, 0x4e, 0xe4, 0x66, 0xb3, 0x6c, 0x74, 0xc1, 0xea,
0x8b, 0x2c, 0xab, 0xa3, 0x63, 0xa3, 0x0b, 0x65, 0xa1, 0x7f, 0x06, 0x00, 0x26, 0x19, 0x28, 0x81,
0x24, 0x4d, 0xcb, 0xf5, 0x4a, 0x48, 0xbc, 0xd2, 0x91, 0x6d, 0x42, 0xb2, 0xb8, 0x48, 0x6a, 0x21,
0x23, 0x51, 0x2a, 0x32, 0x86, 0x5d, 0xa4, 0x07, 0xbb, 0x49, 0xef, 0x20, 0x55, 0x1e, 0x7b, 0x2e,
0x52, 0x25, 0xb0, 0x23, 0x8f, 0xd0, 0x95, 0x47, 0x57, 0x92, 0xca, 0x51, 0x7f, 0x4b, 0x92, 0x2d,
0x15, 0x9a, 0xda, 0x41, 0x87, 0xda, 0x4f, 0xe1, 0xa8, 0xc1, 0xaa, 0x0c, 0x0f, 0xa5, 0x83, 0xae,
0x11, 0x53, 0xc9, 0x0c, 0x55, 0x23, 0x45, 0x82, 0xb1, 0x60, 0x9c, 0x55, 0xcd, 0x7e, 0x55, 0x17,
0x80, 0xbc, 0xc0, 0x18, 0xf0, 0x6e, 0x0c, 0x7a, 0xa9, 0x64, 0x30, 0x8a, 0xf5, 0x0a, 0xed, 0x48,
0xc7, 0x32, 0x93, 0xe4, 0x8f, 0x62, 0xbd, 0xa2, 0xaf, 0x21, 0x6a, 0x8a, 0xfb, 0x82, 0x73, 0x26,
0xe4, 0x0b, 0x34, 0x4b, 0x4f, 0x01, 0x6a, 0xf9, 0x4b, 0x46, 0xe2, 0xa9, 0x48, 0x8c, 0x85, 0x7c,
0x04, 0xc3, 0x1b, 0xb1, 0x51, 0xb9, 0x50, 0x14, 0xb5, 0x6b, 0xfa, 0xb7, 0x0f, 0x93, 0xd6, 0x71,
0x8a, 0xb9, 0x21, 0xcf, 0xa1, 0xaf, 0xb4, 0x24, 0x5d, 0x8d, 0xe7, 0x1f, 0xe8, 0x22, 0x69, 0x60,
0x57, 0x72, 0xf3, 0xfa, 0x20, 0xd6, 0x30, 0xf2, 0x0c, 0x7a, 0x18, 0xbd, 0xf4, 0x3d, 0x9e, 0x3f,
0x76, 0xe0, 0x28, 0xa7, 0xeb, 0x83, 0x58, 0x42, 0xc8, 0x17, 0x10, 0xd6, 0xac, 0x4a, 0x36, 0x52,
0x06, 0xe3, 0xf9, 0x13, 0x07, 0x1b, 0xe3, 0xde, 0xf5, 0x41, 0xac, 0x40, 0xe8, 0xf8, 0x0d, 0x63,
0x99, 0x54, 0xc2, 0xb6, 0xe3, 0xef, 0x19, 0xcb, 0xd0, 0x31, 0x42, 0xd0, 0x71, 0x5a, 0x94, 0x5c,
0x29, 0x62, 0xdb, 0xf1, 0x15, 0xee, 0xa1, 0x63, 0x09, 0xc2, 0x27, 0xde, 0x26, 0xab, 0xe4, 0xad,
0xd2, 0xc6, 0xf6, 0x13, 0x5f, 0xca, 0x4d, 0x7c, 0xa2, 0x82, 0x91, 0x09, 0xf8, 0x62, 0xa3, 0x59,
0xf4, 0xc5, 0xe6, 0x72, 0x00, 0xe1, 0x1d, 0xea, 0x8d, 0xbe, 0x30, 0xe9, 0x53, 0x87, 0x90, 0x0d,
0xbe, 0xae, 0x54, 0x3d, 0xf1, 0xc8, 0x9b, 0x06, 0x58, 0x62, 0xc6, 0x42, 0xff, 0xf2, 0xcc, 0x11,
0x95, 0xca, 0xad, 0x6e, 0xec, 0xed, 0xef, 0xc6, 0xfe, 0xc3, 0xba, 0x71, 0x70, 0x4f, 0x37, 0x36,
0x5d, 0xa8, 0x67, 0x77, 0x21, 0xba, 0x80, 0x43, 0x9b, 0xb7, 0xbd, 0x73, 0xe4, 0x89, 0xce, 0x83,
0x8e, 0x47, 0x27, 0xe5, 0x07, 0x38, 0xea, 0x30, 0xba, 0xd7, 0x8d, 0xa9, 0x06, 0xdf, 0xae, 0x06,
0xfa, 0xbb, 0x09, 0x07, 0xd9, 0x46, 0x25, 0x63, 0x3b, 0x78, 0xb5, 0xa9, 0x54, 0x92, 0xc2, 0xb8,
0x5d, 0x63, 0x28, 0x95, 0x96, 0x78, 0x80, 0xa1, 0x54, 0x4d, 0x8d, 0xdf, 0x95, 0xc5, 0xfa, 0x16,
0x1b, 0x0f, 0x9a, 0xf5, 0x8a, 0x3e, 0x37, 0x21, 0x4a, 0x6d, 0xec, 0x0b, 0x91, 0xfe, 0xe1, 0xc1,
0x71, 0xcc, 0x52, 0x96, 0x57, 0xe2, 0xc1, 0x53, 0xd6, 0x69, 0x9f, 0xfe, 0x76, 0xfb, 0x34, 0x0f,
0x0f, 0xdc, 0x36, 0xa0, 0x5b, 0x53, 0xcf, 0x6e, 0x4d, 0xf4, 0x47, 0x78, 0xe4, 0x04, 0xb1, 0x5c,
0x3c, 0x24, 0xbb, 0xda, 0x99, 0xdf, 0x71, 0x76, 0x05, 0xc7, 0x86, 0x26, 0x35, 0xed, 0x5e, 0xc0,
0xa0, 0xd6, 0x13, 0xd2, 0x93, 0x13, 0xf2, 0x54, 0x57, 0x86, 0x73, 0x6b, 0xdc, 0xc0, 0xe8, 0x97,
0x98, 0x96, 0x77, 0x6d, 0x34, 0xab, 0x37, 0xe5, 0xde, 0x54, 0xfe, 0xeb, 0xc3, 0x69, 0xcc, 0xaa,
0x36, 0xff, 0xeb, 0xba, 0x66, 0x2b, 0x21, 0x8f, 0x9a, 0x50, 0xbd, 0x4e, 0x4b, 0xfe, 0xff, 0xbf,
0x57, 0xac, 0x19, 0x1a, 0x76, 0x67, 0xe8, 0x8e, 0xa1, 0xd6, 0x7f, 0xc0, 0x97, 0xcc, 0xc0, 0x1d,
0x55, 0xa6, 0x06, 0x87, 0x9d, 0x2f, 0x01, 0x33, 0x02, 0x46, 0xf6, 0x08, 0x70, 0xa6, 0x3e, 0xb8,
0x53, 0x9f, 0x7e, 0x05, 0x27, 0x0e, 0x13, 0x1c, 0x73, 0x62, 0x12, 0xdf, 0x74, 0x23, 0xdb, 0x44,
0x7f, 0x86, 0x0f, 0x77, 0x73, 0xc1, 0xc9, 0x39, 0x84, 0x39, 0xfe, 0xd0, 0x52, 0xf8, 0xa4, 0x95,
0xc2, 0x2e, 0x78, 0xac, 0xb0, 0xf4, 0x25, 0x3c, 0xb6, 0xa2, 0xb8, 0xdc, 0x98, 0x79, 0xb7, 0x93,
0xd8, 0xae, 0x56, 0xfc, 0x2d, 0xad, 0x50, 0x98, 0x58, 0xf7, 0x2d, 0x17, 0x9c, 0x9c, 0x40, 0xb0,
0x5c, 0x34, 0x4f, 0xc1, 0x9f, 0xf4, 0x3d, 0x10, 0xeb, 0xca, 0x46, 0xca, 0xfb, 0xaa, 0x82, 0x40,
0x2f, 0x31, 0x55, 0x29, 0x7f, 0x5b, 0x51, 0x06, 0x9d, 0x28, 0x4d, 0x99, 0xf6, 0x3a, 0xfd, 0xe9,
0x02, 0x6f, 0xae, 0xdc, 0x9b, 0x3f, 0x77, 0x8b, 0x68, 0xc7, 0x67, 0x66, 0x5b, 0x3f, 0xdf, 0x62,
0xbe, 0x2a, 0xbb, 0xe9, 0xca, 0x42, 0x78, 0x06, 0x7d, 0x85, 0xd0, 0x43, 0x78, 0x87, 0x0b, 0x0d,
0xa0, 0x33, 0xe4, 0xbd, 0xf5, 0xa0, 0x3e, 0x6d, 0xda, 0x66, 0xa8, 0x46, 0x89, 0x5a, 0xd0, 0x79,
0xa7, 0xee, 0x7e, 0xe3, 0xac, 0x6e, 0x6a, 0xc7, 0x52, 0xbb, 0xd7, 0x51, 0xfb, 0x4d, 0x5f, 0xfe,
0x93, 0x71, 0xfe, 0x5f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x57, 0x52, 0x66, 0x8a, 0x76, 0x0c, 0x00,
0x00,
}
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)
}
......@@ -206,7 +206,7 @@ func (p *privacy) CheckTx(tx *types.Transaction, index int) error {
err := types.Decode(tx.Payload, &action)
if err != nil {
privacylog.Error("PrivacyTrading CheckTx", "txhash", txhashstr, "Decode tx.Payload error", err)
return err
return types.ErrActionNotSupport
}
privacylog.Debug("PrivacyTrading CheckTx", "txhash", txhashstr, "action type ", action.Ty)
assertExec := action.GetAssertExec()
......@@ -214,32 +214,32 @@ func (p *privacy) CheckTx(tx *types.Transaction, index int) error {
if token == "" {
return types.ErrInvalidParam
}
if pty.ActionPublic2Privacy == action.Ty {
if pty.ActionPublic2Privacy == action.Ty && action.GetPublic2Privacy() != nil {
return nil
}
input := action.GetInput()
output := action.GetOutput()
if input == nil || output == nil {
privacylog.Error("PrivacyTrading CheckTx", "txhash", txhashstr, "input", input, "output", output)
return nil
//无论是私对私还是私对公, input都不能为空
if len(input.GetKeyinput()) == 0 {
privacylog.Error("PrivacyTrading CheckTx", "txhash", txhashstr)
return pty.ErrNilUtxoInput
}
//如果是私到私 或者私到公,交易费扣除则需要utxo实现,交易费并不生成真正的UTXO,也是即时燃烧掉而已
var amount int64
keyinput := input.Keyinput
if action.Ty == pty.ActionPrivacy2Public && action.GetPrivacy2Public() != nil {
amount = action.GetPrivacy2Public().Amount
output := action.GetOutput()
//私对私必须有utxo输出
if action.GetPrivacy2Privacy() != nil && len(output.GetKeyoutput()) == 0 {
privacylog.Error("PrivacyTrading CheckTx", "txhash", txhashstr)
return pty.ErrNilUtxoOutput
}
// check sign
var ringSignature types.RingSignature
if err := types.Decode(tx.Signature.Signature, &ringSignature); err != nil {
privacylog.Error("PrivacyTrading CheckTx", "txhash", txhashstr, "Decode tx.Signature.Signature error ", err)
return err
return pty.ErrRingSign
}
totalInput := int64(0)
totalOutput := int64(0)
inputCnt := len(keyinput)
keyImages := make([][]byte, inputCnt)
keyinput := input.GetKeyinput()
keyImages := make([][]byte, len(keyinput))
keys := make([][]byte, 0)
pubkeys := make([][]byte, 0)
for i, input := range keyinput {
......@@ -273,18 +273,20 @@ func (p *privacy) CheckTx(tx *types.Transaction, index int) error {
cfg := p.GetAPI().GetConfig()
if !cfg.IsPara() && (assertExec == "" || assertExec == "coins") {
for _, output := range output.Keyoutput {
totalOutput += output.Amount
totalOutput := int64(0)
for _, output := range output.GetKeyoutput() {
totalOutput += output.GetAmount()
}
if tx.Fee < pty.PrivacyTxFee {
privacylog.Error("PrivacyTrading CheckTx", "txhash", txhashstr, "fee set:", tx.Fee, "required:", pty.PrivacyTxFee, " error ErrPrivacyTxFeeNotEnough")
return pty.ErrPrivacyTxFeeNotEnough
}
//如果是私到私 或者私到公,交易费扣除则需要utxo实现,交易费并不生成真正的UTXO,也是即时燃烧掉而已
var feeAmount int64
if action.Ty == pty.ActionPrivacy2Privacy {
feeAmount = totalInput - totalOutput
} else {
feeAmount = totalInput - totalOutput - amount
} else if action.Ty == pty.ActionPrivacy2Public && action.GetPrivacy2Public() != nil {
feeAmount = totalInput - totalOutput - action.GetPrivacy2Public().Amount
}
if feeAmount < pty.PrivacyTxFee {
......
// 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"
pty "github.com/33cn/plugin/plugin/dapp/privacy/types"
"github.com/stretchr/testify/assert"
)
var (
execTestCases = []*testcase{
{
index: 1,
payload: &pty.ReqCreatePrivacyTx{
Type: types.PrivacyTypePublic2Privacy,
Amount: types.Coin,
Pubkeypair: testPubkeyPairs[0],
},
},
}
)
type queryTestCase struct {
index int
funcName string
params types.Message
expectErr error
expectReply types.Message
disableReplyCheck bool
}
func testQuery(mock *testExecMock, tcArr []*queryTestCase, t *testing.T) {
for _, tc := range tcArr {
reply, err := mock.exec.Query(tc.funcName, types.Encode(tc.params))
assert.Equalf(t, tc.expectErr, err, "queryTest index=%d", tc.index)
if err == nil && !tc.disableReplyCheck {
assert.Equalf(t, tc.expectReply, reply, "queryTest index=%d", tc.index)
}
}
}
func TestPrivacy_Query_ShowAmountsOfUTXO(t *testing.T) {
mock := &testExecMock{}
mock.InitEnv()
defer mock.FreeEnv()
for _, tc := range execTestCases {
tc.testState = testStateExecLocal
}
testExec(mock, execTestCases, testPrivateKeys[0], t)
queryCases := []*queryTestCase{
{
index: 1,
params: &pty.ReqPrivacyToken{
Token: "btc",
},
expectErr: types.ErrNotFound,
},
{
index: 2,
params: &pty.ReqPrivacyToken{
Token: "bty",
},
expectReply: &pty.ReplyPrivacyAmounts{
AmountDetail: []*pty.AmountDetail{
{Amount: types.Coin, Count: 1},
},
},
},
}
for _, tc := range queryCases {
tc.funcName = "ShowAmountsOfUTXO"
}
testQuery(mock, queryCases, t)
}
func TestPrivacy_Query_ShowUTXOs4SpecifiedAmount(t *testing.T) {
mock := &testExecMock{}
mock.InitEnv()
defer mock.FreeEnv()
for _, tc := range execTestCases {
tc.testState = testStateExecLocal
}
testExec(mock, execTestCases, testPrivateKeys[0], t)
queryCases := []*queryTestCase{
{
index: 1,
params: &pty.ReqPrivacyToken{
Token: "bty",
},
expectErr: types.ErrNotFound,
},
{
index: 2,
params: &pty.ReqPrivacyToken{
Token: "bty",
Amount: types.Coin,
},
disableReplyCheck: true,
},
}
for _, tc := range queryCases {
tc.funcName = "ShowUTXOs4SpecifiedAmount"
}
testQuery(mock, queryCases, t)
}
func TestPrivacy_Query_GetUTXOGlobalIndex(t *testing.T) {
mock := &testExecMock{}
mock.InitEnv()
defer mock.FreeEnv()
for _, tc := range execTestCases {
tc.testState = testStateExecLocal
}
testExec(mock, execTestCases, testPrivateKeys[0], t)
queryCases := []*queryTestCase{
{
index: 1,
params: &pty.ReqUTXOGlobalIndex{},
disableReplyCheck: true,
},
{
index: 2,
params: &pty.ReqUTXOGlobalIndex{
Tokenname: "btc",
MixCount: 1,
Amount: []int64{types.Coin},
},
disableReplyCheck: true,
expectErr: types.ErrNotFound,
},
{
index: 3,
params: &pty.ReqUTXOGlobalIndex{
Tokenname: "bty",
MixCount: 1,
Amount: []int64{types.Coin, types.Coin * 2},
},
disableReplyCheck: true,
expectErr: types.ErrNotFound,
},
{
index: 4,
params: &pty.ReqUTXOGlobalIndex{
Tokenname: "bty",
MixCount: 1,
Amount: []int64{types.Coin},
},
disableReplyCheck: true,
},
}
for _, tc := range queryCases {
tc.funcName = "GetUTXOGlobalIndex"
}
testQuery(mock, queryCases, t)
}
func TestPrivacy_Query_GetTxsByAddr(t *testing.T) {
mock := &testExecMock{}
mock.InitEnv()
defer mock.FreeEnv()
for _, tc := range execTestCases {
tc.testState = testStateExecLocal
}
testExec(mock, execTestCases, testPrivateKeys[0], t)
queryCases := []*queryTestCase{
{
index: 1,
params: &types.ReqAddr{
Addr: testAddrs[0],
},
expectErr: types.ErrNotFound,
},
}
for _, tc := range queryCases {
tc.funcName = "GetTxsByAddr"
}
testQuery(mock, queryCases, t)
}
// 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 (
"errors"
"fmt"
"github.com/33cn/chain33/account"
"github.com/33cn/chain33/client"
"github.com/33cn/chain33/common"
"github.com/33cn/chain33/common/crypto"
dbm "github.com/33cn/chain33/common/db"
"github.com/33cn/chain33/common/log"
"github.com/33cn/chain33/queue"
"github.com/33cn/chain33/system/dapp"
"github.com/33cn/chain33/types"
"github.com/33cn/chain33/util"
"github.com/33cn/chain33/wallet"
wcom "github.com/33cn/chain33/wallet/common"
pty "github.com/33cn/plugin/plugin/dapp/privacy/types"
pwallet "github.com/33cn/plugin/plugin/dapp/privacy/wallet"
)
var (
initBalance = types.Coin * 10000
initHeight = int64(100)
// 测试的私钥
testPrivateKeys = []string{
"0x8dea7332c7bb3e3b0ce542db41161fd021e3cfda9d7dabacf24f98f2dfd69558",
"0x920976ffe83b5a98f603b999681a0bc790d97e22ffc4e578a707c2234d55cc8a",
"0xb59f2b02781678356c231ad565f73699753a28fd3226f1082b513ebf6756c15c",
}
// 测试的地址
testAddrs = []string{
"1EDDghAtgBsamrNEtNmYdQzC1QEhLkr87t",
"13cS5G1BDN2YfGudsxRxr7X25yu6ZdgxMU",
"1JSRSwp16NvXiTjYBYK9iUQ9wqp3sCxz2p",
}
// 测试的隐私公钥对
testPubkeyPairs = []string{
"92fe6cfec2e19cd15f203f83b5d440ddb63d0cb71559f96dc81208d819fea85886b08f6e874fca15108d244b40f9086d8c03260d4b954a40dfb3cbe41ebc7389",
"6326126c968a93a546d8f67d623ad9729da0e3e4b47c328a273dfea6930ffdc87bcc365822b80b90c72d30e955e7870a7a9725e9a946b9e89aec6db9455557eb",
"44bf54abcbae297baf3dec4dd998b313eafb01166760f0c3a4b36509b33d3b50239de0a5f2f47c2fc98a98a382dcd95a2c5bf1f4910467418a3c2595b853338e",
}
// exec privacy addr
execAddr = "1FeyE6VDZ4FYgpK1n2okWMDAtPkwBuooQd"
testPolicy = pwallet.New()
testPolicyName = pty.PrivacyX + "test"
testCfg = types.NewChain33Config(types.GetDefaultCfgstring())
)
func init() {
log.SetLogLevel("error")
Init(pty.PrivacyX, testCfg, nil)
wcom.RegisterPolicy(testPolicyName, testPolicy)
}
type testExecMock struct {
dbDir string
localDB dbm.KVDB
stateDB dbm.DB
exec dapp.Driver
wallet *walletMock
policy wcom.WalletBizPolicy
cfg *types.Chain33Config
q queue.Queue
qapi client.QueueProtocolAPI
}
type testcase struct {
payload types.Message
expectExecErr error
expectCheckErr error
expectExecLocalErr error
expectExecDelErr error
priv string
index int
systemCreate bool
testState int
testSign []byte
testFee int64
}
// InitEnv init env
func (mock *testExecMock) InitEnv() {
mock.cfg = testCfg
util.ResetDatadir(mock.cfg.GetModuleConfig(), "$TEMP/")
mock.q = queue.New("channel")
mock.q.SetConfig(mock.cfg)
mock.qapi, _ = client.New(mock.q.Client(), nil)
mock.initExec()
mock.initWallet()
}
func (mock *testExecMock) FreeEnv() {
util.CloseTestDB(mock.dbDir, mock.stateDB)
}
func (mock *testExecMock) initExec() {
mock.dbDir, mock.stateDB, mock.localDB = util.CreateTestDB()
exec := newPrivacy()
exec.SetAPI(mock.qapi)
exec.SetStateDB(mock.stateDB)
exec.SetLocalDB(mock.localDB)
exec.SetEnv(100, 1539918074, 1539918074)
mock.exec = exec
}
func (mock *testExecMock) initWallet() {
mock.wallet = &walletMock{}
mock.wallet.Wallet = wallet.New(mock.cfg)
mock.policy = testPolicy
mock.wallet.SetQueueClient(mock.q.Client())
mock.policy.Init(mock.wallet, nil)
seed, _ := mock.wallet.GenSeed(1)
mock.wallet.SaveSeed("abcd1234", seed.Seed)
mock.wallet.ProcWalletUnLock(&types.WalletUnLock{Passwd: "abcd1234"})
accCoin := account.NewCoinsAccount(mock.cfg)
accCoin.SetDB(mock.stateDB)
for index, addr := range testAddrs {
account := &types.Account{
Balance: initBalance,
Addr: addr,
}
accCoin.SaveAccount(account)
accCoin.SaveExecAccount(execAddr, account)
privBytes, _ := common.FromHex(testPrivateKeys[index])
bpriv := wcom.CBCEncrypterPrivkey([]byte(mock.wallet.Password), privBytes)
was := &types.WalletAccountStore{
Privkey: common.ToHex(bpriv),
Label: fmt.Sprintf("label%d", index),
Addr: addr,
TimeStamp: types.Now().String(),
}
mock.wallet.SetWalletAccount(false, addr, was)
}
mock.wallet.GetAPI().ExecWalletFunc(testPolicyName, "EnablePrivacy", &pty.ReqEnablePrivacy{Addrs: testAddrs})
}
func (mock *testExecMock) addBlockTx(tx *types.Transaction, receipt *types.ReceiptData) {
block := &types.BlockDetail{
Block: &types.Block{
Height: initHeight,
},
Receipts: []*types.ReceiptData{receipt},
}
batch := mock.wallet.GetDBStore().NewBatch(true)
defer batch.Write()
mock.policy.OnAddBlockTx(block, tx, 0, batch)
}
func createTx(mock *testExecMock, payload types.Message, priv string, systemCreate bool) (*types.Transaction, error) {
c, err := crypto.New(crypto.GetName(types.SECP256K1))
if err != nil {
return nil, err
}
bytes, err := common.FromHex(priv[:])
if err != nil {
return nil, err
}
privKey, err := c.PrivKeyFromBytes(bytes)
if err != nil {
return nil, err
}
if systemCreate {
action, _ := buildAction(payload)
tx, err := types.CreateFormatTx(mock.cfg, mock.cfg.ExecName(pty.PrivacyX), types.Encode(action))
if err != nil {
return nil, err
}
tx.Sign(int32(types.SECP256K1), privKey)
return tx, nil
}
req := payload.(*pty.ReqCreatePrivacyTx)
if req.GetAssetExec() == "" {
req.AssetExec = "coins"
}
reply, err := mock.wallet.GetAPI().ExecWalletFunc(testPolicyName, "CreateTransaction", payload)
if err != nil {
return nil, errors.New("createTxErr:" + err.Error())
}
signTxReq := &types.ReqSignRawTx{
TxHex: common.ToHex(types.Encode(reply)),
}
_, signTx, err := mock.policy.SignTransaction(privKey, signTxReq)
if err != nil {
return nil, errors.New("signPrivacyTxErr:" + err.Error())
}
signTxBytes, _ := common.FromHex(signTx)
tx := &types.Transaction{}
err = types.Decode(signTxBytes, tx)
if err != nil {
return nil, err
}
return tx, nil
}
func buildAction(param types.Message) (types.Message, error) {
action := &pty.PrivacyAction{
Value: nil,
Ty: 0,
}
if val, ok := param.(*pty.Public2Privacy); ok {
action.Value = &pty.PrivacyAction_Public2Privacy{Public2Privacy: val}
action.Ty = pty.ActionPublic2Privacy
} else if val, ok := param.(*pty.Privacy2Privacy); ok {
action.Value = &pty.PrivacyAction_Privacy2Privacy{Privacy2Privacy: val}
action.Ty = pty.ActionPrivacy2Privacy
} else if val, ok := param.(*pty.Privacy2Public); ok {
action.Value = &pty.PrivacyAction_Privacy2Public{Privacy2Public: val}
action.Ty = pty.ActionPrivacy2Public
} else {
return nil, types.ErrActionNotSupport
}
return action, nil
}
type walletMock struct {
*wallet.Wallet
}
func (w *walletMock) GetBlockHeight() int64 {
return initHeight + types.PrivacyMaturityDegree
}
......@@ -20,4 +20,7 @@ var (
ErrOutputIndex = errors.New("ErrOutputIndex")
ErrPubkeysOfUTXO = errors.New("ErrPubkeysOfUTXO")
ErrRecoverUTXO = errors.New("ErrRecoverUTXO")
ErrNilUtxoInput = errors.New("ErrNilUtxoInput")
ErrNilUtxoOutput = errors.New("ErrNilUtxoOutput")
ErrRingSign = errors.New("ErrRingSign")
)
......@@ -231,7 +231,7 @@ func (store *privacyStore) getWalletPrivacyTxDetails(param *privacytypes.ReqPriv
} else {
keyPrefix = calcRecvPrivacyTxKey(param.Tokenname, param.Address, "")
}
txkeybytes := list.IteratorScanFromLast(keyPrefix, param.Count)
txkeybytes := list.IteratorScanFromLast(keyPrefix, param.Count, db.ListDESC)
for _, keybyte := range txkeybytes {
value, err := store.Get(keybyte)
if err != nil {
......
......@@ -36,7 +36,7 @@ func (t *trade) ExecDelLocal_RevokeBuy(revoke *pty.TradeForRevokeBuy, tx *types.
func (t *trade) localDelLog(tx *types.Transaction, receipt *types.ReceiptData, index int, tradedBoardlot int64) (*types.LocalDBSet, error) {
var set types.LocalDBSet
table := NewOrderTable(t.GetLocalDB())
table := NewOrderTableV2(t.GetLocalDB())
txIndex := dapp.HeightIndexStr(t.GetHeight(), int64(index))
for i := 0; i < len(receipt.Logs); i++ {
......@@ -47,51 +47,46 @@ func (t *trade) localDelLog(tx *types.Transaction, receipt *types.ReceiptData, i
if err != nil {
panic(err) //数据错误了,已经被修改了
}
kv := t.deleteSell(receipt.Base, item.Ty, tx, txIndex, table, tradedBoardlot)
set.KV = append(set.KV, kv...)
t.deleteSell(receipt.Base, item.Ty, tx, txIndex, table, tradedBoardlot)
} else if item.Ty == pty.TyLogTradeSellRevoke {
var receipt pty.ReceiptTradeSellRevoke
err := types.Decode(item.Log, &receipt)
if err != nil {
panic(err) //数据错误了,已经被修改了
}
kv := t.deleteSell(receipt.Base, item.Ty, tx, txIndex, table, tradedBoardlot)
set.KV = append(set.KV, kv...)
t.deleteSell(receipt.Base, item.Ty, tx, txIndex, table, tradedBoardlot)
} else if item.Ty == pty.TyLogTradeBuyMarket {
var receipt pty.ReceiptTradeBuyMarket
err := types.Decode(item.Log, &receipt)
if err != nil {
panic(err) //数据错误了,已经被修改了
}
kv := t.deleteBuy(receipt.Base, txIndex, table)
set.KV = append(set.KV, kv...)
t.deleteBuy(receipt.Base, txIndex, table)
} else if item.Ty == pty.TyLogTradeBuyRevoke {
var receipt pty.ReceiptTradeBuyRevoke
err := types.Decode(item.Log, &receipt)
if err != nil {
panic(err) //数据错误了,已经被修改了
}
kv := t.deleteBuyLimit(receipt.Base, item.Ty, tx, txIndex, table, tradedBoardlot)
set.KV = append(set.KV, kv...)
t.deleteBuyLimit(receipt.Base, item.Ty, tx, txIndex, table, tradedBoardlot)
} else if item.Ty == pty.TyLogTradeBuyLimit {
var receipt pty.ReceiptTradeBuyLimit
err := types.Decode(item.Log, &receipt)
if err != nil {
panic(err) //数据错误了,已经被修改了
}
kv := t.deleteBuyLimit(receipt.Base, item.Ty, tx, txIndex, table, tradedBoardlot)
set.KV = append(set.KV, kv...)
t.deleteBuyLimit(receipt.Base, item.Ty, tx, txIndex, table, tradedBoardlot)
} else if item.Ty == pty.TyLogTradeSellMarket {
var receipt pty.ReceiptSellMarket
err := types.Decode(item.Log, &receipt)
if err != nil {
panic(err) //数据错误了,已经被修改了
}
kv := t.deleteSellMarket(receipt.Base, txIndex, table)
set.KV = append(set.KV, kv...)
t.deleteSellMarket(receipt.Base, txIndex, table)
}
}
newKvs, err := table.Save()
debugTableKV(newKvs, "exec_del_local orderV2 kvs")
if err != nil {
tradelog.Error("trade table.Save failed", "error", err)
return nil, err
......
......@@ -36,9 +36,8 @@ func (t *trade) ExecLocal_RevokeBuy(revoke *pty.TradeForRevokeBuy, tx *types.Tra
func (t *trade) localAddLog(tx *types.Transaction, receipt *types.ReceiptData, index int) (*types.LocalDBSet, error) {
var set types.LocalDBSet
table := NewOrderTable(t.GetLocalDB())
table := NewOrderTableV2(t.GetLocalDB())
txIndex := dapp.HeightIndexStr(t.GetHeight(), int64(index))
for i := 0; i < len(receipt.Logs); i++ {
item := receipt.Logs[i]
if item.Ty == pty.TyLogTradeSellLimit {
......@@ -47,24 +46,21 @@ func (t *trade) localAddLog(tx *types.Transaction, receipt *types.ReceiptData, i
if err != nil {
panic(err) //数据错误了,已经被修改了
}
kv := t.saveSell(receipt.Base, item.Ty, tx, txIndex, table)
set.KV = append(set.KV, kv...)
t.saveSell(receipt.Base, item.Ty, tx, txIndex, table)
} else if item.Ty == pty.TyLogTradeSellRevoke {
var receipt pty.ReceiptTradeSellRevoke
err := types.Decode(item.Log, &receipt)
if err != nil {
panic(err) //数据错误了,已经被修改了
}
kv := t.saveSell(receipt.Base, item.Ty, tx, txIndex, table)
set.KV = append(set.KV, kv...)
t.saveSell(receipt.Base, item.Ty, tx, txIndex, table)
} else if item.Ty == pty.TyLogTradeBuyMarket {
var receipt pty.ReceiptTradeBuyMarket
err := types.Decode(item.Log, &receipt)
if err != nil {
panic(err) //数据错误了,已经被修改了
}
kv := t.saveBuy(receipt.Base, tx, txIndex, table)
set.KV = append(set.KV, kv...)
t.saveBuy(receipt.Base, tx, txIndex, table)
} else if item.Ty == pty.TyLogTradeBuyRevoke {
var receipt pty.ReceiptTradeBuyRevoke
err := types.Decode(item.Log, &receipt)
......@@ -72,8 +68,7 @@ func (t *trade) localAddLog(tx *types.Transaction, receipt *types.ReceiptData, i
panic(err) //数据错误了,已经被修改了
}
kv := t.saveBuyLimit(receipt.Base, item.Ty, tx, txIndex, table)
set.KV = append(set.KV, kv...)
t.saveBuyLimit(receipt.Base, item.Ty, tx, txIndex, table)
} else if item.Ty == pty.TyLogTradeBuyLimit {
var receipt pty.ReceiptTradeBuyLimit
err := types.Decode(item.Log, &receipt)
......@@ -81,20 +76,18 @@ func (t *trade) localAddLog(tx *types.Transaction, receipt *types.ReceiptData, i
panic(err) //数据错误了,已经被修改了
}
kv := t.saveBuyLimit(receipt.Base, item.Ty, tx, txIndex, table)
set.KV = append(set.KV, kv...)
t.saveBuyLimit(receipt.Base, item.Ty, tx, txIndex, table)
} else if item.Ty == pty.TyLogTradeSellMarket {
var receipt pty.ReceiptSellMarket
err := types.Decode(item.Log, &receipt)
if err != nil {
panic(err) //数据错误了,已经被修改了
}
kv := t.saveSellMarket(receipt.Base, tx, txIndex, table)
//tradelog.Info("saveSellMarket", "kv", kv)
set.KV = append(set.KV, kv...)
t.saveSellMarket(receipt.Base, tx, txIndex, table)
}
}
newKvs, err := table.Save()
debugTableKV(newKvs, "exec_local orderV2 kvs")
if err != nil {
tradelog.Error("trade table.Save failed", "error", err)
return nil, err
......@@ -106,3 +99,10 @@ func (t *trade) localAddLog(tx *types.Transaction, receipt *types.ReceiptData, i
}
return &set, nil
}
func debugTableKV(kvs []*types.KeyValue, msg string) {
tradelog.Debug("table save debug:"+msg, "count", len(kvs))
for i, kv := range kvs {
tradelog.Debug("table save debug:"+msg, "i", i, "key", string(kv.Key), "value", string(kv.Value))
}
}
......@@ -4,74 +4,11 @@
package executor
import (
"fmt"
"strconv"
"github.com/33cn/chain33/types"
pty "github.com/33cn/plugin/plugin/dapp/trade/types"
)
const (
sellOrderSHTAS = "LODB-trade-sellorder-shtas:"
sellOrderASTS = "LODB-trade-sellorder-asts:"
sellOrderATSS = "LODB-trade-sellorder-atss:"
sellOrderTSPAS = "LODB-trade-sellorder-tspas:"
buyOrderSHTAS = "LODB-trade-buyorder-shtas:"
buyOrderASTS = "LODB-trade-buyorder-asts:"
buyOrderATSS = "LODB-trade-buyorder-atss:"
buyOrderTSPAS = "LODB-trade-buyorder-tspas:"
sellIDPrefix = "mavl-trade-sell-"
buyIDPrefix = "mavl-trade-buy-"
// Addr-Status-Type-Height-Key
orderASTHK = "LODB-trade-order-asthk:"
sellIDPrefix = "mavl-trade-sell-"
buyIDPrefix = "mavl-trade-buy-"
)
// sell order 4 key, 4prefix
// 特定状态下的卖单
func calcTokenSellOrderKey(token string, addr string, status int32, sellOrderID string, height int64) []byte {
key := fmt.Sprintf(sellOrderSHTAS+"%d:%d:%s:%s:%s", status, height, token, addr, sellOrderID)
return []byte(key)
}
// 特定账户下特定状态的卖单
func calcOnesSellOrderKeyStatus(token string, addr string, status int32, sellOrderID string) []byte {
key := fmt.Sprintf(sellOrderASTS+"%s:%d:%s:%s", addr, status, token, sellOrderID)
return []byte(key)
}
// 特定账户下特定token的卖单
func calcOnesSellOrderKeyToken(token string, addr string, status int32, sellOrderID string) []byte {
key := fmt.Sprintf(sellOrderATSS+"%s:%s:%d:%s", addr, token, status, sellOrderID)
return []byte(key)
}
// 指定token的卖单, 带上价格方便排序
func calcTokensSellOrderKeyStatus(token string, status int32, price int64, addr string, sellOrderID string) []byte {
key := fmt.Sprintf(sellOrderTSPAS+"%s:%d:%016d:%s:%s", token, status, price, addr, sellOrderID)
return []byte(key)
}
func calcTokensSellOrderPrefixStatus(token string, status int32) []byte {
prefix := fmt.Sprintf(sellOrderTSPAS+"%s:%d:", token, status)
return []byte(prefix)
}
// 特定账户下指定token的卖单
func calcOnesSellOrderPrefixToken(token string, addr string) []byte {
key := fmt.Sprintf(sellOrderATSS+"%s:%s", addr, token)
return []byte(key)
}
// 特定账户下的卖单
func calcOnesSellOrderPrefixAddr(addr string) []byte {
return []byte(fmt.Sprintf(sellOrderASTS+"%s", addr))
}
func calcOnesSellOrderPrefixStatus(addr string, status int32) []byte {
return []byte(fmt.Sprintf(sellOrderASTS+"%s:%d", addr, status))
}
// ids
func calcTokenSellID(hash string) string {
return sellIDPrefix + hash
......@@ -81,104 +18,6 @@ func calcTokenBuyID(hash string) string {
return buyIDPrefix + hash
}
// buy limit order 4 key, 4prefix
// 特定状态下的买单
func calcTokenBuyOrderKey(token string, addr string, status int32, orderID string, height int64) []byte {
key := fmt.Sprintf(buyOrderSHTAS+"%d:%d:%s:%s:%s", status, height, token, addr, orderID)
return []byte(key)
}
// 特定账户下特定状态的买单
func calcOnesBuyOrderKeyStatus(token string, addr string, status int32, orderID string) []byte {
key := fmt.Sprintf(buyOrderASTS+"%s:%d:%s:%s", addr, status, token, orderID)
return []byte(key)
}
// 特定账户下特定token的买单
func calcOnesBuyOrderKeyToken(token string, addr string, status int32, orderID string) []byte {
key := fmt.Sprintf(buyOrderATSS+"%s:%s:%d:%s", addr, token, status, orderID)
return []byte(key)
}
// 指定token的卖单, 带上价格方便排序
func calcTokensBuyOrderKeyStatus(token string, status int32, price int64, addr string, orderID string) []byte {
key := fmt.Sprintf(buyOrderTSPAS+"%s:%d:%016d:%s:%s", token, status, price, addr, orderID)
return []byte(key)
}
func calcTokensBuyOrderPrefixStatus(token string, status int32) []byte {
prefix := fmt.Sprintf(buyOrderTSPAS+"%s:%d:", token, status)
return []byte(prefix)
}
// 特定账户下指定token的买单
func calcOnesBuyOrderPrefixToken(token string, addr string) []byte {
key := fmt.Sprintf(buyOrderATSS+"%s:%s", addr, token)
return []byte(key)
}
// 特定账户下的买单
func calcOnesBuyOrderPrefixAddr(addr string) []byte {
return []byte(fmt.Sprintf(buyOrderASTS+"%s", addr))
}
func calcOnesBuyOrderPrefixStatus(addr string, status int32) []byte {
return []byte(fmt.Sprintf(buyOrderASTS+"%s:%d", addr, status))
}
// 特定帐号下的订单
// 这里状态进行转化, 分成 状态和类型, 状态三种, 类型 两种
// on: OnSale OnBuy
// done: Soldout boughtOut
// revoke: RevokeSell RevokeBuy
// buy/sell 两种类型
// 目前页面是按addr, 状态来
func calcOnesOrderKey(addr string, status int32, ty int32, height int64, key string) []byte {
return []byte(fmt.Sprintf(orderASTHK+"%s:%d:%010d:%d:%s", addr, status, height, ty, key))
}
// 特定状态下的买单
//func calcTokenBuyOrderPrefixStatus(status int32) []byte {
// return []byte(fmt.Sprintf(buyOrderSHTAS+"%d", status))
//}
func genSellMarketOrderKeyValue(kv []*types.KeyValue, receipt *pty.ReceiptSellBase, status int32,
height int64, value []byte) []*types.KeyValue {
keyID := receipt.TxHash
newkey := calcTokenSellOrderKey(receipt.TokenSymbol, receipt.Owner, status, keyID, height)
kv = append(kv, &types.KeyValue{Key: newkey, Value: value})
newkey = calcOnesSellOrderKeyStatus(receipt.TokenSymbol, receipt.Owner, status, keyID)
kv = append(kv, &types.KeyValue{Key: newkey, Value: value})
newkey = calcOnesSellOrderKeyToken(receipt.TokenSymbol, receipt.Owner, status, keyID)
kv = append(kv, &types.KeyValue{Key: newkey, Value: value})
priceBoardlot, err := strconv.ParseFloat(receipt.PricePerBoardlot, 64)
if err != nil {
panic(err)
}
priceBoardlotInt64 := int64(priceBoardlot * float64(types.TokenPrecision))
AmountPerBoardlot, err := strconv.ParseFloat(receipt.AmountPerBoardlot, 64)
if err != nil {
panic(err)
}
AmountPerBoardlotInt64 := int64(AmountPerBoardlot * float64(types.Coin))
price := calcPriceOfToken(priceBoardlotInt64, AmountPerBoardlotInt64)
newkey = calcTokensSellOrderKeyStatus(receipt.TokenSymbol, status,
price, receipt.Owner, keyID)
kv = append(kv, &types.KeyValue{Key: newkey, Value: value})
st, ty := fromStatus(status)
newkey = calcOnesOrderKey(receipt.Owner, st, ty, height, keyID)
kv = append(kv, &types.KeyValue{Key: newkey, Value: value})
return kv
}
// make a number as token's price whether cheap or dear
// support 1e8 bty pre token or 1/1e8 bty pre token, [1Coins, 1e16Coins]
// the number in key is used to sort buy orders and pages
......
......@@ -171,6 +171,7 @@ func NewOrderTable(kvdb dbm.KV) *table.Table {
return t
}
// gen order from tx and receipt
func (t *trade) genSellLimit(tx *types.Transaction, sell *pty.ReceiptSellBase,
sellorder *pty.SellOrder, txIndex string) *pty.LocalOrder {
......@@ -272,7 +273,6 @@ func parseOrderPriceFloat(s string) int64 {
}
func (t *trade) genSellMarket(tx *types.Transaction, sell *pty.ReceiptSellBase, txIndex string) *pty.LocalOrder {
order := &pty.LocalOrder{
AssetSymbol: sell.TokenSymbol,
TxIndex: txIndex,
......@@ -300,7 +300,6 @@ func (t *trade) genSellMarket(tx *types.Transaction, sell *pty.ReceiptSellBase,
}
func (t *trade) genBuyLimit(tx *types.Transaction, buy *pty.ReceiptBuyBase, txIndex string) *pty.LocalOrder {
order := &pty.LocalOrder{
AssetSymbol: buy.TokenSymbol,
TxIndex: txIndex,
......@@ -375,7 +374,6 @@ func (t *trade) rollbackBuyLimit(tx *types.Transaction, buy *pty.ReceiptBuyBase,
}
func (t *trade) genBuyMarket(tx *types.Transaction, buy *pty.ReceiptBuyBase, txIndex string) *pty.LocalOrder {
order := &pty.LocalOrder{
AssetSymbol: buy.TokenSymbol,
TxIndex: txIndex,
......@@ -392,7 +390,7 @@ func (t *trade) genBuyMarket(tx *types.Transaction, buy *pty.ReceiptBuyBase, txI
Height: buy.Height,
Key: calcTokenBuyID(hex.EncodeToString(tx.Hash())),
BlockTime: t.GetBlockTime(),
IsSellOrder: true,
IsSellOrder: false,
AssetExec: buy.AssetExec,
IsFinished: true,
PriceExec: buy.PriceExec,
......@@ -400,63 +398,3 @@ func (t *trade) genBuyMarket(tx *types.Transaction, buy *pty.ReceiptBuyBase, txI
}
return order
}
func list(db dbm.KVDB, indexName string, data *pty.LocalOrder, count, direction int32) ([]*table.Row, error) {
query := NewOrderTable(db).GetQuery(db)
var primary []byte
if len(data.TxIndex) > 0 {
primary = []byte(data.TxIndex)
}
cur := &OrderRow{LocalOrder: data}
index, err := cur.Get(indexName)
if err != nil {
tradelog.Error("query List failed", "key", string(primary), "param", data, "err", err)
return nil, err
}
tradelog.Debug("query List dbg", "indexName", indexName, "index", string(index), "primary", primary, "count", count, "direction", direction)
rows, err := query.ListIndex(indexName, index, primary, count, direction)
if err != nil {
tradelog.Error("query List failed", "key", string(primary), "param", data, "err", err)
return nil, err
}
if len(rows) == 0 {
return nil, types.ErrNotFound
}
return rows, nil
}
/*
按 资产 查询 :
按 资产 & 地址 查询
按 地址
排序和分类
1. 时间顺序 txindex
1. 分类, 不同的状态 & 不同的性质: 买/卖
交易 -> 订单 按订单来 (交易和订单是多对多的关系,不适合joinTable)
交易 T1 Create -> T2 part-take -> T3 Revoke
订单左为进行中, 右为完成,
订单 (C1) | () -> (C1m) | (C2) -> () | (C2, C1r)
查询交易 / 查询订单
C -> C/M -> C/D
\
\ ->R
状态 1, TradeOrderStatusOnSale, 在售
状态 2: TradeOrderStatusSoldOut,售完
状态 3: TradeOrderStatusRevoked, 卖单被撤回
状态 4: TradeOrderStatusExpired, 订单超时(目前不支持订单超时)
状态 5: TradeOrderStatusOnBuy, 求购
状态 6: TradeOrderStatusBoughtOut, 购买完成
状态 7: TradeOrderStatusBuyRevoked, 买单被撤回
*/
......@@ -13,7 +13,7 @@ import (
)
var order1 = &pty.LocalOrder{
AssetSymbol: "A",
AssetSymbol: "bty",
Owner: "O1",
AmountPerBoardlot: 1,
MinBoardlot: 1,
......@@ -28,13 +28,15 @@ var order1 = &pty.LocalOrder{
Key: "B1",
BlockTime: 1,
IsSellOrder: false,
AssetExec: "a",
AssetExec: "coins",
TxIndex: dapp.HeightIndexStr(1, 1),
IsFinished: false,
PriceExec: "token",
PriceSymbol: "CCNY",
}
var order2 = &pty.LocalOrder{
AssetSymbol: "A",
AssetSymbol: "bty",
Owner: "O1",
AmountPerBoardlot: 1,
MinBoardlot: 1,
......@@ -49,9 +51,32 @@ var order2 = &pty.LocalOrder{
Key: "B2",
BlockTime: 2,
IsSellOrder: false,
AssetExec: "a",
AssetExec: "coins",
TxIndex: dapp.HeightIndexStr(2, 1),
IsFinished: false,
PriceExec: "token",
PriceSymbol: "CCNY",
}
// 两个fork前的数据
var order3 = &pty.LocalOrder{
AssetSymbol: "CCNY",
Owner: "O1",
AmountPerBoardlot: 1,
MinBoardlot: 1,
PricePerBoardlot: 1,
TotalBoardlot: 10,
TradedBoardlot: 0,
BuyID: "B2",
Status: pty.TradeOrderStatusOnBuy,
SellID: "",
TxHash: nil,
Height: 3,
Key: "B2",
BlockTime: 3,
IsSellOrder: false,
TxIndex: dapp.HeightIndexStr(3, 1),
IsFinished: false,
}
func TestListAll(t *testing.T) {
......@@ -65,3 +90,15 @@ func TestListAll(t *testing.T) {
t.Log(kvs)
ldb.Close()
}
func TestListV2All(t *testing.T) {
dir, ldb, tdb := util.CreateTestDB()
t.Log(dir, ldb, tdb)
odb := NewOrderTableV2(tdb)
odb.Add(order1)
odb.Add(order2)
kvs, err := odb.Save()
assert.Nil(t, err)
t.Log(kvs)
ldb.Close()
}
// Copyright Fuzamei Corp. 2018 All Rights Reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package executor
import (
"fmt"
dbm "github.com/33cn/chain33/common/db"
"github.com/33cn/chain33/common/db/table"
"github.com/33cn/chain33/types"
pty "github.com/33cn/plugin/plugin/dapp/trade/types"
)
// 本地数据版本
// 1. v0 手动生成
// 2. v1 用table生成 LocalOrder
// 3. v2 用table生成 LocalOrderV2 比v1 用更多的索引,支持v0需要的数据索引,即将v2 包含 v0 v1 数据
// 预期在6.4升级后 v0 格式将不存在
/*
现有接口
1. 查询地址对应的买单 (无分页)
1.1 只指定地址 -> owner
1.2 同时指定地址和token -> owner_asset
1.3 显示一个用户成交的所有买单 -> owner
1.4 显示一个用户成交的指定一个或者多个token所有买单 -> owner_asset 不支持多个
2. 分状态查询地址的买单: 状态 地址 (无分页) -> owner_status
3. 显示一个token 指定数量的买单 GetTokenBuyOrderByStatus -> asset_inBuy_status
4. 显示指定token出售者的一个或多个token 或 不指定token 的卖单 (无分页) -> owner_asset/owner_asset_isSell 不支持多个
5. 显示指定状态下的某地址卖单 (无分页) -> owner_isSell_status
6. 显示一个token 指定数量的卖单 -> asset_isSell
7. 根据状态分页列出某地址的订单(包括买单卖单) owner_status
*/
//
var optV2 = &table.Option{
Prefix: "LODB-trade",
Name: "order_v2",
Primary: "txIndex",
// asset 指定交易对 price_exec + price_symbol + asset_exec+asset_symbol
// status: 设计为可以同时查询几种的并集 , 存储为前缀, 需要提前设计需要合并的, 用前缀表示
// 进行中, 撤销, 部分成交 , 全部成交, 完成状态统一前缀. 数字和原来不一样
// 00 10 11 12 1*
// 排序特点: 在不用key排序时,需要生成排序用的组合索引, 前面n个索引用来区分前缀, 后一个索引用来排序
Index: []string{
"key", // 内部查询用
"asset", // 按资产统计订单
"asset_isSell_status", // 接口 3
// "asset_status", 可能需求, 用于资产的交易历史
// "asset_isSell",
"owner", // 接口 1.1, 1.3
"owner_asset", // 接口 1.2, 1.4, 4, 7
"owner_asset_isSell", // 接口 4
"owner_asset_status", // 新需求, 在
"owner_isSell", // 接口 6
// "owner_isSell_statusPrefix", // 状态可以定制组合, 成交历史需求
"owner_status", // 接口 2
"assset_isSell_isFinished", // 用 isFinish, 进行订单是否完成的列表功能
"owner_asset_isFinished",
"owner_isFinished",
// "owner_statusPrefix", // 状态可以定制组合 , 成交历史需求
// 增加更多的key, 把老接口的数据的key 也生成,可以去掉老接口的实现
// https://chain.33.cn/document/105 文档1.8 sell & asset-price & status, order by price
// https://chain.33.cn/document/105 文档1.3 buy & asset-price & status, order by price
"asset_isSell_status_price",
// 文档1.2 文档1.5 按 用户状态来 addr-status buy or sell
"owner_isSell_status",
},
}
// OrderV2Row order row
type OrderV2Row struct {
*pty.LocalOrder
}
// NewOrderV2Row create row
func NewOrderV2Row() *OrderV2Row {
return &OrderV2Row{LocalOrder: nil}
}
// CreateRow create row
func (r *OrderV2Row) CreateRow() *table.Row {
return &table.Row{Data: &pty.LocalOrder{}}
}
// SetPayload set payload
func (r *OrderV2Row) SetPayload(data types.Message) error {
if d, ok := data.(*pty.LocalOrder); ok {
r.LocalOrder = d
return nil
}
return types.ErrTypeAsset
}
// Get get index key
func (r *OrderV2Row) Get(key string) ([]byte, error) {
switch key {
case "txIndex":
return []byte(r.TxIndex), nil
case "key":
return []byte(r.Key), nil
case "asset":
return []byte(r.asset()), nil
case "asset_isSell_status":
return []byte(fmt.Sprintf("%s_%d_%s", r.asset(), r.isSell(), r.status())), nil
case "owner":
return []byte(r.Owner), nil
case "owner_asset":
return []byte(fmt.Sprintf("%s_%s", r.Owner, r.asset())), nil
case "owner_asset_isSell":
return []byte(fmt.Sprintf("%s_%s_%d", r.Owner, r.asset(), r.isSell())), nil
case "owner_asset_status":
return []byte(fmt.Sprintf("%s_%s_%s", r.Owner, r.asset(), r.status())), nil
case "owner_isSell":
return []byte(fmt.Sprintf("%s_%d", r.Owner, r.isSell())), nil
case "owner_isSell_status":
return []byte(fmt.Sprintf("%s_%d_%s", r.Owner, r.isSell(), r.status())), nil
case "owner_status":
return []byte(fmt.Sprintf("%s_%s", r.Owner, r.status())), nil
//case "owner_statusPrefix":
// return []byte(fmt.Sprintf("%s_%d", r.Owner, r.isSell())), nil
case "assset_isSell_isFinished":
return []byte(fmt.Sprintf("%s_%d_%d", r.Owner, r.isSell(), r.isFinished())), nil
case "owner_asset_isFinished":
return []byte(fmt.Sprintf("%s_%s_%d", r.Owner, r.asset(), r.isFinished())), nil
case "owner_isFinished":
return []byte(fmt.Sprintf("%s_%d", r.Owner, r.isFinished())), nil
case "asset_isSell_status_price":
return []byte(fmt.Sprintf("%s_%d_%s_%s", r.asset(), r.isSell(), r.status(), r.price())), nil
default:
return nil, types.ErrNotFound
}
}
// 老接口查询参数: Price 用主币
func (r *OrderV2Row) asset() string {
return r.LocalOrder.PriceExec + "." + r.LocalOrder.PriceSymbol + "_" + r.LocalOrder.AssetExec + "." + r.LocalOrder.AssetSymbol
}
func (r *OrderV2Row) isSell() int {
if r.IsSellOrder {
return 1
}
return 0
}
func (r *OrderV2Row) isFinished() int {
if r.IsFinished {
return 1
}
return 0
}
func (r *OrderV2Row) price() string {
// 在计算前缀时,返回空
if r.AmountPerBoardlot == 0 {
return ""
}
p := calcPriceOfToken(r.PricePerBoardlot, r.AmountPerBoardlot)
return fmt.Sprintf("%018d", p)
}
// status: 设计为可以同时查询几种的并集 , 存储为前缀, 需要提前设计需要合并的, 用前缀表示
// 进行中, 撤销, 部分成交 , 全部成交, 完成状态统一前缀. 数字和原来不一样
// 01 10 11 12 19 -> 1*
func (r *OrderV2Row) status() string {
if r.Status == pty.TradeOrderStatusOnBuy || r.Status == pty.TradeOrderStatusOnSale {
return "01" // 试图用1 可以匹配所有完成的
} else if r.Status == pty.TradeOrderStatusSoldOut || r.Status == pty.TradeOrderStatusBoughtOut {
return "12"
} else if r.Status == pty.TradeOrderStatusRevoked || r.Status == pty.TradeOrderStatusBuyRevoked {
return "10"
} else if r.Status == pty.TradeOrderStatusSellHalfRevoked || r.Status == pty.TradeOrderStatusBuyHalfRevoked {
return "11"
} else if r.Status == pty.TradeOrderStatusGroupComplete {
return "1" // 1* match complete
}
return "XX"
}
// NewOrderTableV2 create order table
func NewOrderTableV2(kvdb dbm.KV) *table.Table {
rowMeta := NewOrderV2Row()
rowMeta.SetPayload(&pty.LocalOrder{})
t, err := table.NewTable(rowMeta, kvdb, optV2)
if err != nil {
panic(err)
}
return t
}
func listV2(db dbm.KVDB, indexName string, data *pty.LocalOrder, count, direction int32) ([]*table.Row, error) {
query := NewOrderTableV2(db).GetQuery(db)
var primary []byte
if len(data.TxIndex) > 0 {
primary = []byte(data.TxIndex)
}
cur := &OrderV2Row{LocalOrder: data}
index, err := cur.Get(indexName)
if err != nil {
tradelog.Error("query List failed", "key", string(primary), "param", data, "err", err)
return nil, err
}
tradelog.Debug("query List dbg", "indexName", indexName, "index", string(index), "primary", primary, "count", count, "direction", direction)
rows, err := query.ListIndex(indexName, index, primary, count, direction)
if err != nil {
tradelog.Error("query List failed", "key", string(primary), "param", data, "err", err)
return nil, err
}
if len(rows) == 0 {
return nil, types.ErrNotFound
}
return rows, nil
}
package executor
import (
"strconv"
dbm "github.com/33cn/chain33/common/db"
"github.com/33cn/chain33/types"
pty "github.com/33cn/plugin/plugin/dapp/trade/types"
"github.com/pkg/errors"
)
// 将手动生成的local db 的代码和用table 生成的local db的代码分离出来
// 手动生成的local db, 将不生成任意资产标价的数据, 保留用coins 生成交易的数据, 来兼容为升级的app 应用
// 希望有全量数据的, 需要调用新的rpc
// sell limit
func genSaveSellKv(sellorder *pty.SellOrder) []*types.KeyValue {
if sellorder.PriceExec != "" && sellorder.PriceExec != defaultPriceExec {
return nil
}
status := sellorder.Status
var kv []*types.KeyValue
kv = saveSellOrderKeyValue(kv, sellorder, status)
if pty.TradeOrderStatusSoldOut == status || pty.TradeOrderStatusRevoked == status {
tradelog.Debug("trade saveSell ", "remove old status onsale to soldout or revoked with sellid", sellorder.SellID)
kv = deleteSellOrderKeyValue(kv, sellorder, pty.TradeOrderStatusOnSale)
}
return kv
}
func saveSellOrderKeyValue(kv []*types.KeyValue, sellorder *pty.SellOrder, status int32) []*types.KeyValue {
sellID := []byte(sellorder.SellID)
return genSellOrderKeyValue(kv, sellorder, status, sellID)
}
func deleteSellOrderKeyValue(kv []*types.KeyValue, sellorder *pty.SellOrder, status int32) []*types.KeyValue {
return genSellOrderKeyValue(kv, sellorder, status, nil)
}
func genSellOrderKeyValue(kv []*types.KeyValue, sellorder *pty.SellOrder, status int32, value []byte) []*types.KeyValue {
newkey := calcTokenSellOrderKey(sellorder.TokenSymbol, sellorder.Address, status, sellorder.SellID, sellorder.Height)
kv = append(kv, &types.KeyValue{Key: newkey, Value: value})
newkey = calcOnesSellOrderKeyStatus(sellorder.TokenSymbol, sellorder.Address, status, sellorder.SellID)
kv = append(kv, &types.KeyValue{Key: newkey, Value: value})
newkey = calcOnesSellOrderKeyToken(sellorder.TokenSymbol, sellorder.Address, status, sellorder.SellID)
kv = append(kv, &types.KeyValue{Key: newkey, Value: value})
newkey = calcTokensSellOrderKeyStatus(sellorder.TokenSymbol, status,
calcPriceOfToken(sellorder.PricePerBoardlot, sellorder.AmountPerBoardlot), sellorder.Address, sellorder.SellID)
kv = append(kv, &types.KeyValue{Key: newkey, Value: value})
const (
tradeLocaldbVersioin = "LODB-trade-version"
)
st, ty := fromStatus(status)
newkey = calcOnesOrderKey(sellorder.Address, st, ty, sellorder.Height, sellorder.SellID)
kv = append(kv, &types.KeyValue{Key: newkey, Value: value})
// 由于数据库精简需要保存具体数据
// 生成 key -> id 格式的本地数据库数据, 在下个版本这个文件可以全部删除
// 下个版本可以删除
const (
sellOrderSHTAS = "LODB-trade-sellorder-shtas:"
sellOrderASTS = "LODB-trade-sellorder-asts:"
sellOrderATSS = "LODB-trade-sellorder-atss:"
sellOrderTSPAS = "LODB-trade-sellorder-tspas:"
buyOrderSHTAS = "LODB-trade-buyorder-shtas:"
buyOrderASTS = "LODB-trade-buyorder-asts:"
buyOrderATSS = "LODB-trade-buyorder-atss:"
buyOrderTSPAS = "LODB-trade-buyorder-tspas:"
// Addr-Status-Type-Height-Key
orderASTHK = "LODB-trade-order-asthk:"
)
return kv
// Upgrade 实现升级接口
func (t *trade) Upgrade() error {
localDB := t.GetLocalDB()
// 获得默认的coins symbol, 更新数据时用
coinSymbol := t.GetAPI().GetConfig().GetCoinSymbol()
err := UpgradeLocalDBV2(localDB, coinSymbol)
if err != nil {
tradelog.Error("Upgrade failed", "err", err)
return errors.Cause(err)
}
return nil
}
// buy market
func saveBuyMarketOrderKeyValue(kv []*types.KeyValue, receipt *pty.ReceiptBuyBase, status int32, height int64) []*types.KeyValue {
if receipt.PriceExec != "" && receipt.PriceExec != defaultPriceExec {
// UpgradeLocalDBV2 trade 本地数据库升级
// from 1 to 2
func UpgradeLocalDBV2(localDB dbm.KVDB, coinSymbol string) error {
toVersion := 2
tradelog.Info("UpgradeLocalDBV2 upgrade start", "to_version", toVersion)
version, err := getVersion(localDB)
if err != nil {
return errors.Wrap(err, "UpgradeLocalDBV2 get version")
}
if version >= toVersion {
tradelog.Debug("UpgradeLocalDBV2 not need to upgrade", "current_version", version, "to_version", toVersion)
return nil
}
txhash := []byte(receipt.TxHash)
return genBuyMarketOrderKeyValue(kv, receipt, status, height, txhash)
}
func genBuyMarketOrderKeyValue(kv []*types.KeyValue, receipt *pty.ReceiptBuyBase,
status int32, height int64, value []byte) []*types.KeyValue {
keyID := receipt.TxHash
newkey := calcTokenBuyOrderKey(receipt.TokenSymbol, receipt.Owner, status, keyID, height)
kv = append(kv, &types.KeyValue{Key: newkey, Value: value})
newkey = calcOnesBuyOrderKeyStatus(receipt.TokenSymbol, receipt.Owner, status, keyID)
kv = append(kv, &types.KeyValue{Key: newkey, Value: value})
newkey = calcOnesBuyOrderKeyToken(receipt.TokenSymbol, receipt.Owner, status, keyID)
kv = append(kv, &types.KeyValue{Key: newkey, Value: value})
err = UpgradeLocalDBPart2(localDB, coinSymbol)
if err != nil {
return errors.Wrap(err, "UpgradeLocalDBV2 UpgradeLocalDBPart2")
}
priceBoardlot, err := strconv.ParseFloat(receipt.PricePerBoardlot, 64)
err = UpgradeLocalDBPart1(localDB)
if err != nil {
panic(err)
return errors.Wrap(err, "UpgradeLocalDBV2 UpgradeLocalDBPart1")
}
priceBoardlotInt64 := int64(priceBoardlot * float64(types.TokenPrecision))
AmountPerBoardlot, err := strconv.ParseFloat(receipt.AmountPerBoardlot, 64)
err = setVersion(localDB, toVersion)
if err != nil {
panic(err)
return errors.Wrap(err, "UpgradeLocalDBV2 setVersion")
}
AmountPerBoardlotInt64 := int64(AmountPerBoardlot * float64(types.Coin))
price := calcPriceOfToken(priceBoardlotInt64, AmountPerBoardlotInt64)
newkey = calcTokensBuyOrderKeyStatus(receipt.TokenSymbol, status,
price, receipt.Owner, keyID)
kv = append(kv, &types.KeyValue{Key: newkey, Value: value})
st, ty := fromStatus(status)
newkey = calcOnesOrderKey(receipt.Owner, st, ty, height, keyID)
kv = append(kv, &types.KeyValue{Key: newkey, Value: value})
return kv
tradelog.Info("UpgradeLocalDBV2 upgrade done")
return nil
}
// buy limit
func genSaveBuyLimitKv(buyOrder *pty.BuyLimitOrder) []*types.KeyValue {
if buyOrder.PriceExec != "" && buyOrder.PriceExec != defaultPriceExec {
return nil
// UpgradeLocalDBPart1 手动生成KV,需要在原有数据库中删除
func UpgradeLocalDBPart1(localDB dbm.KVDB) error {
prefixes := []string{
sellOrderSHTAS,
sellOrderASTS,
sellOrderATSS,
sellOrderTSPAS,
buyOrderSHTAS,
buyOrderASTS,
buyOrderATSS,
buyOrderTSPAS,
orderASTHK,
}
status := buyOrder.Status
var kv []*types.KeyValue
kv = saveBuyLimitOrderKeyValue(kv, buyOrder, status)
if pty.TradeOrderStatusBoughtOut == status || pty.TradeOrderStatusBuyRevoked == status {
tradelog.Debug("trade saveBuyLimit ", "remove old status with Buyid", buyOrder.BuyID)
kv = deleteBuyLimitKeyValue(kv, buyOrder, pty.TradeOrderStatusOnBuy)
for _, prefix := range prefixes {
err := delOnePrefix(localDB, prefix)
if err != nil {
return errors.Wrapf(err, "UpdateLocalDBPart1 delOnePrefix: %s", prefix)
}
}
return kv
return nil
}
func saveBuyLimitOrderKeyValue(kv []*types.KeyValue, buyOrder *pty.BuyLimitOrder, status int32) []*types.KeyValue {
buyID := []byte(buyOrder.BuyID)
return genBuyLimitOrderKeyValue(kv, buyOrder, status, buyID)
}
// delOnePrefix 删除指定前缀的记录
func delOnePrefix(localDB dbm.KVDB, prefix string) error {
start := []byte(prefix)
keys, err := localDB.List(start, nil, 0, dbm.ListASC|dbm.ListKeyOnly)
if err != nil {
if err == types.ErrNotFound {
return nil
}
return err
}
tradelog.Debug("delOnePrefix", "len", len(keys), "prefix", prefix)
for _, key := range keys {
err = localDB.Set(key, nil)
if err != nil {
return err
}
}
func deleteBuyLimitKeyValue(kv []*types.KeyValue, buyOrder *pty.BuyLimitOrder, status int32) []*types.KeyValue {
return genBuyLimitOrderKeyValue(kv, buyOrder, status, nil)
return nil
}
func genBuyLimitOrderKeyValue(kv []*types.KeyValue, buyOrder *pty.BuyLimitOrder, status int32, value []byte) []*types.KeyValue {
newkey := calcTokenBuyOrderKey(buyOrder.TokenSymbol, buyOrder.Address, status, buyOrder.BuyID, buyOrder.Height)
kv = append(kv, &types.KeyValue{Key: newkey, Value: value})
newkey = calcOnesBuyOrderKeyStatus(buyOrder.TokenSymbol, buyOrder.Address, status, buyOrder.BuyID)
kv = append(kv, &types.KeyValue{Key: newkey, Value: value})
newkey = calcOnesBuyOrderKeyToken(buyOrder.TokenSymbol, buyOrder.Address, status, buyOrder.BuyID)
kv = append(kv, &types.KeyValue{Key: newkey, Value: value})
newkey = calcTokensBuyOrderKeyStatus(buyOrder.TokenSymbol, status,
calcPriceOfToken(buyOrder.PricePerBoardlot, buyOrder.AmountPerBoardlot), buyOrder.Address, buyOrder.BuyID)
kv = append(kv, &types.KeyValue{Key: newkey, Value: value})
// UpgradeLocalDBPart2 升级order
// order 从 v1 升级到 v2
// 通过tableV1 删除, 通过tableV2 添加, 无需通过每个区块扫描对应的交易
func UpgradeLocalDBPart2(kvdb dbm.KVDB, coinSymbol string) error {
return upgradeOrder(kvdb, coinSymbol)
}
st, ty := fromStatus(status)
newkey = calcOnesOrderKey(buyOrder.Address, st, ty, buyOrder.Height, buyOrder.BuyID)
kv = append(kv, &types.KeyValue{Key: newkey, Value: value})
func upgradeOrder(kvdb dbm.KVDB, coinSymbol string) (err error) {
tab2 := NewOrderTableV2(kvdb)
tab := NewOrderTable(kvdb)
q1 := tab.GetQuery(kvdb)
return kv
}
var order1 pty.LocalOrder
rows, err := q1.List("key", &order1, []byte(""), 0, 0)
if err != nil {
if err == types.ErrNotFound {
return nil
}
return errors.Wrap(err, "upgradeOrder list from order v1 table")
}
// sell market
func saveSellMarketOrderKeyValue(kv []*types.KeyValue, receipt *pty.ReceiptSellBase, status int32, height int64) []*types.KeyValue {
if receipt.PriceExec != "" && receipt.PriceExec != defaultPriceExec {
return nil
tradelog.Debug("upgradeOrder", "len", len(rows))
for _, row := range rows {
o1, ok := row.Data.(*pty.LocalOrder)
if !ok {
return errors.Wrap(types.ErrTypeAsset, "decode order v1")
}
o2 := types.Clone(o1).(*pty.LocalOrder)
upgradeLocalOrder(o2, coinSymbol)
err = tab2.Add(o2)
if err != nil {
return errors.Wrap(err, "upgradeOrder add to order v2 table")
}
err = tab.Del([]byte(o1.TxIndex))
if err != nil {
return errors.Wrapf(err, "upgradeOrder del from order v1 table, key: %s", o1.TxIndex)
}
}
txhash := []byte(receipt.TxHash)
return genSellMarketOrderKeyValue(kv, receipt, status, height, txhash)
}
// delete part
// sell limit
func genDeleteSellKv(sellorder *pty.SellOrder) []*types.KeyValue {
if sellorder.PriceExec != "" && sellorder.PriceExec != defaultPriceExec {
return nil
kvs, err := tab2.Save()
if err != nil {
return errors.Wrap(err, "upgradeOrder save-add to order v2 table")
}
status := sellorder.Status
var kv []*types.KeyValue
kv = deleteSellOrderKeyValue(kv, sellorder, status)
if pty.TradeOrderStatusSoldOut == status || pty.TradeOrderStatusRevoked == status {
tradelog.Debug("trade saveSell ", "remove old status onsale to soldout or revoked with sellID", sellorder.SellID)
kv = saveSellOrderKeyValue(kv, sellorder, pty.TradeOrderStatusOnSale)
kvs2, err := tab.Save()
if err != nil {
return errors.Wrap(err, "upgradeOrder save-del to order v1 table")
}
kvs = append(kvs, kvs2...)
for _, kv := range kvs {
tradelog.Debug("upgradeOrder", "KEY", string(kv.GetKey()))
err = kvdb.Set(kv.GetKey(), kv.GetValue())
if err != nil {
return errors.Wrapf(err, "upgradeOrder set localdb key: %s", string(kv.GetKey()))
}
}
return kv
return nil
}
// buy market
func deleteBuyMarketOrderKeyValue(kv []*types.KeyValue, receipt *pty.ReceiptBuyBase, status int32, height int64) []*types.KeyValue {
if receipt.PriceExec != "" && receipt.PriceExec != defaultPriceExec {
return nil
// upgradeLocalOrder 处理两个fork前的升级数据
// 1. 支持任意资产
// 2. 支持任意资产定价
func upgradeLocalOrder(order *pty.LocalOrder, coinSymbol string) {
if order.AssetExec == "" {
order.AssetExec = defaultAssetExec
}
if order.PriceExec == "" {
order.PriceExec = defaultPriceExec
order.PriceSymbol = coinSymbol
}
return genBuyMarketOrderKeyValue(kv, receipt, status, height, nil)
}
// buy limit
func genDeleteBuyLimitKv(buyOrder *pty.BuyLimitOrder) []*types.KeyValue {
if buyOrder.PriceExec != "" && buyOrder.PriceExec != defaultPriceExec {
return nil
// localdb Version
func getVersion(kvdb dbm.KV) (int, error) {
value, err := kvdb.Get([]byte(tradeLocaldbVersioin))
if err != nil && err != types.ErrNotFound {
return 1, err
}
status := buyOrder.Status
var kv []*types.KeyValue
kv = deleteBuyLimitKeyValue(kv, buyOrder, status)
if pty.TradeOrderStatusBoughtOut == status || pty.TradeOrderStatusBuyRevoked == status {
tradelog.Debug("trade saveSell ", "remove old status onsale to soldout or revoked with sellid", buyOrder.BuyID)
kv = saveBuyLimitOrderKeyValue(kv, buyOrder, pty.TradeOrderStatusOnBuy)
if err == types.ErrNotFound {
return 1, nil
}
return kv
var v types.Int32
err = types.Decode(value, &v)
if err != nil {
return 1, err
}
return int(v.Data), nil
}
// sell market
func deleteSellMarketOrderKeyValue(kv []*types.KeyValue, receipt *pty.ReceiptSellBase, status int32, height int64) []*types.KeyValue {
if receipt.PriceExec != "" && receipt.PriceExec != defaultPriceExec {
return nil
}
return genSellMarketOrderKeyValue(kv, receipt, status, height, nil)
func setVersion(kvdb dbm.KV, version int) error {
v := types.Int32{Data: int32(version)}
x := types.Encode(&v)
return kvdb.Set([]byte(tradeLocaldbVersioin), x)
}
......@@ -81,23 +81,12 @@ func (t *trade) GetOnesOrderWithStatus(req *pty.ReqAddrAssets) (types.Message, e
if len(req.FromKey) > 0 {
order.TxIndex = req.FromKey
}
rows, err := list(t.GetLocalDB(), "owner_isFinished", &order, req.Count, req.Direction)
rows, err := listV2(t.GetLocalDB(), "owner_isFinished", &order, req.Count, req.Direction)
if err != nil {
tradelog.Error("GetOnesOrderWithStatus", "err", err)
return nil, err
}
var replys pty.ReplyTradeOrders
cfg := t.GetAPI().GetConfig()
for _, row := range rows {
o, ok := row.Data.(*pty.LocalOrder)
if !ok {
tradelog.Error("GetOnesOrderWithStatus", "err", "bad row type")
return nil, types.ErrTypeAsset
}
reply := fmtReply(cfg, o)
replys.Orders = append(replys.Orders, reply)
}
return &replys, nil
return t.toTradeOrders(rows)
}
func fmtReply(cfg *types.Chain33Config, order *pty.LocalOrder) *pty.ReplyTradeOrder {
......@@ -131,7 +120,7 @@ func fmtReply(cfg *types.Chain33Config, order *pty.LocalOrder) *pty.ReplyTradeOr
}
func (t *trade) GetOneOrder(req *pty.ReqAddrAssets) (types.Message, error) {
query := NewOrderTable(t.GetLocalDB())
query := NewOrderTableV2(t.GetLocalDB())
tradelog.Debug("query GetData dbg", "primary", req.FromKey)
row, err := query.GetData([]byte(req.FromKey))
if err != nil {
......
package executor
import (
"strconv"
"strings"
"github.com/33cn/chain33/common"
"github.com/33cn/chain33/common/db/table"
"github.com/33cn/chain33/types"
pty "github.com/33cn/plugin/plugin/dapp/trade/types"
)
// 1.8 根据token 分页显示未完成成交卖单
// 文档 1.8 根据token 分页显示未完成成交卖单
func (t *trade) Query_GetTokenSellOrderByStatus(req *pty.ReqTokenSellOrder) (types.Message, error) {
return t.GetTokenSellOrderByStatus(req, req.Status)
}
// GetTokenSellOrderByStatus by status
// sell & TokenSymbol & status sort by price
func (t *trade) GetTokenSellOrderByStatus(req *pty.ReqTokenSellOrder, status int32) (types.Message, error) {
return t.GetTokenOrderByStatus(true, req, status)
}
func (t *trade) GetTokenOrderByStatus(isSell bool, req *pty.ReqTokenSellOrder, status int32) (types.Message, error) {
if req.Count <= 0 || (req.Direction != 1 && req.Direction != 0) {
return nil, types.ErrInvalidParam
}
fromKey := []byte("")
if len(req.FromKey) != 0 {
sell := t.replyReplySellOrderfromID([]byte(req.FromKey))
if sell == nil {
tradelog.Error("GetTokenSellOrderByStatus", "key not exist", req.FromKey)
return nil, types.ErrInvalidParam
}
fromKey = calcTokensSellOrderKeyStatus(sell.TokenSymbol, sell.Status,
calcPriceOfToken(sell.PricePerBoardlot, sell.AmountPerBoardlot), sell.Owner, sell.Key)
var order pty.LocalOrder
if len(req.FromKey) > 0 {
order.TxIndex = req.FromKey
}
values, err := t.GetLocalDB().List(calcTokensSellOrderPrefixStatus(req.TokenSymbol, status), fromKey, req.Count, req.Direction)
t.setQueryAsset(&order, req.TokenSymbol)
order.IsSellOrder = isSell
order.Status = req.Status
rows, err := listV2(t.GetLocalDB(), "asset_isSell_status_price", &order, req.Count, req.Direction)
if err != nil {
tradelog.Error("GetOnesOrderWithStatus", "err", err)
return nil, err
}
var replys pty.ReplyTradeOrders
for _, key := range values {
reply := t.loadOrderFromKey(key)
if reply == nil {
continue
}
replys.Orders = append(replys.Orders, reply)
}
return &replys, nil
return t.toTradeOrders(rows)
}
// 1.3 根据token 分页显示未完成成交买单
......@@ -54,39 +49,18 @@ func (t *trade) Query_GetTokenBuyOrderByStatus(req *pty.ReqTokenBuyOrder) (types
}
// GetTokenBuyOrderByStatus by status
// buy & TokenSymbol & status buy sort by price
func (t *trade) GetTokenBuyOrderByStatus(req *pty.ReqTokenBuyOrder, status int32) (types.Message, error) {
if req.Count <= 0 || (req.Direction != 1 && req.Direction != 0) {
return nil, types.ErrInvalidParam
}
fromKey := []byte("")
if len(req.FromKey) != 0 {
buy := t.replyReplyBuyOrderfromID([]byte(req.FromKey))
if buy == nil {
tradelog.Error("GetTokenBuyOrderByStatus", "key not exist", req.FromKey)
return nil, types.ErrInvalidParam
}
fromKey = calcTokensBuyOrderKeyStatus(buy.TokenSymbol, buy.Status,
calcPriceOfToken(buy.PricePerBoardlot, buy.AmountPerBoardlot), buy.Owner, buy.Key)
}
tradelog.Debug("GetTokenBuyOrderByStatus", "fromKey ", fromKey)
// List Direction 是升序, 买单是要降序, 把高价买的放前面, 在下一页操作时, 显示买价低的。
direction := 1 - req.Direction
values, err := t.GetLocalDB().List(calcTokensBuyOrderPrefixStatus(req.TokenSymbol, status), fromKey, req.Count, direction)
if err != nil {
return nil, err
}
var replys pty.ReplyTradeOrders
for _, key := range values {
reply := t.loadOrderFromKey(key)
if reply == nil {
continue
}
tradelog.Debug("trade Query", "getSellOrderFromID", string(key))
replys.Orders = append(replys.Orders, reply)
req2 := pty.ReqTokenSellOrder{
TokenSymbol: req.TokenSymbol,
FromKey: req.FromKey,
Count: req.Count,
Direction: direction,
Status: req.Status,
}
return &replys, nil
return t.GetTokenOrderByStatus(false, &req2, status)
}
// addr part
......@@ -102,500 +76,106 @@ func (t *trade) Query_GetOnesBuyOrder(req *pty.ReqAddrAssets) (types.Message, er
// GetOnesSellOrder by address or address-token
func (t *trade) GetOnesSellOrder(addrTokens *pty.ReqAddrAssets) (types.Message, error) {
var keys [][]byte
if 0 == len(addrTokens.Token) {
values, err := t.GetLocalDB().List(calcOnesSellOrderPrefixAddr(addrTokens.Addr), nil, 0, 0)
if err != nil {
return nil, err
}
if len(values) != 0 {
tradelog.Debug("trade Query", "get number of sellID", len(values))
keys = append(keys, values...)
}
} else {
for _, token := range addrTokens.Token {
values, err := t.GetLocalDB().List(calcOnesSellOrderPrefixToken(token, addrTokens.Addr), nil, 0, 0)
tradelog.Debug("trade Query", "Begin to list addr with token", token, "got values", len(values))
if err != nil && err != types.ErrNotFound {
return nil, err
}
if len(values) != 0 {
keys = append(keys, values...)
}
}
}
var replys pty.ReplyTradeOrders
for _, key := range keys {
reply := t.loadOrderFromKey(key)
if reply == nil {
continue
}
tradelog.Debug("trade Query", "getSellOrderFromID", string(key))
replys.Orders = append(replys.Orders, reply)
}
return &replys, nil
return t.GetOnesOrder(true, addrTokens)
}
// GetOnesBuyOrder by address or address-token
func (t *trade) GetOnesBuyOrder(addrTokens *pty.ReqAddrAssets) (types.Message, error) {
var keys [][]byte
return t.GetOnesOrder(false, addrTokens)
}
// GetOnesSellOrder by address or address-token
func (t *trade) GetOnesOrder(isSell bool, addrTokens *pty.ReqAddrAssets) (types.Message, error) {
var order pty.LocalOrder
order.Owner = addrTokens.Addr
order.IsSellOrder = isSell
if 0 == len(addrTokens.Token) {
values, err := t.GetLocalDB().List(calcOnesBuyOrderPrefixAddr(addrTokens.Addr), nil, 0, 0)
rows, err := listV2(t.GetLocalDB(), "owner_isSell", &order, 0, 0)
if err != nil {
tradelog.Error("GetOnesSellOrder", "err", err)
return nil, err
}
if len(values) != 0 {
tradelog.Debug("trade Query", "get number of buy keys", len(values))
keys = append(keys, values...)
}
} else {
for _, token := range addrTokens.Token {
values, err := t.GetLocalDB().List(calcOnesBuyOrderPrefixToken(token, addrTokens.Addr), nil, 0, 0)
tradelog.Debug("trade Query", "Begin to list addr with token", token, "got values", len(values))
if err != nil && err != types.ErrNotFound {
return nil, err
}
if len(values) != 0 {
keys = append(keys, values...)
}
}
return t.toTradeOrders(rows)
}
var replys pty.ReplyTradeOrders
for _, key := range keys {
reply := t.loadOrderFromKey(key)
if reply == nil {
for _, token := range addrTokens.Token {
t.setQueryAsset(&order, token)
rows, err := listV2(t.GetLocalDB(), "owner_asset_isSell", &order, 0, 0)
if err != nil && err != types.ErrNotFound {
return nil, err
}
if len(rows) == 0 {
continue
}
tradelog.Debug("trade Query", "getSellOrderFromID", string(key))
replys.Orders = append(replys.Orders, reply)
}
rs, err := t.toTradeOrders(rows)
if err != nil {
return nil, err
}
replys.Orders = append(replys.Orders, rs.Orders...)
}
return &replys, nil
}
// 1.5 没找到
// Query_GetOnesBuyOrderWithStatus 1.5 没找到
// 按 用户状态来 addr-status
func (t *trade) Query_GetOnesSellOrderWithStatus(req *pty.ReqAddrAssets) (types.Message, error) {
return t.GetOnesSellOrdersWithStatus(req)
}
// 1.2 按 用户状态来 addr-status
// Query_GetOnesBuyOrderWithStatus 1.2 按 用户状态来 addr-status
func (t *trade) Query_GetOnesBuyOrderWithStatus(req *pty.ReqAddrAssets) (types.Message, error) {
return t.GetOnesBuyOrdersWithStatus(req)
}
// GetOnesSellOrdersWithStatus by address-status
func (t *trade) GetOnesSellOrdersWithStatus(req *pty.ReqAddrAssets) (types.Message, error) {
var sellIDs [][]byte
values, err := t.GetLocalDB().List(calcOnesSellOrderPrefixStatus(req.Addr, req.Status), nil, 0, 0)
if err != nil {
return nil, err
}
if len(values) != 0 {
tradelog.Debug("trade Query", "get number of sellID", len(values))
sellIDs = append(sellIDs, values...)
}
var replys pty.ReplyTradeOrders
for _, key := range sellIDs {
reply := t.loadOrderFromKey(key)
if reply == nil {
continue
}
tradelog.Debug("trade Query", "getSellOrderFromID", string(key))
replys.Orders = append(replys.Orders, reply)
}
return &replys, nil
return t.GetOnesStatusOrder(true, req)
}
// GetOnesBuyOrdersWithStatus by address-status
func (t *trade) GetOnesBuyOrdersWithStatus(req *pty.ReqAddrAssets) (types.Message, error) {
var sellIDs [][]byte
values, err := t.GetLocalDB().List(calcOnesBuyOrderPrefixStatus(req.Addr, req.Status), nil, 0, 0)
if err != nil {
return nil, err
}
if len(values) != 0 {
tradelog.Debug("trade Query", "get number of buy keys", len(values))
sellIDs = append(sellIDs, values...)
}
var replys pty.ReplyTradeOrders
for _, key := range sellIDs {
reply := t.loadOrderFromKey(key)
if reply == nil {
continue
}
tradelog.Debug("trade Query", "getSellOrderFromID", string(key))
replys.Orders = append(replys.Orders, reply)
}
return &replys, nil
return t.GetOnesStatusOrder(false, req)
}
// utils
func (t *trade) loadOrderFromKey(key []byte) *pty.ReplyTradeOrder {
tradelog.Debug("trade Query", "id", string(key), "check-prefix", sellIDPrefix)
if strings.HasPrefix(string(key), sellIDPrefix) {
txHash := strings.Replace(string(key), sellIDPrefix, "0x", 1)
txResult, err := getTx([]byte(txHash), t.GetLocalDB(), t.GetAPI())
tradelog.Debug("loadOrderFromKey ", "load txhash", txResult)
if err != nil {
return nil
}
reply := limitOrderTxResult2Order(txResult)
// GetOnesStatusOrder Get Ones Status Order
func (t *trade) GetOnesStatusOrder(isSell bool, req *pty.ReqAddrAssets) (types.Message, error) {
var order pty.LocalOrder
order.Owner = req.Addr
order.Status = req.Status
order.IsSellOrder = isSell
sellOrder, err := getSellOrderFromID(key, t.GetStateDB())
tradelog.Debug("trade Query", "getSellOrderFromID", string(key))
if err != nil {
return nil
}
reply.TradedBoardlot = sellOrder.SoldBoardlot
reply.Status = sellOrder.Status
return reply
} else if strings.HasPrefix(string(key), buyIDPrefix) {
txHash := strings.Replace(string(key), buyIDPrefix, "0x", 1)
txResult, err := getTx([]byte(txHash), t.GetLocalDB(), t.GetAPI())
tradelog.Debug("loadOrderFromKey ", "load txhash", txResult)
if err != nil {
return nil
}
reply := limitOrderTxResult2Order(txResult)
buyOrder, err := getBuyOrderFromID(key, t.GetStateDB())
if err != nil {
return nil
}
reply.TradedBoardlot = buyOrder.BoughtBoardlot
reply.Status = buyOrder.Status
return reply
}
txResult, err := getTx(key, t.GetLocalDB(), t.GetAPI())
tradelog.Debug("loadOrderFromKey ", "load txhash", string(key))
rows, err := listV2(t.GetLocalDB(), "owner_isSell_status", &order, 0, 0)
if err != nil {
return nil
}
return txResult2OrderReply(txResult)
}
func limitOrderTxResult2Order(txResult *types.TxResult) *pty.ReplyTradeOrder {
logs := txResult.Receiptdate.Logs
tradelog.Debug("txResult2sellOrderReply", "show logs", logs)
for _, log := range logs {
if log.Ty == pty.TyLogTradeSellLimit {
var receipt pty.ReceiptTradeSellLimit
err := types.Decode(log.Log, &receipt)
if err != nil {
tradelog.Error("txResult2sellOrderReply", "decode receipt", err)
return nil
}
tradelog.Debug("txResult2sellOrderReply", "show logs 1 ", receipt)
return sellBase2Order(receipt.Base, common.ToHex(txResult.GetTx().Hash()), txResult.Blocktime)
} else if log.Ty == pty.TyLogTradeBuyLimit {
var receipt pty.ReceiptTradeBuyLimit
err := types.Decode(log.Log, &receipt)
if err != nil {
tradelog.Error("txResult2sellOrderReply", "decode receipt", err)
return nil
}
tradelog.Debug("txResult2sellOrderReply", "show logs 1 ", receipt)
return buyBase2Order(receipt.Base, common.ToHex(txResult.GetTx().Hash()), txResult.Blocktime)
}
}
return nil
}
func txResult2OrderReply(txResult *types.TxResult) *pty.ReplyTradeOrder {
logs := txResult.Receiptdate.Logs
tradelog.Debug("txResult2sellOrderReply", "show logs", logs)
for _, log := range logs {
if log.Ty == pty.TyLogTradeBuyMarket {
var receipt pty.ReceiptTradeBuyMarket
err := types.Decode(log.Log, &receipt)
if err != nil {
tradelog.Error("txResult2sellOrderReply", "decode receipt", err)
return nil
}
tradelog.Debug("txResult2sellOrderReply", "show logs 1 ", receipt)
return buyBase2Order(receipt.Base, common.ToHex(txResult.GetTx().Hash()), txResult.Blocktime)
} else if log.Ty == pty.TyLogTradeBuyRevoke {
var receipt pty.ReceiptTradeBuyRevoke
err := types.Decode(log.Log, &receipt)
if err != nil {
tradelog.Error("txResult2sellOrderReply", "decode receipt", err)
return nil
}
tradelog.Debug("txResult2sellOrderReply", "show logs 1 ", receipt)
return buyBase2Order(receipt.Base, common.ToHex(txResult.GetTx().Hash()), txResult.Blocktime)
} else if log.Ty == pty.TyLogTradeSellRevoke {
var receipt pty.ReceiptTradeSellRevoke
err := types.Decode(log.Log, &receipt)
if err != nil {
tradelog.Error("txResult2sellOrderReply", "decode receipt", err)
return nil
}
tradelog.Debug("txResult2sellOrderReply", "show revoke 1 ", receipt)
return sellBase2Order(receipt.Base, common.ToHex(txResult.GetTx().Hash()), txResult.Blocktime)
} else if log.Ty == pty.TyLogTradeSellMarket {
var receipt pty.ReceiptSellMarket
err := types.Decode(log.Log, &receipt)
if err != nil {
tradelog.Error("txResult2sellOrderReply", "decode receipt", err)
return nil
}
tradelog.Debug("txResult2sellOrderReply", "show logs 1 ", receipt)
return sellBase2Order(receipt.Base, common.ToHex(txResult.GetTx().Hash()), txResult.Blocktime)
}
}
return nil
}
// SellMarkMarket BuyMarket 没有tradeOrder 需要调用这个函数进行转化
// BuyRevoke, SellRevoke 也需要
// SellLimit/BuyLimit 有order 但order 里面没有 bolcktime, 直接访问 order 还需要再次访问 block, 还不如直接访问交易
func buyBase2Order(base *pty.ReceiptBuyBase, txHash string, blockTime int64) *pty.ReplyTradeOrder {
amount, err := strconv.ParseFloat(base.AmountPerBoardlot, 64)
if err != nil {
tradelog.Error("txResult2sellOrderReply", "decode receipt", err)
return nil
}
price, err := strconv.ParseFloat(base.PricePerBoardlot, 64)
if err != nil {
tradelog.Error("txResult2sellOrderReply", "decode receipt", err)
return nil
}
key := txHash
if len(base.BuyID) > 0 {
key = base.BuyID
}
//txhash := common.ToHex(txResult.GetTx().Hash())
reply := &pty.ReplyTradeOrder{
TokenSymbol: base.TokenSymbol,
Owner: base.Owner,
AmountPerBoardlot: int64(amount * float64(types.TokenPrecision)),
MinBoardlot: base.MinBoardlot,
PricePerBoardlot: int64(price * float64(types.Coin)),
TotalBoardlot: base.TotalBoardlot,
TradedBoardlot: base.BoughtBoardlot,
BuyID: base.BuyID,
Status: pty.SellOrderStatus2Int[base.Status],
SellID: base.SellID,
TxHash: txHash,
Height: base.Height,
Key: key,
BlockTime: blockTime,
IsSellOrder: false,
AssetExec: base.AssetExec,
}
tradelog.Debug("txResult2sellOrderReply", "show reply", reply)
return reply
}
func sellBase2Order(base *pty.ReceiptSellBase, txHash string, blockTime int64) *pty.ReplyTradeOrder {
amount, err := strconv.ParseFloat(base.AmountPerBoardlot, 64)
if err != nil {
tradelog.Error("txResult2sellOrderReply", "decode receipt", err)
return nil
}
price, err := strconv.ParseFloat(base.PricePerBoardlot, 64)
if err != nil {
tradelog.Error("txResult2sellOrderReply", "decode receipt", err)
return nil
}
//txhash := common.ToHex(txResult.GetTx().Hash())
key := txHash
if len(base.SellID) > 0 {
key = base.SellID
}
reply := &pty.ReplyTradeOrder{
TokenSymbol: base.TokenSymbol,
Owner: base.Owner,
AmountPerBoardlot: int64(amount * float64(types.TokenPrecision)),
MinBoardlot: base.MinBoardlot,
PricePerBoardlot: int64(price * float64(types.Coin)),
TotalBoardlot: base.TotalBoardlot,
TradedBoardlot: base.SoldBoardlot,
BuyID: base.BuyID,
Status: pty.SellOrderStatus2Int[base.Status],
SellID: base.SellID,
TxHash: txHash,
Height: base.Height,
Key: key,
BlockTime: blockTime,
IsSellOrder: true,
AssetExec: base.AssetExec,
}
tradelog.Debug("txResult2sellOrderReply", "show reply", reply)
return reply
}
func (t *trade) replyReplySellOrderfromID(key []byte) *pty.ReplySellOrder {
tradelog.Debug("trade Query", "id", string(key), "check-prefix", sellIDPrefix)
if strings.HasPrefix(string(key), sellIDPrefix) {
if sellorder, err := getSellOrderFromID(key, t.GetStateDB()); err == nil {
tradelog.Debug("trade Query", "getSellOrderFromID", string(key))
return sellOrder2reply(sellorder)
}
} else { // txhash as key
txResult, err := getTx(key, t.GetLocalDB(), t.GetAPI())
tradelog.Debug("GetOnesSellOrder ", "load txhash", string(key))
if err != nil {
return nil
}
return txResult2sellOrderReply(txResult)
}
return nil
}
func (t *trade) replyReplyBuyOrderfromID(key []byte) *pty.ReplyBuyOrder {
tradelog.Debug("trade Query", "id", string(key), "check-prefix", buyIDPrefix)
if strings.HasPrefix(string(key), buyIDPrefix) {
if buyOrder, err := getBuyOrderFromID(key, t.GetStateDB()); err == nil {
tradelog.Debug("trade Query", "getSellOrderFromID", string(key))
return buyOrder2reply(buyOrder)
}
} else { // txhash as key
txResult, err := getTx(key, t.GetLocalDB(), t.GetAPI())
tradelog.Debug("replyReplyBuyOrderfromID ", "load txhash", string(key))
if err != nil {
return nil
}
return txResult2buyOrderReply(txResult)
}
return nil
}
func sellOrder2reply(sellOrder *pty.SellOrder) *pty.ReplySellOrder {
reply := &pty.ReplySellOrder{
TokenSymbol: sellOrder.TokenSymbol,
Owner: sellOrder.Address,
AmountPerBoardlot: sellOrder.AmountPerBoardlot,
MinBoardlot: sellOrder.MinBoardlot,
PricePerBoardlot: sellOrder.PricePerBoardlot,
TotalBoardlot: sellOrder.TotalBoardlot,
SoldBoardlot: sellOrder.SoldBoardlot,
BuyID: "",
Status: sellOrder.Status,
SellID: sellOrder.SellID,
TxHash: strings.Replace(sellOrder.SellID, sellIDPrefix, "0x", 1),
Height: sellOrder.Height,
Key: sellOrder.SellID,
AssetExec: sellOrder.AssetExec,
}
return reply
}
func txResult2sellOrderReply(txResult *types.TxResult) *pty.ReplySellOrder {
logs := txResult.Receiptdate.Logs
tradelog.Debug("txResult2sellOrderReply", "show logs", logs)
for _, log := range logs {
if log.Ty == pty.TyLogTradeSellMarket {
var receipt pty.ReceiptSellMarket
err := types.Decode(log.Log, &receipt)
if err != nil {
tradelog.Error("txResult2sellOrderReply", "decode receipt", err)
return nil
}
tradelog.Debug("txResult2sellOrderReply", "show logs 1 ", receipt)
amount, err := strconv.ParseFloat(receipt.Base.AmountPerBoardlot, 64)
if err != nil {
tradelog.Error("txResult2sellOrderReply", "decode receipt", err)
return nil
}
price, err := strconv.ParseFloat(receipt.Base.PricePerBoardlot, 64)
if err != nil {
tradelog.Error("txResult2sellOrderReply", "decode receipt", err)
return nil
}
txhash := common.ToHex(txResult.GetTx().Hash())
reply := &pty.ReplySellOrder{
TokenSymbol: receipt.Base.TokenSymbol,
Owner: receipt.Base.Owner,
AmountPerBoardlot: int64(amount * float64(types.TokenPrecision)),
MinBoardlot: receipt.Base.MinBoardlot,
PricePerBoardlot: int64(price * float64(types.Coin)),
TotalBoardlot: receipt.Base.TotalBoardlot,
SoldBoardlot: receipt.Base.SoldBoardlot,
BuyID: receipt.Base.BuyID,
Status: pty.SellOrderStatus2Int[receipt.Base.Status],
SellID: "",
TxHash: txhash,
Height: receipt.Base.Height,
Key: txhash,
AssetExec: receipt.Base.AssetExec,
}
tradelog.Debug("txResult2sellOrderReply", "show reply", reply)
return reply
}
tradelog.Error("GetOnesStatusOrder", "err", err)
return nil, err
}
return nil
return t.toTradeOrders(rows)
}
func buyOrder2reply(buyOrder *pty.BuyLimitOrder) *pty.ReplyBuyOrder {
reply := &pty.ReplyBuyOrder{
TokenSymbol: buyOrder.TokenSymbol,
Owner: buyOrder.Address,
AmountPerBoardlot: buyOrder.AmountPerBoardlot,
MinBoardlot: buyOrder.MinBoardlot,
PricePerBoardlot: buyOrder.PricePerBoardlot,
TotalBoardlot: buyOrder.TotalBoardlot,
BoughtBoardlot: buyOrder.BoughtBoardlot,
BuyID: buyOrder.BuyID,
Status: buyOrder.Status,
SellID: "",
TxHash: strings.Replace(buyOrder.BuyID, buyIDPrefix, "0x", 1),
Height: buyOrder.Height,
Key: buyOrder.BuyID,
AssetExec: buyOrder.AssetExec,
}
return reply
// util
// 在老版本中,默认查询token相关的订单
func (t *trade) setQueryAsset(order *pty.LocalOrder, tokenSymbol string) {
order.AssetSymbol = tokenSymbol
order.AssetExec = defaultAssetExec
order.PriceSymbol = t.GetAPI().GetConfig().GetCoinSymbol()
order.PriceExec = defaultPriceExec
}
func txResult2buyOrderReply(txResult *types.TxResult) *pty.ReplyBuyOrder {
logs := txResult.Receiptdate.Logs
tradelog.Debug("txResult2sellOrderReply", "show logs", logs)
for _, log := range logs {
if log.Ty == pty.TyLogTradeBuyMarket {
var receipt pty.ReceiptTradeBuyMarket
err := types.Decode(log.Log, &receipt)
if err != nil {
tradelog.Error("txResult2sellOrderReply", "decode receipt", err)
return nil
}
tradelog.Debug("txResult2sellOrderReply", "show logs 1 ", receipt)
amount, err := strconv.ParseFloat(receipt.Base.AmountPerBoardlot, 64)
if err != nil {
tradelog.Error("txResult2sellOrderReply", "decode receipt", err)
return nil
}
price, err := strconv.ParseFloat(receipt.Base.PricePerBoardlot, 64)
if err != nil {
tradelog.Error("txResult2sellOrderReply", "decode receipt", err)
return nil
}
txhash := common.ToHex(txResult.GetTx().Hash())
reply := &pty.ReplyBuyOrder{
TokenSymbol: receipt.Base.TokenSymbol,
Owner: receipt.Base.Owner,
AmountPerBoardlot: int64(amount * float64(types.TokenPrecision)),
MinBoardlot: receipt.Base.MinBoardlot,
PricePerBoardlot: int64(price * float64(types.Coin)),
TotalBoardlot: receipt.Base.TotalBoardlot,
BoughtBoardlot: receipt.Base.BoughtBoardlot,
BuyID: "",
Status: pty.SellOrderStatus2Int[receipt.Base.Status],
SellID: receipt.Base.SellID,
TxHash: txhash,
Height: receipt.Base.Height,
Key: txhash,
AssetExec: receipt.Base.AssetExec,
}
tradelog.Debug("txResult2sellOrderReply", "show reply", reply)
return reply
}
// 转换数据结构, 输出前调用
func (t *trade) toTradeOrders(rows []*table.Row) (*pty.ReplyTradeOrders, error) {
var replys pty.ReplyTradeOrders
cfg := t.GetAPI().GetConfig()
for _, row := range rows {
o, ok := row.Data.(*pty.LocalOrder)
if !ok {
tradelog.Error("toTradeOrders", "err", "bad row type")
return nil, types.ErrTypeAsset
}
reply := fmtReply(cfg, o)
replys.Orders = append(replys.Orders, reply)
}
return nil
return &replys, nil
}
......@@ -73,7 +73,8 @@ func (t *trade) getSellOrderFromDb(sellID []byte) *pty.SellOrder {
return &sellorder
}
func (t *trade) saveSell(base *pty.ReceiptSellBase, ty int32, tx *types.Transaction, txIndex string, ldb *table.Table) []*types.KeyValue {
// sell limit
func (t *trade) saveSell(base *pty.ReceiptSellBase, ty int32, tx *types.Transaction, txIndex string, ldb *table.Table) {
sellorder := t.getSellOrderFromDb([]byte(base.SellID))
if ty == pty.TyLogTradeSellLimit && sellorder.SoldBoardlot == 0 {
......@@ -83,33 +84,25 @@ func (t *trade) saveSell(base *pty.ReceiptSellBase, ty int32, tx *types.Transact
} else {
t.updateSellLimit(tx, base, sellorder, txIndex, ldb)
}
return genSaveSellKv(sellorder)
}
func (t *trade) deleteSell(base *pty.ReceiptSellBase, ty int32, tx *types.Transaction, txIndex string, ldb *table.Table, tradedBoardlot int64) []*types.KeyValue {
func (t *trade) deleteSell(base *pty.ReceiptSellBase, ty int32, tx *types.Transaction, txIndex string, ldb *table.Table, tradedBoardlot int64) {
sellorder := t.getSellOrderFromDb([]byte(base.SellID))
if ty == pty.TyLogTradeSellLimit && sellorder.SoldBoardlot == 0 {
ldb.Del([]byte(txIndex))
} else {
t.rollBackSellLimit(tx, base, sellorder, txIndex, ldb, tradedBoardlot)
}
return genDeleteSellKv(sellorder)
}
func (t *trade) saveBuy(receiptTradeBuy *pty.ReceiptBuyBase, tx *types.Transaction, txIndex string, ldb *table.Table) []*types.KeyValue {
//tradelog.Info("save", "buy", receiptTradeBuy)
var kv []*types.KeyValue
func (t *trade) saveBuy(receiptTradeBuy *pty.ReceiptBuyBase, tx *types.Transaction, txIndex string, ldb *table.Table) {
order := t.genBuyMarket(tx, receiptTradeBuy, txIndex)
tradelog.Debug("trade BuyMarket save local", "order", order)
ldb.Add(order)
return saveBuyMarketOrderKeyValue(kv, receiptTradeBuy, pty.TradeOrderStatusBoughtOut, t.GetHeight())
}
func (t *trade) deleteBuy(receiptTradeBuy *pty.ReceiptBuyBase, txIndex string, ldb *table.Table) []*types.KeyValue {
var kv []*types.KeyValue
func (t *trade) deleteBuy(receiptTradeBuy *pty.ReceiptBuyBase, txIndex string, ldb *table.Table) {
ldb.Del([]byte(txIndex))
return deleteBuyMarketOrderKeyValue(kv, receiptTradeBuy, pty.TradeOrderStatusBoughtOut, t.GetHeight())
}
// BuyLimit Local
......@@ -123,7 +116,7 @@ func (t *trade) getBuyOrderFromDb(buyID []byte) *pty.BuyLimitOrder {
return &buyOrder
}
func (t *trade) saveBuyLimit(buy *pty.ReceiptBuyBase, ty int32, tx *types.Transaction, txIndex string, ldb *table.Table) []*types.KeyValue {
func (t *trade) saveBuyLimit(buy *pty.ReceiptBuyBase, ty int32, tx *types.Transaction, txIndex string, ldb *table.Table) {
buyOrder := t.getBuyOrderFromDb([]byte(buy.BuyID))
tradelog.Debug("Table", "buy-add", buyOrder)
if buyOrder.Status == pty.TradeOrderStatusOnBuy && buy.BoughtBoardlot == 0 {
......@@ -133,31 +126,25 @@ func (t *trade) saveBuyLimit(buy *pty.ReceiptBuyBase, ty int32, tx *types.Transa
} else {
t.updateBuyLimit(tx, buy, buyOrder, txIndex, ldb)
}
return genSaveBuyLimitKv(buyOrder)
}
func (t *trade) deleteBuyLimit(buy *pty.ReceiptBuyBase, ty int32, tx *types.Transaction, txIndex string, ldb *table.Table, traded int64) []*types.KeyValue {
func (t *trade) deleteBuyLimit(buy *pty.ReceiptBuyBase, ty int32, tx *types.Transaction, txIndex string, ldb *table.Table, traded int64) {
buyOrder := t.getBuyOrderFromDb([]byte(buy.BuyID))
if ty == pty.TyLogTradeBuyLimit && buy.BoughtBoardlot == 0 {
ldb.Del([]byte(txIndex))
} else {
t.rollbackBuyLimit(tx, buy, buyOrder, txIndex, ldb, traded)
}
return genDeleteBuyLimitKv(buyOrder)
}
func (t *trade) saveSellMarket(receiptTradeBuy *pty.ReceiptSellBase, tx *types.Transaction, txIndex string, ldb *table.Table) []*types.KeyValue {
var kv []*types.KeyValue
func (t *trade) saveSellMarket(receiptTradeBuy *pty.ReceiptSellBase, tx *types.Transaction, txIndex string, ldb *table.Table) {
order := t.genSellMarket(tx, receiptTradeBuy, txIndex)
ldb.Add(order)
return saveSellMarketOrderKeyValue(kv, receiptTradeBuy, pty.TradeOrderStatusSoldOut, t.GetHeight())
}
func (t *trade) deleteSellMarket(receiptTradeBuy *pty.ReceiptSellBase, txIndex string, ldb *table.Table) []*types.KeyValue {
var kv []*types.KeyValue
func (t *trade) deleteSellMarket(receiptTradeBuy *pty.ReceiptSellBase, txIndex string, ldb *table.Table) {
ldb.Del([]byte(txIndex))
return deleteSellMarketOrderKeyValue(kv, receiptTradeBuy, pty.TradeOrderStatusSoldOut, t.GetHeight())
}
// CheckReceiptExecOk return true to check if receipt ty is ok
......
......@@ -9,7 +9,6 @@ import (
"github.com/stretchr/testify/assert"
"github.com/33cn/chain33/types"
pty "github.com/33cn/plugin/plugin/dapp/trade/types"
)
......@@ -68,51 +67,11 @@ var (
}
)
func init() {
}
// 分叉不好构造, 直接生成对应的kv 记录进行对比
// 在save时有值的, 需要在del 时设置为空;或save 时设置为空, 在del 时有值的
func check(t *testing.T, kvSave, kvDel []*types.KeyValue) {
kvmapSave := map[string]string{}
for _, kv := range kvSave {
if string(kv.Value) != "IAMSELLID" && kv.Value != nil {
t.Error("onsale error")
}
kvmapSave[string(kv.Key)] = string(kv.Value)
}
for _, kv := range kvDel {
v, ok := kvmapSave[string(kv.Key)]
if !ok {
t.Error("error 1")
}
if len(v) == 0 && len(kv.Value) == 0 {
t.Error("error 2")
}
if len(v) != 0 && len(kv.Value) != 0 {
t.Error("error 3")
}
}
}
func TestOnsaleSaveDel(t *testing.T) {
kvOnsale := genSaveSellKv(&sellorderOnsale)
kvOnsaleDel := genDeleteSellKv(&sellorderOnsale)
check(t, kvOnsale, kvOnsaleDel)
}
func TestSoldOutSaveDel(t *testing.T) {
kv := genSaveSellKv(&sellorderSoldOut)
kvDel := genDeleteSellKv(&sellorderSoldOut)
check(t, kv, kvDel)
}
func TestRevokeSaveDel(t *testing.T) {
kv := genSaveSellKv(&sellorderRevoked)
kvDel := genDeleteSellKv(&sellorderRevoked)
check(t, kv, kvDel)
// TODO 几个测试数据 linter 不报错, 修改好后写测试可能需要用
func Test_Order(t *testing.T) {
assert.NotNil(t, &sellorderOnsale)
assert.NotNil(t, &sellorderSoldOut)
assert.NotNil(t, &sellorderRevoked)
}
func TestPriceCheck(t *testing.T) {
......
......@@ -12,7 +12,6 @@ import (
"strings"
"github.com/33cn/chain33/client"
"github.com/33cn/chain33/common"
dbm "github.com/33cn/chain33/common/db"
"github.com/33cn/chain33/system/dapp"
"github.com/33cn/chain33/types"
......@@ -116,27 +115,6 @@ func getSellOrderFromID(sellID []byte, db dbm.KV) (*pty.SellOrder, error) {
return &sellOrder, nil
}
func getTx(txHash []byte, db dbm.KV, api client.QueueProtocolAPI) (*types.TxResult, error) {
hash, err := common.FromHex(string(txHash))
if err != nil {
return nil, err
}
value, err := api.QueryTx(&types.ReqHash{Hash: hash})
if err != nil {
tradelog.Error("getTx", "Failed to get value from db with getTx", string(txHash))
return nil, err
}
txResult := types.TxResult{
Height: value.Height,
Index: int32(value.Index),
Tx: value.Tx,
Receiptdate: value.Receipt,
Blocktime: value.Blocktime,
ActionName: value.ActionName,
}
return &txResult, nil
}
func (selldb *sellDB) getKVSet() (kvset []*types.KeyValue) {
value := types.Encode(&selldb.SellOrder)
key := []byte(selldb.SellID)
......
package executor
import (
"bytes"
"testing"
dbm "github.com/33cn/chain33/common/db"
"github.com/33cn/chain33/types"
"github.com/33cn/chain33/util"
"github.com/stretchr/testify/assert"
)
func Test_Upgrade(t *testing.T) {
dir, db, localdb := util.CreateTestDB()
defer util.CloseTestDB(dir, db)
assert.NotNil(t, localdb)
// test empty db
err := callUpgradeLocalDBV2(localdb)
assert.Nil(t, err)
// test again
setVersion(localdb, 1)
err = callUpgradeLocalDBV2(localdb)
assert.Nil(t, err)
// test with data
// create for test
prefixes := []string{
sellOrderSHTAS,
sellOrderASTS,
sellOrderATSS,
sellOrderTSPAS,
buyOrderSHTAS,
buyOrderASTS,
buyOrderATSS,
buyOrderTSPAS,
orderASTHK,
}
localdb.Set([]byte(prefixes[0]+"xxxx1"), []byte("xx1"))
localdb.Set([]byte(prefixes[0]+"xxxx2"), []byte("xx2"))
localdb.Set([]byte(prefixes[0]+"xxxx3"), []byte("xx3"))
localdb.Set([]byte(prefixes[1]+"xxxx3"), []byte("xx3"))
//tabV2 := NewOrderTableV2(localdb)
tabV1 := NewOrderTable(localdb)
tabV1.Add(order1)
tabV1.Add(order2)
tabV1.Add(order3)
kvs, err := tabV1.Save()
assert.Nil(t, err)
for _, kv := range kvs {
localdb.Set(kv.Key, kv.Value)
}
// 初次升级
setVersion(localdb, 1)
err = callUpgradeLocalDBV2(localdb)
assert.Nil(t, err)
// 已经是升级后的版本了, 不需要再升级
err = callUpgradeLocalDBV2(localdb)
assert.Nil(t, err)
// 先修改版本去升级,但数据已经升级了, 所以处理数据量为0
setVersion(localdb, 1)
err = callUpgradeLocalDBV2(localdb)
assert.Nil(t, err)
// just print log
//assert.NotNil(t, nil)
}
func callUpgradeLocalDBV2(localdb dbm.KVDB) error {
return UpgradeLocalDBV2(localdb, "bty")
}
// 测试更新后是否删除完全, asset 设置
func Test_UpgradeOrderAsset(t *testing.T) {
dir, db, localdb := util.CreateTestDB()
defer util.CloseTestDB(dir, db)
assert.NotNil(t, localdb)
tabV1 := NewOrderTable(localdb)
tabV1.Add(order3)
kvs, err := tabV1.Save()
assert.Nil(t, err)
for _, kv := range kvs {
localdb.Set(kv.Key, kv.Value)
}
err = callUpgradeLocalDBV2(localdb)
assert.Nil(t, err)
v1, err := localdb.List([]byte("LODB-trade-order"), nil, 0, dbm.ListASC|dbm.ListWithKey)
assert.Nil(t, err)
assert.NotNil(t, v1)
primaryKey := "000000000000300001"
prefix := "LODB-trade-order_v2"
for _, v := range v1 {
var kv types.KeyValue
err := types.Decode(v, &kv)
assert.Nil(t, err)
// 前缀都是v2, 删除完成测试
if !bytes.Equal([]byte("LODB-trade-order_v2-d-000000000000300001"), kv.Key) {
assert.Equal(t, []byte(primaryKey), kv.Value)
assert.True(t, bytes.HasPrefix(kv.Key, []byte(prefix)))
}
}
// assert 前缀测试
v, err := localdb.Get([]byte("LODB-trade-order_v2-m-asset-coins.bty_token.CCNY-000000000000300001"))
assert.Nil(t, err)
assert.Equal(t, primaryKey, string(v))
// just print log
//assert.NotNil(t, nil)
}
......@@ -437,7 +437,7 @@ func (mvccs *KVMVCCStore) GetHashRdm(hash []byte, height int64) ([]byte, error)
func (mvccs *KVMVCCStore) GetFirstHashRdm(hash []byte) ([]byte, error) {
prefix := append(rdmHashPrefix, hash...)
list := dbm.NewListHelper(mvccs.db)
values := list.IteratorScanFromFirst(prefix, 1)
values := list.IteratorScanFromFirst(prefix, 1, dbm.ListASC)
if len(values) == 1 {
return values[0], nil
}
......
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