Commit 17b6b5f4 authored by pengjun's avatar pengjun

Merge remote-tracking branch 'remotes/origin/master' into issue-627-collateralize-v2

parents 34bc0575 9f95ccab
......@@ -116,8 +116,12 @@ chain33_SignRawTx() {
local txHex="$1"
local priKey="$2"
local MAIN_HTTP=$3
local expire="120s"
if [ -n "$4" ]; then
expire=$4
fi
local req='"method":"Chain33.SignRawTx","params":[{"privkey":"'"$priKey"'","txHex":"'"$txHex"'","expire":"120s"}]'
local req='"method":"Chain33.SignRawTx","params":[{"privkey":"'"$priKey"'","txHex":"'"$txHex"'","expire":"'"$expire"'"}]'
signedTx=$(curl -ksd "{$req}" "${MAIN_HTTP}" | jq -r ".result")
if [ "$signedTx" != null ]; then
......
......@@ -10,17 +10,18 @@ function dapp_test_rpc() {
if [ -d dapptest ]; then
cp "$DAPP_TEST_COMMON" dapptest/
cd dapptest || return
rm -f "retries.log"
rm -f "jobs.log"
rm -rf "outdir"
dapps=$(find . -maxdepth 1 -type d ! -name dapptest ! -name . | sed 's/^\.\///' | sort)
echo "dapps list: $dapps"
set +e
parallel -k --joblog ./jobs.log 'echo tried {} >>./retries.log; ./{}/"'"${RPC_TESTFILE}"'" "'"$ip"'"' ::: "$dapps"
parallel -k --results outdir --joblog ./jobs.log ./{}/"${RPC_TESTFILE}" "$ip" ::: "$dapps"
local ret=$?
# retries 3 times if one dapp fail
echo "============ # retried dapps log: ============="
cat ./retries.log
if [ $ret -ne 0 ]; then
wrongdapps=$(awk '{print $7,$9 }' jobs.log | grep -a 1 | awk -F '/' '{print $2}')
parallel -k 'cat ./outdir/1/{}/stderr; cat ./outdir/1/{}/stdout' ::: "$wrongdapps"
fi
echo "============ # check dapps test log: ============="
cat ./jobs.log
set -e
......
......@@ -255,6 +255,7 @@ ForkParacrossCommitTx=0
ForkLoopCheckCommitTxDone=0
#平行链分阶段自共识支持合约配置,缺省是0
ForkParaSelfConsStages=0
ForkParaAssetTransferRbk=0
[fork.sub.evm]
Enable=0
......
......@@ -22,6 +22,7 @@ import (
_ "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
......
package executor
import (
"fmt"
"math/rand"
"testing"
"time"
"github.com/33cn/chain33/account"
"github.com/33cn/chain33/client"
"github.com/33cn/chain33/common/address"
"github.com/33cn/chain33/types"
"github.com/33cn/chain33/util"
"github.com/33cn/chain33/common"
"github.com/33cn/chain33/common/crypto"
dbm "github.com/33cn/chain33/common/db"
"github.com/33cn/chain33/queue"
oty "github.com/33cn/plugin/plugin/dapp/oracle/types"
"github.com/stretchr/testify/assert"
//"github.com/33cn/chain33/types/jsonpb"
"strings"
)
type execEnv struct {
blockTime int64
blockHeight int64
difficulty uint64
}
var (
PrivKeyA = "0x6da92a632ab7deb67d38c0f6560bcfed28167998f6496db64c258d5e8393a81b" // 1KSBd17H7ZK8iT37aJztFB22XGwsPTdwE4
Nodes = [][]byte{
[]byte("1KSBd17H7ZK8iT37aJztFB22XGwsPTdwE4"),
[]byte("1JRNjdEqp4LJ5fqycUBm9ayCKSeeskgMKR"),
[]byte("1NLHPEcbTWWxxU3dGUZBhayjrCHD3psX7k"),
[]byte("1MCftFynyvG2F4ED5mdHYgziDxx6vDrScs"),
}
)
var (
r *rand.Rand
)
func init() {
r = rand.New(rand.NewSource(types.Now().UnixNano()))
}
func TestOrace(t *testing.T) {
cfg := types.NewChain33Config(strings.Replace(types.GetDefaultCfgstring(), "Title=\"local\"", "Title=\"chain33\"", 1))
Init(oty.OracleX, cfg, nil)
total := 100 * types.Coin
accountA := types.Account{
Balance: total,
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]),
}
accountD := types.Account{
Balance: total,
Frozen: 0,
Addr: string(Nodes[3]),
}
execAddr := address.ExecAddress(oty.OracleX)
stateDB, _ := dbm.NewGoMemDB("1", "2", 1000)
_, _, kvdb := util.CreateTestDB()
accA, _ := account.NewAccountDB(cfg, "coins", "bty", stateDB)
accA.SaveExecAccount(execAddr, &accountA)
accB, _ := account.NewAccountDB(cfg, "coins", "bty", stateDB)
accB.SaveExecAccount(execAddr, &accountB)
accC, _ := account.NewAccountDB(cfg, "coins", "bty", stateDB)
accC.SaveExecAccount(execAddr, &accountC)
accD, _ := account.NewAccountDB(cfg, "coins", "bty", stateDB)
accD.SaveExecAccount(execAddr, &accountD)
env := execEnv{
10,
cfg.GetDappFork(oty.OracleX, "Enable"),
1539918074,
}
// set config key 授权
item := &types.ConfigItem{
Key: "mavl-manage-oracle-publish-event",
Value: &types.ConfigItem_Arr{
Arr: &types.ArrayConfig{Value: []string{"1KSBd17H7ZK8iT37aJztFB22XGwsPTdwE4"}},
},
}
stateDB.Set([]byte(item.Key), types.Encode(item))
// publish event
ety := types.LoadExecutorType(oty.OracleX)
tx, err := ety.Create("EventPublish", &oty.EventPublish{Type: "football", SubType: "Premier League", Time: time.Now().AddDate(0, 0, 1).Unix(),
Content: fmt.Sprintf("{\"team%d\":\"ChelSea\", \"team%d\":\"Manchester\",\"resultType\":\"score\"}", r.Int()%10, r.Int()%10),
Introduction: "guess the sore result of football game between ChelSea and Manchester in 2019-01-21 14:00:00"})
assert.Nil(t, err)
tx, err = types.FormatTx(cfg, oty.OracleX, tx)
assert.Nil(t, err)
tx, err = signTx(tx, PrivKeyA)
assert.Nil(t, err)
t.Log("tx", tx)
exec := newOracle()
q := queue.New("channel")
q.SetConfig(cfg)
api, _ := client.New(q.Client(), nil)
exec.SetAPI(api)
exec.SetStateDB(stateDB)
exec.SetLocalDB(kvdb)
exec.SetEnv(1, env.blockTime, env.difficulty)
receipt, err := exec.Exec(tx, int(1))
if err != nil {
t.Error(err)
}
for _, kv := range receipt.KV {
stateDB.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 {
t.Error(err)
}
for _, kv := range set.KV {
kvdb.Set(kv.Key, kv.Value)
}
var eventID string
//获取eventID
for _, log := range receipt.Logs {
if log.Ty >= oty.TyLogEventPublish && log.Ty <= oty.TyLogResultPublish {
status := oty.ReceiptOracle{}
err := types.Decode(log.Log, &status)
assert.Nil(t, err)
eventID = status.EventID
}
}
t.Log("eventID:", eventID)
//查询事件
msg, err := exec.Query(oty.FuncNameQueryOracleListByIDs, types.Encode(&oty.QueryOracleInfos{
EventID: []string{eventID}}))
if err != nil {
t.Error(err)
}
t.Log(msg)
reply := msg.(*oty.ReplyOracleStatusList)
assert.Equal(t, int32(oty.EventPublished), reply.Status[0].Status.Status)
//通过状态查询eventID
msg, err = exec.Query(oty.FuncNameQueryEventIDByStatus, types.Encode(&oty.QueryEventID{
Status: int32(oty.EventPublished)}))
if err != nil {
t.Error(err)
}
t.Log(msg)
reply2 := msg.(*oty.ReplyEventIDs)
assert.Equal(t, eventID, reply2.EventID[0])
//通过状态和地址查询
msg, err = exec.Query(oty.FuncNameQueryEventIDByAddrAndStatus, types.Encode(&oty.QueryEventID{
Status: int32(oty.EventPublished), Addr: string(Nodes[0])}))
if err != nil {
t.Error(err)
}
t.Log(msg)
reply3 := msg.(*oty.ReplyEventIDs)
assert.Equal(t, eventID, reply3.EventID[0])
//通过类型和状态查询
msg, err = exec.Query(oty.FuncNameQueryEventIDByTypeAndStatus, types.Encode(&oty.QueryEventID{
Status: int32(oty.EventPublished), Type: "football"}))
if err != nil {
t.Error(err)
}
t.Log(msg)
reply4 := msg.(*oty.ReplyEventIDs)
assert.Equal(t, eventID, reply4.EventID[0])
//pre publish result
tx, err = ety.Create("ResultPrePublish", &oty.ResultPrePublish{EventID: eventID,
Result: fmt.Sprintf("%d:%d", r.Int()%10, r.Int()%10),
Source: "sina sport"})
assert.Nil(t, err)
tx, err = types.FormatTx(cfg, oty.OracleX, tx)
assert.Nil(t, err)
tx, err = signTx(tx, PrivKeyA)
assert.Nil(t, err)
exec.SetEnv(env.blockHeight+1, env.blockTime+20, env.difficulty+1)
receipt, err = exec.Exec(tx, int(1))
if err != nil {
t.Error(err)
}
for _, kv := range receipt.KV {
stateDB.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 {
t.Error(err)
}
for _, kv := range set.KV {
kvdb.Set(kv.Key, kv.Value)
}
msg, err = exec.Query(oty.FuncNameQueryOracleListByIDs, types.Encode(&oty.QueryOracleInfos{
EventID: []string{eventID}}))
if err != nil {
t.Error(err)
}
t.Log(msg)
reply = msg.(*oty.ReplyOracleStatusList)
assert.Equal(t, int32(oty.ResultPrePublished), reply.Status[0].Status.Status)
//publish result
tx, err = ety.Create("ResultPublish", &oty.ResultPublish{EventID: eventID,
Result: fmt.Sprintf("%d:%d", r.Int()%10, r.Int()%10),
Source: "sina sport"})
assert.Nil(t, err)
tx, err = types.FormatTx(cfg, oty.OracleX, tx)
assert.Nil(t, err)
tx, err = signTx(tx, PrivKeyA)
assert.Nil(t, err)
exec.SetEnv(env.blockHeight+1, env.blockTime+20, env.difficulty+1)
receipt, err = exec.Exec(tx, int(1))
if err != nil {
t.Error(err)
}
for _, kv := range receipt.KV {
stateDB.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 {
t.Error(err)
}
for _, kv := range set.KV {
kvdb.Set(kv.Key, kv.Value)
}
msg, err = exec.Query(oty.FuncNameQueryOracleListByIDs, types.Encode(&oty.QueryOracleInfos{
EventID: []string{eventID}}))
if err != nil {
t.Error(err)
}
t.Log(msg)
reply = msg.(*oty.ReplyOracleStatusList)
assert.Equal(t, int32(oty.ResultPublished), reply.Status[0].Status.Status)
// publish event
tx, err = ety.Create("EventPublish", &oty.EventPublish{Type: "football", SubType: "Premier League", Time: time.Now().AddDate(0, 0, 1).Unix(),
Content: fmt.Sprintf("{\"team%d\":\"ChelSea\", \"team%d\":\"Manchester\",\"resultType\":\"score\"}", r.Int()%10, r.Int()%10),
Introduction: "guess the sore result of football game between ChelSea and Manchester in 2019-03-21 14:00:00"})
assert.Nil(t, err)
tx, err = types.FormatTx(cfg, oty.OracleX, tx)
assert.Nil(t, err)
tx, err = signTx(tx, PrivKeyA)
assert.Nil(t, err)
t.Log("tx", tx)
receipt, err = exec.Exec(tx, int(1))
if err != nil {
t.Error(err)
}
for _, kv := range receipt.KV {
stateDB.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 {
t.Error(err)
}
for _, kv := range set.KV {
kvdb.Set(kv.Key, kv.Value)
}
//var eventID string
//获取eventID
for _, log := range receipt.Logs {
if log.Ty >= oty.TyLogEventPublish && log.Ty <= oty.TyLogResultPublish {
status := oty.ReceiptOracle{}
err := types.Decode(log.Log, &status)
assert.Nil(t, err)
eventID = status.EventID
}
}
t.Log("eventID:", eventID)
//查询事件
msg, err = exec.Query(oty.FuncNameQueryOracleListByIDs, types.Encode(&oty.QueryOracleInfos{
EventID: []string{eventID}}))
if err != nil {
t.Error(err)
}
t.Log(msg)
reply = msg.(*oty.ReplyOracleStatusList)
assert.Equal(t, int32(oty.EventPublished), reply.Status[0].Status.Status)
//EventAbort
tx, err = ety.Create("EventAbort", &oty.EventAbort{EventID: eventID})
assert.Nil(t, err)
tx, err = types.FormatTx(cfg, oty.OracleX, tx)
assert.Nil(t, err)
tx, err = signTx(tx, PrivKeyA)
assert.Nil(t, err)
exec.SetEnv(env.blockHeight+1, env.blockTime+20, env.difficulty+1)
receipt, err = exec.Exec(tx, int(1))
if err != nil {
t.Error(err)
}
for _, kv := range receipt.KV {
stateDB.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 {
t.Error(err)
}
for _, kv := range set.KV {
kvdb.Set(kv.Key, kv.Value)
}
msg, err = exec.Query(oty.FuncNameQueryOracleListByIDs, types.Encode(&oty.QueryOracleInfos{
EventID: []string{eventID}}))
if err != nil {
t.Error(err)
}
t.Log(msg)
reply = msg.(*oty.ReplyOracleStatusList)
assert.Equal(t, int32(oty.EventAborted), reply.Status[0].Status.Status)
//pre publish result
tx, err = ety.Create("ResultPrePublish", &oty.ResultPrePublish{EventID: eventID,
Result: fmt.Sprintf("%d:%d", r.Int()%10, r.Int()%10),
Source: "sina sport"})
assert.Nil(t, err)
tx, err = types.FormatTx(cfg, oty.OracleX, tx)
assert.Nil(t, err)
tx, err = signTx(tx, PrivKeyA)
assert.Nil(t, err)
exec.SetEnv(env.blockHeight+1, env.blockTime+20, env.difficulty+1)
receipt, err = exec.Exec(tx, int(1))
assert.Equal(t, oty.ErrResultPrePublishNotAllowed, err)
// publish event
tx, err = ety.Create("EventPublish", &oty.EventPublish{Type: "football", SubType: "Premier League", Time: time.Now().AddDate(0, 0, 1).Unix(),
Content: fmt.Sprintf("{\"team%d\":\"ChelSea\", \"team%d\":\"Manchester\",\"resultType\":\"score\"}", r.Int()%10, r.Int()%10),
Introduction: "guess the sore result of football game between ChelSea and Manchester in 2019-03-21 14:00:00"})
assert.Nil(t, err)
tx, err = types.FormatTx(cfg, oty.OracleX, tx)
assert.Nil(t, err)
tx, err = signTx(tx, PrivKeyA)
assert.Nil(t, err)
t.Log("tx", tx)
receipt, err = exec.Exec(tx, int(1))
if err != nil {
t.Error(err)
}
for _, kv := range receipt.KV {
stateDB.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 {
t.Error(err)
}
for _, kv := range set.KV {
kvdb.Set(kv.Key, kv.Value)
}
//var eventID string
//获取eventID
for _, log := range receipt.Logs {
if log.Ty >= oty.TyLogEventPublish && log.Ty <= oty.TyLogResultPublish {
status := oty.ReceiptOracle{}
err := types.Decode(log.Log, &status)
assert.Nil(t, err)
eventID = status.EventID
}
}
t.Log("eventID:", eventID)
//查询事件
msg, err = exec.Query(oty.FuncNameQueryOracleListByIDs, types.Encode(&oty.QueryOracleInfos{
EventID: []string{eventID}}))
if err != nil {
t.Error(err)
}
t.Log(msg)
reply = msg.(*oty.ReplyOracleStatusList)
assert.Equal(t, int32(oty.EventPublished), reply.Status[0].Status.Status)
//pre publish result
tx, err = ety.Create("ResultPrePublish", &oty.ResultPrePublish{EventID: eventID,
Result: fmt.Sprintf("%d:%d", r.Int()%10, r.Int()%10),
Source: "sina sport"})
assert.Nil(t, err)
tx, err = types.FormatTx(cfg, oty.OracleX, tx)
assert.Nil(t, err)
tx, err = signTx(tx, PrivKeyA)
assert.Nil(t, err)
exec.SetEnv(env.blockHeight+1, env.blockTime+20, env.difficulty+1)
receipt, err = exec.Exec(tx, int(1))
if err != nil {
t.Error(err)
}
for _, kv := range receipt.KV {
stateDB.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 {
t.Error(err)
}
for _, kv := range set.KV {
kvdb.Set(kv.Key, kv.Value)
}
msg, err = exec.Query(oty.FuncNameQueryOracleListByIDs, types.Encode(&oty.QueryOracleInfos{
EventID: []string{eventID}}))
if err != nil {
t.Error(err)
}
t.Log(msg)
reply = msg.(*oty.ReplyOracleStatusList)
assert.Equal(t, int32(oty.ResultPrePublished), reply.Status[0].Status.Status)
//ResultAbort
tx, err = ety.Create("ResultAbort", &oty.ResultAbort{EventID: eventID})
assert.Nil(t, err)
tx, err = types.FormatTx(cfg, oty.OracleX, tx)
assert.Nil(t, err)
tx, err = signTx(tx, PrivKeyA)
assert.Nil(t, err)
exec.SetEnv(env.blockHeight+1, env.blockTime+20, env.difficulty+1)
receipt, err = exec.Exec(tx, int(1))
if err != nil {
t.Error(err)
}
for _, kv := range receipt.KV {
stateDB.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 {
t.Error(err)
}
for _, kv := range set.KV {
kvdb.Set(kv.Key, kv.Value)
}
msg, err = exec.Query(oty.FuncNameQueryOracleListByIDs, types.Encode(&oty.QueryOracleInfos{
EventID: []string{eventID}}))
if err != nil {
t.Error(err)
}
t.Log(msg)
reply = msg.(*oty.ReplyOracleStatusList)
assert.Equal(t, int32(oty.ResultAborted), reply.Status[0].Status.Status)
}
func signTx(tx *types.Transaction, hexPrivKey string) (*types.Transaction, error) {
signType := types.SECP256K1
c, err := crypto.New(types.GetSignName(oty.OracleX, 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
}
FROM ubuntu:16.04
WORKDIR /root
COPY chain33 chain33
COPY chain33-cli chain33-cli
COPY entrypoint.sh entrypoint.sh
COPY chain33.toml chain33*.toml ./
CMD ["/root/chain33", "-f", "/root/chain33.toml"]
op := "start"
.PHONY: docker-compose help
docker-compose: ## build docker-compose for chain33 run
@./docker-compose.sh $(op)
docker-compose-down: ## build docker-compose for chain33 run
@cd temp ;docker-compose down;cd ..
help: ## Display this help screen
@printf "Help doc:\nUsage: make docker-compose op=[command]\n"
@printf "[command]\n"
@printf "[nodegroup]: create super node group if not create \n"
@printf "[wallet]: set node wallet private key if not set \n"
\ No newline at end of file
paraName="test"
#genesisAccount=""
#genesisAmount=100000000
#mainStartHeight=4800000
#authAccount=()
#authPrikey=()
##docker8901端口暴露到宿主机的端口
#authPort=("18901" "18902" "18903" "18904")
#
##需要和chain33 主链保持一致
#superManager="['1JmFaA6unrCFYEWPGRi7uuXY1KthTJxJEP']"
#
##nodegroup create
##申请超级账户需要在主链冻结币数量
#authFrozenCoins=0
#nodeGroupApplier=""
#applierPrikey=""
#superManagerPrikey=""
#### 测试链配置,主链配置需要把如下测试链配置屏蔽 ##########
genesisAccount="14KEKbYtKKQm4wMthSK9J4La4nAiidGozt"
genesisAmount=100000000
mainStartHeight=4000000
authAccount=( "1KSBd17H7ZK8iT37aJztFB22XGwsPTdwE4" "1JRNjdEqp4LJ5fqycUBm9ayCKSeeskgMKR" "1NLHPEcbTWWxxU3dGUZBhayjrCHD3psX7k" "1MCftFynyvG2F4ED5mdHYgziDxx6vDrScs")
authPrikey=("0x6da92a632ab7deb67d38c0f6560bcfed28167998f6496db64c258d5e8393a81b" "0x19c069234f9d3e61135fefbeb7791b149cdf6af536f26bebb310d4cd22c3fee4" "0x7a80a1f75d7360c6123c32a78ecf978c1ac55636f87892df38d8b85a9aeff115" "0xcacb1f5d51700aea07fca2246ab43b0917d70405c65edea9b5063d72eb5c6b71")
authPort=("18901" "18902" "18903" "18904")
#需要和chain33 主链保持一致
superManager="['12qyocayNF7Lv6C9qW4avxs2E7U41fKSfv']"
tokenApprs="['12qyocayNF7Lv6C9qW4avxs2E7U41fKSfv']"
#nodegroup create
authFrozenCoins=0
nodeGroupApplier="1KSBd17H7ZK8iT37aJztFB22XGwsPTdwE4"
applierPrikey="0x6da92a632ab7deb67d38c0f6560bcfed28167998f6496db64c258d5e8393a81b"
superManagerPrikey="4257D8692EF7FE13C68B65D6A52F03933DB2FA5CE8FAF210B5B8B80C721CED01"
\ No newline at end of file
#!/usr/bin/env bash
# shellcheck disable=SC2154
set -e
PWD=$(cd "$(dirname "$0")" && pwd)
export PATH="$PWD:$PATH"
buildpath="temp"
NODE1="$buildpath""_parachain1_1"
CLI="docker exec ${NODE1} /root/chain33-cli"
NODE2="$buildpath""_parachain2_1"
NODE3="$buildpath""_parachain3_1"
NODE4="$buildpath""_parachain4_1"
CHAIN33_CLI="chain33-cli"
containers=("${NODE1}" "${NODE2}" "${NODE3}" "${NODE4}")
## global config ###
sedfix=""
if [ "$(uname)" == "Darwin" ]; then
sedfix=".bak"
fi
# shellcheck source=/dev/null
source config
####################
function para_init() {
local index=1
for auth in "${authAccount[@]}"; do
tomlfile="chain33.para.$index.toml"
para_set_toml "$tomlfile"
sed -i $sedfix 's/^authAccount=.*/authAccount="'''"$auth"'''"/g' "$tomlfile"
((index++))
done
}
function para_set_toml() {
cp chain33.para.toml "${1}"
sed -i $sedfix 's/^Title.*/Title="user.p.'''"$paraName"'''."/g' "${1}"
sed -i $sedfix 's/^startHeight=.*/startHeight='''"$mainStartHeight"'''/g' "${1}"
# rpc
sed -i $sedfix 's/^jrpcBindAddr=.*/jrpcBindAddr="0.0.0.0:8901"/g' "${1}"
sed -i $sedfix 's/^grpcBindAddr=.*/grpcBindAddr="0.0.0.0:8902"/g' "${1}"
sed -i $sedfix 's/^whitelist=.*/whitelist=["localhost","127.0.0.1","0.0.0.0"]/g' "${1}"
if [ -n "$superManager" ]; then
# shellcheck disable=SC1004
sed -i $sedfix 's/^superManager=.*/superManager='''"$superManager"'''/g' "${1}"
fi
if [ -n "$tokenApprs" ]; then
# shellcheck disable=SC1004
sed -i $sedfix 's/^tokenApprs=.*/tokenApprs='''"$tokenApprs"'''/g' "${1}"
fi
}
function para_set_wallet() {
echo "=========== # para set wallet ============="
for ((i = 0; i < ${#authAccount[@]}; i++)); do
para_import_wallet "${authPort[$i]}" "${authPrikey[$i]}"
done
}
function para_import_wallet() {
local key=$2
local port=$1
echo "=========== # save seed to wallet ============="
./$CHAIN33_CLI --rpc_laddr "http://localhost:$port" seed save -p 1314fuzamei -s "tortoise main civil member grace happy century convince father cage beach hip maid merry rib"
echo "=========== # unlock wallet ============="
./$CHAIN33_CLI --rpc_laddr "http://localhost:$port" wallet unlock -p 1314fuzamei -t 0
echo "=========== # import private key ============="
echo "key: ${key}"
./$CHAIN33_CLI --rpc_laddr "http://localhost:$port" account import_key -k "${key}" -l "paraAuthAccount"
echo "=========== # close auto mining ============="
./$CHAIN33_CLI --rpc_laddr "http://localhost:$port" wallet auto_mine -f 0
echo "=========== # wallet status ============="
./$CHAIN33_CLI --rpc_laddr "http://localhost:$port" wallet status
}
function start() {
echo "=========== # docker-compose ps ============="
docker-compose ps
docker-compose down
# create and run docker-compose container
docker-compose up --build -d
local SLEEP=10
echo "=========== sleep ${SLEEP}s ============="
sleep ${SLEEP}
docker-compose ps
# query node run status
echo "status"
check_docker_status
# ./chain33-cli --rpc_laddr http://localhost:18901 block last_header
$CLI --rpc_laddr http://localhost:8901 block last_header
}
function check_docker_status() {
status=$(docker-compose ps | grep parachain1_1 | awk '{print $6}')
statusPara=$(docker-compose ps | grep parachain1_1 | awk '{print $3}')
if [ "${status}" == "Exit" ] || [ "${statusPara}" == "Exit" ]; then
echo "=========== chain33 service Exit logs ========== "
docker-compose logs parachain1
echo "=========== chain33 service Exit logs End========== "
fi
}
function check_docker_container() {
echo "============== check_docker_container ==============================="
for con in "${containers[@]}"; do
runing=$(docker inspect "${con}" | jq '.[0].State.Running')
if [ ! "${runing}" ]; then
docker inspect "${con}"
echo "check ${con} not actived!"
exit 1
fi
done
}
function query_tx() {
sleep 5
local times=100
while true; do
ret=$(${CLI} --rpc_laddr http://localhost:8901 tx query -s "${1}" | jq -r ".tx.hash")
echo "query hash is ${1}, return ${ret} "
if [ "${ret}" != "${1}" ]; then
sleep 5
times=$((times - 1))
if [ $times -le 0 ]; then
echo "query tx=$1 failed"
exit 1
fi
else
echo "query tx=$1 success"
break
fi
done
}
function create_yml() {
touch docker-compose.yml
cat >>docker-compose.yml <<EOF
version: '3'
services:
EOF
for ((i = 1; i <= ${#authAccount[@]}; i++)); do
cat >>docker-compose.yml <<EOF
parachain$i:
build:
context: .
entrypoint: /root/entrypoint.sh
environment:
PARAFILE: "/root/chain33.para.$i.toml"
ports:
- "1890$i:8901"
volumes:
- "../storage/parachain$i/paradatadir:/root/paradatadir"
- "../storage/parachain$i/logs:/root/logs"
EOF
done
}
function create_storage() {
mkdir -p storage
cd storage
for ((i = 0; i < ${#authAccount[@]}; i++)); do
dirfile="parachain$i"
mkdir -p "$dirfile"
done
cd ..
}
function create_build() {
rm -rf $buildpath
mkdir -p $buildpath
cp chain33* Dockerfile ./*.sh "$buildpath"/
cd $buildpath
create_yml
}
function para_create_nodegroup() {
echo "=========== # para chain create node group ============="
local auths=""
for auth in "${authAccount[@]}"; do
if [ -z $auths ]; then
auths="$auth"
else
auths="$auths,$auth"
fi
done
echo "auths=$auths"
##apply
txhash=$(${CLI} --rpc_laddr http://localhost:8901 --paraName "user.p.$paraName." send para nodegroup apply -a "$auths" -c "${authFrozenCoins}" -k "$applierPrikey")
echo "tx=$txhash"
query_tx "${txhash}"
id=$txhash
echo "need super manager approve id=$txhash"
if [ -n "$superManagerPrikey" ]; then
echo "=========== # para chain approve node group ============="
##approve
txhash=$(${CLI} --rpc_laddr http://localhost:8901 --paraName "user.p.$paraName." send para nodegroup approve -i "$id" -c "${authFrozenCoins}" -k "$superManagerPrikey")
echo "tx=$txhash"
query_tx "${CLI}" "${txhash}"
status=$(${CLI} --rpc_laddr http://localhost:8901 --paraName "user.p.$paraName." para nodegroup status | jq -r ".status")
if [ "$status" != 2 ]; then
echo "status not approve status=$status"
exit 1
fi
${CLI} --rpc_laddr http://localhost:8901 --paraName "user.p.$paraName." para nodegroup addrs
fi
echo "======== super node group config end ==================="
}
function main() {
echo "==============================parachain startup op=$1========================================================"
### init para ####
if [ "$1" == "start" ]; then
create_storage
create_build
para_init
### start docker ####
start
### finish ###
check_docker_container
fi
if [ "$1" == "nodegroup" ]; then
para_create_nodegroup
fi
if [ "$1" == "wallet" ]; then
para_set_wallet
fi
echo "===============================parachain startup end========================================================="
}
# run script
main "$1"
version: '3'
services:
\ No newline at end of file
#!/usr/bin/env bash
/root/chain33 -f "$PARAFILE"
......@@ -293,36 +293,26 @@ function paracross_ListNodeStatus() {
para_test_addr="1MAuE8QSbbech3bVKK2JPJJxYxNtT95oSU"
para_test_prikey="0x24d1fad138be98eebee31440f144aa38c404533f40862995282162bc538e91c8"
function paracross_testTxGroup() {
local para_ip=$1
ispara=$(echo '"'"${para_ip}"'"' | jq '.|contains("8901")')
echo "ipara=$ispara"
local paracross_addr=""
local main_ip=${para_ip//8901/8801}
function paracross_txgroupex() {
local amount_transfer=$1
local amount_trade=$2
local para_ip=$3
paracross_addr=$(curl -ksd '{"method":"Chain33.ConvertExectoAddr","params":[{"execname":"paracross"}]}' "${main_ip}" | jq -r ".result")
echo "paracross_addr=$paracross_addr"
#execer
local paracross_execer_name="user.p.para.paracross"
local trade_exec_name="user.p.para.trade"
local trade_exec_addr="12bihjzbaYWjcpDiiy9SuAWeqNksQdiN13"
local amount_trade=100000000
local amount_transfer=800000000
chain33_ImportPrivkey "${para_test_prikey}" "${para_test_addr}" "paracross-transfer6" "${main_ip}"
# tx fee + transfer 10 coins
chain33_applyCoins "${para_test_addr}" 1000000000 "${main_ip}"
chain33_QueryBalance "${para_test_addr}" "$main_ip"
#deposit 8 coins to paracross
chain33_SendToAddress "${para_test_addr}" "$paracross_addr" "$amount_transfer" "${main_ip}"
chain33_QueryExecBalance "${para_test_addr}" "paracross" "${main_ip}"
# 资产从主链转移到平行链
tx_hash_asset=$(curl -ksd '{"method":"Chain33.CreateTransaction","params":[{"execer":"'"${paracross_execer_name}"'","actionName":"ParacrossAssetTransfer","payload":{"execName":"'"${paracross_execer_name}"'","to":"'"$para_test_addr"'","amount":'${amount_transfer}'}}]}' "${para_ip}" | jq -r ".result")
#curl -ksd '{"method":"Chain33.CreateTransaction","params":[{"execer":"user.p.para.paracross","actionName":"ParacrossAssetTransfer","payload":{"execName":"user.p.para.paracross","to":"1MAuE8QSbbech3bVKK2JPJJxYxNtT95oSU","amount":100000000}}]}' http://172.20.0.5:8901
req='"method":"Chain33.CreateTransaction","params":[{"execer":"'"${paracross_execer_name}"'","actionName":"ParacrossAssetTransfer","payload":{"execName":"'"${paracross_execer_name}"'","to":"'"$para_test_addr"'","amount":'${amount_transfer}'}}]'
echo "$req"
resp=$(curl -ksd "{$req}" "${para_ip}")
# echo "$resp"
err=$(jq '(.error)' <<<"$resp")
if [ "$err" != null ]; then
echo "$resp"
exit 1
fi
tx_hash_asset=$(jq -r ".result" <<<"$resp")
# tx_hash_asset=$(curl -ksd '{"method":"Chain33.CreateTransaction","params":[{"execer":"'"${paracross_execer_name}"'","actionName":"ParacrossAssetTransfer","payload":{"execName":"'"${paracross_execer_name}"'","to":"'"$para_test_addr"'","amount":'${amount_transfer}'}}]}' "${para_ip}" | jq -r ".result")
# 资产从平行链转移到平行链合约
req='"method":"Chain33.CreateTransaction","params":[{"execer":"'"${paracross_execer_name}"'","actionName":"TransferToExec","payload":{"execName":"'"${paracross_execer_name}"'","to":"'"${trade_exec_addr}"'","amount":'${amount_trade}', "cointoken":"coins.bty"}}]'
......@@ -348,19 +338,107 @@ function paracross_testTxGroup() {
#sign 1
tx_sign=$(curl -ksd '{"method":"Chain33.SignRawTx","params":[{"privkey":"'"$para_test_prikey"'","txHex":"'"$tx_hash_group"'","index":2,"expire":"120s"}]}' "${para_ip}" | jq -r ".result")
#curl -ksd '{"method":"Chain33.SignRawTx","params":[{"privkey":"0x24d1fad138be98eebee31440f144aa38c404533f40862995282162bc538e91c8","txHex":"0a10757365722e702e706172612e6e6f6e6512126e6f2d6665652d7472616e73616374696f6e1a6e080112210320bbac09528e19c55b0f89cb37ab265e7e856b1a8c388780322dbbfd194b52ba1a473045022100fe7763b2fa5b42eddccf1a3434cb6d6bb60a5c5c32e5498219e99be01bb94ad302201ecb9931a2bb4e1b0d49ec50ee552a774c1db8a1eb9b2dff47e4b931625e3af220e0a71230a89780b2a5b187990a3a2231466a58697076505142754e6f7a4133506150724b6846703854343166717141707640034a8c050a8e020a10757365722e702e706172612e6e6f6e6512126e6f2d6665652d7472616e73616374696f6e1a6e080112210320bbac09528e19c55b0f89cb37ab265e7e856b1a8c388780322dbbfd194b52ba1a473045022100fe7763b2fa5b42eddccf1a3434cb6d6bb60a5c5c32e5498219e99be01bb94ad302201ecb9931a2bb4e1b0d49ec50ee552a774c1db8a1eb9b2dff47e4b931625e3af220e0a71230a89780b2a5b187990a3a2231466a58697076505142754e6f7a4133506150724b6846703854343166717141707640034a2054ba4451fb8f226dd54b52ec086f4eaa4990d66876899b1badec8ce96ef55208522000f2e5970b5b1854da143f4f3e91bf7eb87d1d62869ef08a2ce3b109994ec3650abb010a15757365722e702e706172612e7061726163726f7373122e10904e22291080c2d72f2222314d41754538515362626563683362564b4b324a504a4a7859784e745439356f535530d195faf7d3a1ec9a4c3a223139574a4a7639366e4b4155347348465771476d7371666a786433376a617a71696940034a2054ba4451fb8f226dd54b52ec086f4eaa4990d66876899b1badec8ce96ef5520852208fb7939bf2701e5af9cef05da33020be682e10c84fde9bd8d24765031fad530b0aba010a15757365722e702e706172612e7061726163726f7373124f1004424b0a09636f696e732e6274791080ade2042215757365722e702e706172612e7061726163726f73732a2231326269686a7a626159576a637044696979395375415765714e6b735164694e313330a8c984ebb2bb90a5613a223139574a4a7639366e4b4155347348465771476d7371666a786433376a617a71696940034a2054ba4451fb8f226dd54b52ec086f4eaa4990d66876899b1badec8ce96ef55208522000f2e5970b5b1854da143f4f3e91bf7eb87d1d62869ef08a2ce3b109994ec365","index":2,"expire":"120s"}]}' http://172.20.0.5:8901
#sign 2
tx_sign2=$(curl -ksd '{"method":"Chain33.SignRawTx","params":[{"privkey":"'"$para_test_prikey"'","txHex":"'"$tx_sign"'","index":3,"expire":"120s"}]}' "${para_ip}" | jq -r ".result")
#curl -ksd '{"method":"Chain33.SignRawTx","params":[{"privkey":"0x24d1fad138be98eebee31440f144aa38c404533f40862995282162bc538e91c8","txHex":"0a10757365722e702e706172612e6e6f6e6512126e6f2d6665652d7472616e73616374696f6e1a6e080112210320bbac09528e19c55b0f89cb37ab265e7e856b1a8c388780322dbbfd194b52ba1a473045022100fe7763b2fa5b42eddccf1a3434cb6d6bb60a5c5c32e5498219e99be01bb94ad302201ecb9931a2bb4e1b0d49ec50ee552a774c1db8a1eb9b2dff47e4b931625e3af220e0a71230a89780b2a5b187990a3a2231466a58697076505142754e6f7a4133506150724b6846703854343166717141707640034afc050a8e020a10757365722e702e706172612e6e6f6e6512126e6f2d6665652d7472616e73616374696f6e1a6e080112210320bbac09528e19c55b0f89cb37ab265e7e856b1a8c388780322dbbfd194b52ba1a473045022100fe7763b2fa5b42eddccf1a3434cb6d6bb60a5c5c32e5498219e99be01bb94ad302201ecb9931a2bb4e1b0d49ec50ee552a774c1db8a1eb9b2dff47e4b931625e3af220e0a71230a89780b2a5b187990a3a2231466a58697076505142754e6f7a4133506150724b6846703854343166717141707640034a2054ba4451fb8f226dd54b52ec086f4eaa4990d66876899b1badec8ce96ef55208522000f2e5970b5b1854da143f4f3e91bf7eb87d1d62869ef08a2ce3b109994ec3650aab020a15757365722e702e706172612e7061726163726f7373122e10904e22291080c2d72f2222314d41754538515362626563683362564b4b324a504a4a7859784e745439356f53551a6e0801122103589ebf581958aeb8a72ff517f823c878aee16139ecbf0001a4611e9c004fecdf1a473045022100da5ad2bdc6e1e43a01d32c44f116e5d0bf96aa4c16debad49381ea5d11a49835022055a510460df9b63f8f585393d6603abf1388fac0e122b53ef3533f242287915730d195faf7d3a1ec9a4c3a223139574a4a7639366e4b4155347348465771476d7371666a786433376a617a71696940034a2054ba4451fb8f226dd54b52ec086f4eaa4990d66876899b1badec8ce96ef5520852208fb7939bf2701e5af9cef05da33020be682e10c84fde9bd8d24765031fad530b0aba010a15757365722e702e706172612e7061726163726f7373124f1004424b0a09636f696e732e6274791080ade2042215757365722e702e706172612e7061726163726f73732a2231326269686a7a626159576a637044696979395375415765714e6b735164694e313330a8c984ebb2bb90a5613a223139574a4a7639366e4b4155347348465771476d7371666a786433376a617a71696940034a2054ba4451fb8f226dd54b52ec086f4eaa4990d66876899b1badec8ce96ef55208522000f2e5970b5b1854da143f4f3e91bf7eb87d1d62869ef08a2ce3b109994ec365","index":3,"expire":"120s"}]}' http://172.20.0.5:8901
#send
chain33_SendTx "${tx_sign2}" "${para_ip}"
#tx_rst=$(curl -ksd '{"method":"Chain33.SendTransaction","params":[{"token":"BTY","data":"${tx_sign2}"}]'} "${para_ip}" | jq -r ".result" )
local transfer_expect="700000000"
}
//测试平行链交易组跨链失败,主链自动恢复原值
function paracross_testTxGroupFail() {
local para_ip=$1
ispara=$(echo '"'"${para_ip}"'"' | jq '.|contains("8901")')
echo "ipara=$ispara"
local paracross_addr=""
local main_ip=${para_ip//8901/8801}
paracross_addr=$(curl -ksd '{"method":"Chain33.ConvertExectoAddr","params":[{"execname":"paracross"}]}' "${main_ip}" | jq -r ".result")
echo "paracross_addr=$paracross_addr"
#execer
local trade_exec_addr="12bihjzbaYWjcpDiiy9SuAWeqNksQdiN13"
//测试跨链过去1个,交易组转账8个失败的场景,主链应该还保持原来的
local amount_trade=800000000
local amount_transfer=100000000
local amount_left=500000000
left_exec_val=$(paracross_QueryMainBalance "${para_test_addr}")
if [ "${left_exec_val}" != $amount_left ]; then
echo "paracross_testTxGroupFail left main paracross failed, get=$left_exec_val,expec=$amount_left"
exit 1
fi
paracross_txgroupex "${amount_transfer}" "${amount_trade}" "${para_ip}"
local count=0
local times=100
local paracross_execer_name="user.p.para.paracross"
local trade_exec_name="user.p.para.trade"
local transfer_expect="200000000"
local exec_expect="100000000"
while true; do
transfer_val=$(paracross_QueryParaBalance "${para_test_addr}" "$paracross_execer_name")
transfer_exec_val=$(paracross_QueryParaBalance "${para_test_addr}" "$trade_exec_name")
left_exec_val=$(paracross_QueryMainBalance "${para_test_addr}")
if [ "${left_exec_val}" != $amount_left ] || [ "${transfer_val}" != $transfer_expect ] || [ "${transfer_exec_val}" != $exec_expect ]; then
echo "trans=${transfer_val}-expect=${transfer_expect},trader=${transfer_exec_val}-expect=${exec_expect},left=${left_exec_val}-expect=${amount_left}"
chain33_BlockWait 2 ${UNIT_HTTP}
times=$((times - 1))
if [ $times -le 0 ]; then
echo "para_cross_transfer_testfail failed"
exit 1
fi
echo "paracross_testTxGroupFail left main paracross failed, get=$left_exec_val,expec=$amount_left"
else
count=$((count + 1))
break
fi
done
[ "$count" -eq 1 ]
local rst=$?
echo_rst "$FUNCNAME" "$rst"
}
function paracross_testTxGroup() {
local para_ip=$1
ispara=$(echo '"'"${para_ip}"'"' | jq '.|contains("8901")')
echo "ipara=$ispara"
local paracross_addr=""
local main_ip=${para_ip//8901/8801}
paracross_addr=$(curl -ksd '{"method":"Chain33.ConvertExectoAddr","params":[{"execname":"paracross"}]}' "${main_ip}" | jq -r ".result")
echo "paracross_addr=$paracross_addr"
#execer
local paracross_execer_name="user.p.para.paracross"
local trade_exec_name="user.p.para.trade"
local trade_exec_addr="12bihjzbaYWjcpDiiy9SuAWeqNksQdiN13"
local amount_trade=100000000
local amount_deposit=800000000
local amount_transfer=300000000
local amount_left=500000000
chain33_ImportPrivkey "${para_test_prikey}" "${para_test_addr}" "paracross-transfer6" "${main_ip}"
# tx fee + transfer 10 coins
chain33_applyCoins "${para_test_addr}" 1000000000 "${main_ip}"
chain33_QueryBalance "${para_test_addr}" "$main_ip"
#deposit 8 coins to paracross
chain33_SendToAddress "${para_test_addr}" "$paracross_addr" "$amount_deposit" "${main_ip}"
chain33_QueryExecBalance "${para_test_addr}" "paracross" "${main_ip}"
paracross_txgroupex "${amount_transfer}" "${amount_trade}" "${para_ip}"
local transfer_expect="200000000"
local exec_expect="100000000"
transfer_val=$(paracross_QueryParaBalance "${para_test_addr}" "$paracross_execer_name")
transfer_exec_val=$(paracross_QueryParaBalance "${para_test_addr}" "$trade_exec_name")
left_exec_val=$(paracross_QueryMainBalance "${para_test_addr}")
if [ "${transfer_val}" != $transfer_expect ]; then
echo "paracross_testTxGroup trasfer failed, get=$transfer_val,expec=$transfer_expect"
exit 1
......@@ -369,6 +447,10 @@ function paracross_testTxGroup() {
echo "paracross_testTxGroup toexec failed, get=$transfer_exec_val,expec=$exec_expect"
exit 1
fi
if [ "${left_exec_val}" != $amount_left ]; then
echo "paracross_testTxGroup left main paracross failed, get=$left_exec_val,expec=$amount_left"
exit 1
fi
echo_rst "$FUNCNAME" 0
......@@ -396,6 +478,10 @@ paracross_testSelfConsensStages() {
resp=$(curl -ksd "{$req}" "${para_ip}")
echo "$resp"
id=$(jq -r ".result.stageInfo[0].id" <<<"$resp")
if [ -z "$id" ]; then
echo "paracross stage apply id null"
exit 1
fi
echo "vote id"
KS_PRI="0x6da92a632ab7deb67d38c0f6560bcfed28167998f6496db64c258d5e8393a81b"
......@@ -405,9 +491,12 @@ paracross_testSelfConsensStages() {
req='"method":"Chain33.CreateTransaction","params":[{"execer" : "user.p.para.paracross","actionName" : "selfConsStageConfig","payload":{"title":"user.p.para.","op":"2","vote":{"id":"'"$id"'","value":1} }}]'
resp=$(curl -ksd "{$req}" "${para_ip}")
rawtx=$(jq -r ".result" <<<"$resp")
echo "send vote 1"
chain33_SignRawTx "$rawtx" "$KS_PRI" "${para_ip}"
chain33_SignRawTx "$rawtx" "$JR_PRI" "${para_ip}"
chain33_SignRawTx "$rawtx" "$NL_PRI" "${para_ip}"
echo "send vote 2"
chain33_SignRawTx "$rawtx" "$JR_PRI" "${para_ip}" "110s"
echo "send vote 3"
chain33_SignRawTx "$rawtx" "$NL_PRI" "${para_ip}" "111s"
echo "query status"
req='"method":"paracross.ListSelfStages","params":[{"status":3,"count":1}]'
......@@ -446,6 +535,7 @@ function run_testcases() {
paracross_ListNodeStatus
paracross_Transfer_Withdraw
paracross_testTxGroup "$UNIT_HTTP"
paracross_testTxGroupFail "$UNIT_HTTP"
paracross_testSelfConsensStages "$UNIT_HTTP"
}
......
......@@ -37,6 +37,7 @@ func ParcCmd() *cobra.Command {
paraConfigCmd(),
GetParaInfoCmd(),
GetParaListCmd(),
GetParaAssetTransCmd(),
IsSyncCmd(),
GetHeightCmd(),
GetBlockInfoCmd(),
......@@ -936,6 +937,35 @@ func getNodeGroupAddrsCmd() *cobra.Command {
return cmd
}
func addParaAssetTranCmdFlags(cmd *cobra.Command) {
cmd.Flags().StringP("hash", "s", "", "asset transfer tx hash")
cmd.MarkFlagRequired("hash")
}
func paraAssetTransfer(cmd *cobra.Command, args []string) {
rpcLaddr, _ := cmd.Flags().GetString("rpc_laddr")
hash, _ := cmd.Flags().GetString("hash")
params := types.ReqString{
Data: hash,
}
var res pt.ParacrossAssetRsp
ctx := jsonclient.NewRPCCtx(rpcLaddr, "paracross.GetAssetTxResult", params, &res)
ctx.Run()
}
// GetParaAssetTransCmd get para chain asset transfer info
func GetParaAssetTransCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "asset_tranfer",
Short: "Get para chain cross asset transfer info",
Run: paraAssetTransfer,
}
addParaAssetTranCmdFlags(cmd)
return cmd
}
func nodeGroup(cmd *cobra.Command, args []string) {
rpcLaddr, _ := cmd.Flags().GetString("rpc_laddr")
paraName, _ := cmd.Flags().GetString("paraName")
......
......@@ -318,10 +318,10 @@ func updateCommitAddrs(stat *pt.ParacrossHeightStatus, nodes map[string]struct{}
func (a *action) Commit(commit *pt.ParacrossCommitAction) (*types.Receipt, error) {
cfg := a.api.GetConfig()
if cfg.IsPara() && cfg.IsDappFork(a.height, pt.ParaX, pt.ForkParaSelfConsStages) {
if cfg.IsPara() && cfg.IsDappFork(commit.Status.Height, pt.ParaX, pt.ForkParaSelfConsStages) {
//分叉之后,key不存在,自共识没配置也认为不支持自共识
isSelfConsOn, err := isSelfConsOn(a.db, commit.Status.Height)
if err != nil {
if err != nil && errors.Cause(err) != pt.ErrKeyNotExist {
return nil, err
}
if !isSelfConsOn {
......@@ -748,7 +748,7 @@ func (a *action) isAllowConsensJump(commit *pt.ParacrossCommitAction, titleStatu
}
func (a *action) execCrossTx(tx *types.TransactionDetail, crossTxHash []byte) (*types.Receipt, error) {
func execCrossTx(a *action, tx *types.TransactionDetail, crossTxHash []byte) (*types.Receipt, error) {
if !bytes.HasSuffix(tx.Tx.Execer, []byte(pt.ParaX)) {
return nil, nil
}
......@@ -762,7 +762,7 @@ func (a *action) execCrossTx(tx *types.TransactionDetail, crossTxHash []byte) (*
if payload.Ty == pt.ParacrossActionAssetWithdraw {
receiptWithdraw, err := a.assetWithdraw(payload.GetAssetWithdraw(), tx.Tx)
if err != nil {
clog.Crit("paracross.Commit Decode Tx failed", "error", err, "txHash", hex.EncodeToString(crossTxHash))
clog.Crit("paracross.Commit withdraw Tx failed", "error", err, "txHash", hex.EncodeToString(crossTxHash))
return nil, errors.Cause(err)
}
......@@ -773,6 +773,31 @@ func (a *action) execCrossTx(tx *types.TransactionDetail, crossTxHash []byte) (*
}
func rollbackCrossTx(a *action, tx *types.TransactionDetail, crossTxHash []byte) (*types.Receipt, error) {
if !bytes.HasSuffix(tx.Tx.Execer, []byte(pt.ParaX)) {
return nil, nil
}
var payload pt.ParacrossAction
err := types.Decode(tx.Tx.Payload, &payload)
if err != nil {
clog.Crit("paracross.Commit.rollbackCrossTx Decode Tx failed", "error", err, "txHash", hex.EncodeToString(crossTxHash))
return nil, err
}
if payload.Ty == pt.ParacrossActionAssetTransfer {
receipt, err := a.assetTransferRollback(payload.GetAssetTransfer(), tx.Tx)
if err != nil {
clog.Crit("paracross.Commit rbk Tx failed", "error", err, "txHash", hex.EncodeToString(crossTxHash))
return nil, errors.Cause(err)
}
clog.Debug("paracross.Commit rollbackCrossTx", "txHash", hex.EncodeToString(crossTxHash), "mainHeight", a.height)
return receipt, nil
}
return nil, nil
}
func getCrossTxHashsByRst(api client.QueueProtocolAPI, status *pt.ParacrossNodeStatus) ([][]byte, []byte, error) {
//只获取跨链tx
cfg := api.GetConfig()
......@@ -781,11 +806,13 @@ func getCrossTxHashsByRst(api client.QueueProtocolAPI, status *pt.ParacrossNodeS
clog.Error("getCrossTxHashs decode rst", "CrossTxResult", string(status.TxResult), "paraHeight", status.Height)
return nil, nil, types.ErrInvalidParam
}
clog.Debug("getCrossTxHashsByRst", "height", status.Height, "txResult", string(status.TxResult))
//空块
if !cfg.IsDappFork(status.MainBlockHeight, pt.ParaX, pt.ForkParaAssetTransferRbk) {
if len(rst) == 0 {
return nil, nil, nil
}
}
blockDetail, err := GetBlock(api, status.MainBlockHash)
if err != nil {
......@@ -800,6 +827,7 @@ func getCrossTxHashsByRst(api client.QueueProtocolAPI, status *pt.ParacrossNodeS
}
paraCrossHashs := FilterParaCrossTxHashes(paraAllTxs)
crossRst := util.CalcBitMapByBitMap(paraCrossHashs, baseHashs, rst)
clog.Debug("getCrossTxHashsByRst.crossRst", "height", status.Height, "txResult", hex.EncodeToString(crossRst), "len", len(paraCrossHashs))
return paraCrossHashs, crossRst, nil
......@@ -858,6 +886,24 @@ func getCrossTxHashs(api client.QueueProtocolAPI, status *pt.ParacrossNodeStatus
}
func crossTxProc(a *action, txHash []byte, fn func(*action, *types.TransactionDetail, []byte) (*types.Receipt, error)) (*types.Receipt, error) {
tx, err := GetTx(a.api, txHash)
if err != nil {
clog.Crit("paracross.Commit Load Tx failed", "error", err, "txHash", hex.EncodeToString(txHash))
return nil, err
}
if tx == nil {
clog.Error("paracross.Commit Load Tx nil", "error", err, "txHash", hex.EncodeToString(txHash))
return nil, types.ErrHashNotExist
}
receiptCross, err := fn(a, tx, txHash)
if err != nil {
clog.Error("paracross.Commit execCrossTx", "error", err)
return nil, errors.Cause(err)
}
return receiptCross, nil
}
func (a *action) execCrossTxs(status *pt.ParacrossNodeStatus) (*types.Receipt, error) {
var receipt types.Receipt
......@@ -866,28 +912,30 @@ func (a *action) execCrossTxs(status *pt.ParacrossNodeStatus) (*types.Receipt, e
clog.Error("paracross.Commit getCrossTxHashs", "err", err.Error())
return nil, err
}
if len(crossTxHashs) == 0 {
return &receipt, nil
}
for i := 0; i < len(crossTxHashs); i++ {
clog.Debug("paracross.Commit commitDone", "do cross number", i, "hash", hex.EncodeToString(crossTxHashs[i]),
"res", util.BitMapBit(crossTxResult, uint32(i)))
if util.BitMapBit(crossTxResult, uint32(i)) {
tx, err := GetTx(a.api, crossTxHashs[i])
receiptCross, err := crossTxProc(a, crossTxHashs[i], execCrossTx)
if err != nil {
clog.Crit("paracross.Commit Load Tx failed", "para title", title, "para height", status.Height,
"para tx index", i, "error", err, "txHash", hex.EncodeToString(crossTxHashs[i]))
return nil, err
clog.Error("paracross.Commit execCrossTx", "para title", status.Title, "para height", status.Height,
"para tx index", i, "error", err)
return nil, errors.Cause(err)
}
if tx == nil {
clog.Error("paracross.Commit Load Tx failed", "para title", title, "para height", status.Height,
"para tx index", i, "error", err, "txHash", hex.EncodeToString(crossTxHashs[i]))
return nil, types.ErrHashNotExist
if receiptCross == nil {
continue
}
receiptCross, err := a.execCrossTx(tx, crossTxHashs[i])
receipt.KV = append(receipt.KV, receiptCross.KV...)
receipt.Logs = append(receipt.Logs, receiptCross.Logs...)
} else {
clog.Error("paracross.Commit commitDone", "do cross number", i, "hash",
hex.EncodeToString(crossTxHashs[i]), "para res", util.BitMapBit(crossTxResult, uint32(i)))
cfg := a.api.GetConfig()
if cfg.IsDappFork(a.height, pt.ParaX, pt.ForkParaAssetTransferRbk) {
receiptCross, err := crossTxProc(a, crossTxHashs[i], rollbackCrossTx)
if err != nil {
clog.Error("paracross.Commit execCrossTx", "para title", title, "para height", status.Height,
clog.Error("paracross.Commit rollbackCrossTx", "para title", status.Title, "para height", status.Height,
"para tx index", i, "error", err)
return nil, errors.Cause(err)
}
......@@ -896,10 +944,7 @@ func (a *action) execCrossTxs(status *pt.ParacrossNodeStatus) (*types.Receipt, e
}
receipt.KV = append(receipt.KV, receiptCross.KV...)
receipt.Logs = append(receipt.Logs, receiptCross.Logs...)
} else {
clog.Error("paracross.Commit commitDone", "do cross number", i, "hash",
hex.EncodeToString(crossTxHashs[i]),
"para res", util.BitMapBit(crossTxResult, uint32(i)))
}
}
}
......
......@@ -87,6 +87,24 @@ func (a *action) assetWithdraw(withdraw *types.AssetsWithdraw, withdrawTx *types
return assetWithdrawBalance(paraAcc, a.fromaddr, withdraw.Amount)
}
func (a *action) assetTransferRollback(transfer *types.AssetsTransfer, transferTx *types.Transaction) (*types.Receipt, error) {
cfg := a.api.GetConfig()
isPara := cfg.IsPara()
//主链处理分支
if !isPara {
accDB, err := createAccount(cfg, a.db, transfer.Cointoken)
if err != nil {
return nil, errors.Wrap(err, "assetTransferToken call account.NewAccountDB failed")
}
execAddr := address.ExecAddress(pt.ParaX)
fromAcc := address.ExecAddress(string(transferTx.Execer))
clog.Debug("paracross.AssetTransferRbk ", "execer", string(transferTx.Execer),
"transfer.txHash", hex.EncodeToString(transferTx.Hash()), "curTx", hex.EncodeToString(a.tx.Hash()))
return accDB.ExecTransfer(fromAcc, transferTx.From(), execAddr, transfer.Amount)
}
return nil, nil
}
func createAccount(cfg *types.Chain33Config, db db.KV, symbol string) (*account.DB, error) {
var accDB *account.DB
var err error
......
......@@ -228,6 +228,7 @@ func setMinerTxResultFork(cfg *types.Chain33Config, status *pt.ParacrossNodeStat
//主链自己过滤平行链tx, 对平行链执行失败的tx主链无法识别,主链和平行链需要获取相同的最初的tx map
//全部平行链tx结果
status.TxResult = []byte(hex.EncodeToString(util.CalcSingleBitMap(curTxHashs, receipts)))
clog.Debug("setMinerTxResultFork", "height", status.Height, "txResult", string(status.TxResult))
//ForkLoopCheckCommitTxDone 后只保留全部txreseult 结果
if !pt.IsParaForkHeight(cfg, status.MainBlockHeight, pt.ForkLoopCheckCommitTxDone) {
......
......@@ -218,11 +218,15 @@ func (p *Paracross) Query_GetDoneTitleHeight(in *pt.ReqParacrossTitleHeight) (ty
}
// Query_GetAssetTxResult query get asset tx reseult
func (p *Paracross) Query_GetAssetTxResult(in *types.ReqHash) (types.Message, error) {
if in == nil {
func (p *Paracross) Query_GetAssetTxResult(in *types.ReqString) (types.Message, error) {
if in == nil || in.Data == "" {
return nil, types.ErrInvalidParam
}
return p.paracrossGetAssetTxResult(in.Hash)
hash, err := common.FromHex(in.Data)
if err != nil {
return nil, errors.Wrap(err, "fromHex")
}
return p.paracrossGetAssetTxResult(hash)
}
// Query_GetMainBlockHash query get mainblockHash by tx
......@@ -296,7 +300,7 @@ func listLocalTitles(db dbm.KVDB) (types.Message, error) {
MostSameCommit: st.MostSameCommit,
Title: st.Title,
Height: st.Height,
TxResult: hex.EncodeToString(st.TxResult),
TxResult: string(st.TxResult),
}
resp.Titles = append(resp.Titles, rst)
......@@ -400,13 +404,34 @@ func (p *Paracross) paracrossGetAssetTxResult(hash []byte) (types.Message, error
return nil, err
}
var result pt.ParacrossAsset
err = types.Decode(value, &result)
var rst pt.ParacrossAsset
err = types.Decode(value, &rst)
if err != nil {
return nil, err
}
return &result, nil
rsp := &pt.ParacrossAssetRsp{
From: rst.From,
To: rst.To,
Amount: rst.Amount,
Exec: rst.Exec,
Symbol: rst.Symbol,
Height: rst.Height,
CommitDoneHeight: rst.CommitDoneHeight,
ParaHeight: rst.ParaHeight,
}
rsp.TxHash = common.ToHex(rst.TxHash)
rsp.IsWithdraw = "false"
if rst.IsWithdraw {
rsp.IsWithdraw = "true"
}
rsp.Success = "false"
if rst.Success {
rsp.Success = "true"
}
return rsp, nil
}
//Query_GetSelfConsStages get self consensus stages configed
......
......@@ -385,6 +385,23 @@ message ParacrossAsset {
bool success = 23;
}
message ParacrossAssetRsp {
// input
string from = 1;
string to = 2;
string isWithdraw = 3;
string txHash = 4;
int64 amount = 5;
string exec = 6;
string symbol = 7;
// 主链部分
int64 height = 10;
// 平行链部分
int64 commitDoneHeight = 21;
int64 paraHeight = 22;
string success = 23;
}
message ParaLocalDbBlock {
int64 height = 1;
bytes mainHash = 2;
......@@ -408,6 +425,6 @@ service paracross {
rpc ListTitles(ReqNil) returns (RespParacrossTitles) {}
rpc GetDoneTitleHeight(ReqParacrossTitleHeight) returns (RespParacrossDone) {}
rpc GetTitleHeight(ReqParacrossTitleHeight) returns (ParacrossHeightStatusRsp) {}
rpc GetAssetTxResult(ReqHash) returns (ParacrossAsset) {}
rpc GetAssetTxResult(ReqString) returns (ParacrossAssetRsp) {}
rpc IsSync(ReqNil) returns (IsCaughtUp) {}
}
\ No newline at end of file
......@@ -118,20 +118,20 @@ func (c *channelClient) GetDoneTitleHeight(ctx context.Context, req *pt.ReqParac
return nil, types.ErrDecode
}
func (c *channelClient) GetAssetTxResult(ctx context.Context, req *types.ReqHash) (*pt.ParacrossAsset, error) {
func (c *channelClient) GetAssetTxResult(ctx context.Context, req *types.ReqString) (*pt.ParacrossAssetRsp, error) {
cfg := c.GetConfig()
data, err := c.Query(pt.GetExecName(cfg), "GetAssetTxResult", req)
if err != nil {
return nil, err
}
if resp, ok := data.(*pt.ParacrossAsset); ok {
if resp, ok := data.(*pt.ParacrossAssetRsp); ok {
return resp, nil
}
return nil, types.ErrDecode
}
// GetAssetTxResult get asset tx result
func (c *Jrpc) GetAssetTxResult(req *types.ReqHash, result *interface{}) error {
func (c *Jrpc) GetAssetTxResult(req *types.ReqString, result *interface{}) error {
if req == nil {
return types.ErrInvalidParam
}
......
......@@ -124,8 +124,8 @@ func TestChannelClient_GetAssetTxResult(t *testing.T) {
api.On("GetConfig", mock.Anything).Return(cfg, nil)
client := newGrpc(api)
client.Init("paracross", nil, nil, nil)
req := &types.ReqHash{}
api.On("Query", pt.GetExecName(cfg), "GetAssetTxResult", req).Return(&pt.ParacrossAsset{}, nil)
req := &types.ReqString{}
api.On("Query", pt.GetExecName(cfg), "GetAssetTxResult", req).Return(&pt.ParacrossAssetRsp{}, nil)
_, err := client.GetAssetTxResult(context.Background(), req)
assert.Nil(t, err)
}
......@@ -135,9 +135,9 @@ func TestJrpc_GetAssetTxResult(t *testing.T) {
api := new(mocks.QueueProtocolAPI)
api.On("GetConfig", mock.Anything).Return(cfg, nil)
j := newJrpc(api)
req := &types.ReqHash{}
req := &types.ReqString{}
var result interface{}
api.On("Query", pt.GetExecName(cfg), "GetAssetTxResult", req).Return(&pt.ParacrossAsset{}, nil)
api.On("Query", pt.GetExecName(cfg), "GetAssetTxResult", req).Return(&pt.ParacrossAssetRsp{}, nil)
err := j.GetAssetTxResult(req, &result)
assert.Nil(t, err)
}
......
......@@ -41,7 +41,7 @@ func (m *ParacrossStatusDetails) Reset() { *m = ParacrossStatusDetails{}
func (m *ParacrossStatusDetails) String() string { return proto.CompactTextString(m) }
func (*ParacrossStatusDetails) ProtoMessage() {}
func (*ParacrossStatusDetails) Descriptor() ([]byte, []int) {
return fileDescriptor_paracross_e0081cf2748ff01a, []int{0}
return fileDescriptor_paracross_313193799a5638f5, []int{0}
}
func (m *ParacrossStatusDetails) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ParacrossStatusDetails.Unmarshal(m, b)
......@@ -88,7 +88,7 @@ func (m *ParacrossStatusBlockDetails) Reset() { *m = ParacrossStatusBloc
func (m *ParacrossStatusBlockDetails) String() string { return proto.CompactTextString(m) }
func (*ParacrossStatusBlockDetails) ProtoMessage() {}
func (*ParacrossStatusBlockDetails) Descriptor() ([]byte, []int) {
return fileDescriptor_paracross_e0081cf2748ff01a, []int{1}
return fileDescriptor_paracross_313193799a5638f5, []int{1}
}
func (m *ParacrossStatusBlockDetails) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ParacrossStatusBlockDetails.Unmarshal(m, b)
......@@ -140,7 +140,7 @@ func (m *ParacrossHeightStatus) Reset() { *m = ParacrossHeightStatus{} }
func (m *ParacrossHeightStatus) String() string { return proto.CompactTextString(m) }
func (*ParacrossHeightStatus) ProtoMessage() {}
func (*ParacrossHeightStatus) Descriptor() ([]byte, []int) {
return fileDescriptor_paracross_e0081cf2748ff01a, []int{2}
return fileDescriptor_paracross_313193799a5638f5, []int{2}
}
func (m *ParacrossHeightStatus) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ParacrossHeightStatus.Unmarshal(m, b)
......@@ -226,7 +226,7 @@ func (m *ParacrossHeightStatusRsp) Reset() { *m = ParacrossHeightStatusR
func (m *ParacrossHeightStatusRsp) String() string { return proto.CompactTextString(m) }
func (*ParacrossHeightStatusRsp) ProtoMessage() {}
func (*ParacrossHeightStatusRsp) Descriptor() ([]byte, []int) {
return fileDescriptor_paracross_e0081cf2748ff01a, []int{3}
return fileDescriptor_paracross_313193799a5638f5, []int{3}
}
func (m *ParacrossHeightStatusRsp) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ParacrossHeightStatusRsp.Unmarshal(m, b)
......@@ -310,7 +310,7 @@ func (m *ParacrossStatus) Reset() { *m = ParacrossStatus{} }
func (m *ParacrossStatus) String() string { return proto.CompactTextString(m) }
func (*ParacrossStatus) ProtoMessage() {}
func (*ParacrossStatus) Descriptor() ([]byte, []int) {
return fileDescriptor_paracross_e0081cf2748ff01a, []int{4}
return fileDescriptor_paracross_313193799a5638f5, []int{4}
}
func (m *ParacrossStatus) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ParacrossStatus.Unmarshal(m, b)
......@@ -379,7 +379,7 @@ func (m *ParacrossConsensusStatus) Reset() { *m = ParacrossConsensusStat
func (m *ParacrossConsensusStatus) String() string { return proto.CompactTextString(m) }
func (*ParacrossConsensusStatus) ProtoMessage() {}
func (*ParacrossConsensusStatus) Descriptor() ([]byte, []int) {
return fileDescriptor_paracross_e0081cf2748ff01a, []int{5}
return fileDescriptor_paracross_313193799a5638f5, []int{5}
}
func (m *ParacrossConsensusStatus) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ParacrossConsensusStatus.Unmarshal(m, b)
......@@ -443,7 +443,7 @@ func (m *ParaNodeAddrConfig) Reset() { *m = ParaNodeAddrConfig{} }
func (m *ParaNodeAddrConfig) String() string { return proto.CompactTextString(m) }
func (*ParaNodeAddrConfig) ProtoMessage() {}
func (*ParaNodeAddrConfig) Descriptor() ([]byte, []int) {
return fileDescriptor_paracross_e0081cf2748ff01a, []int{6}
return fileDescriptor_paracross_313193799a5638f5, []int{6}
}
func (m *ParaNodeAddrConfig) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ParaNodeAddrConfig.Unmarshal(m, b)
......@@ -517,7 +517,7 @@ func (m *ParaNodeVoteDetail) Reset() { *m = ParaNodeVoteDetail{} }
func (m *ParaNodeVoteDetail) String() string { return proto.CompactTextString(m) }
func (*ParaNodeVoteDetail) ProtoMessage() {}
func (*ParaNodeVoteDetail) Descriptor() ([]byte, []int) {
return fileDescriptor_paracross_e0081cf2748ff01a, []int{7}
return fileDescriptor_paracross_313193799a5638f5, []int{7}
}
func (m *ParaNodeVoteDetail) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ParaNodeVoteDetail.Unmarshal(m, b)
......@@ -566,7 +566,7 @@ func (m *ParaNodeAddrIdStatus) Reset() { *m = ParaNodeAddrIdStatus{} }
func (m *ParaNodeAddrIdStatus) String() string { return proto.CompactTextString(m) }
func (*ParaNodeAddrIdStatus) ProtoMessage() {}
func (*ParaNodeAddrIdStatus) Descriptor() ([]byte, []int) {
return fileDescriptor_paracross_e0081cf2748ff01a, []int{8}
return fileDescriptor_paracross_313193799a5638f5, []int{8}
}
func (m *ParaNodeAddrIdStatus) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ParaNodeAddrIdStatus.Unmarshal(m, b)
......@@ -639,7 +639,7 @@ func (m *ParaNodeIdStatus) Reset() { *m = ParaNodeIdStatus{} }
func (m *ParaNodeIdStatus) String() string { return proto.CompactTextString(m) }
func (*ParaNodeIdStatus) ProtoMessage() {}
func (*ParaNodeIdStatus) Descriptor() ([]byte, []int) {
return fileDescriptor_paracross_e0081cf2748ff01a, []int{9}
return fileDescriptor_paracross_313193799a5638f5, []int{9}
}
func (m *ParaNodeIdStatus) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ParaNodeIdStatus.Unmarshal(m, b)
......@@ -729,7 +729,7 @@ func (m *ReceiptParaNodeConfig) Reset() { *m = ReceiptParaNodeConfig{} }
func (m *ReceiptParaNodeConfig) String() string { return proto.CompactTextString(m) }
func (*ReceiptParaNodeConfig) ProtoMessage() {}
func (*ReceiptParaNodeConfig) Descriptor() ([]byte, []int) {
return fileDescriptor_paracross_e0081cf2748ff01a, []int{10}
return fileDescriptor_paracross_313193799a5638f5, []int{10}
}
func (m *ReceiptParaNodeConfig) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ReceiptParaNodeConfig.Unmarshal(m, b)
......@@ -790,7 +790,7 @@ func (m *ReceiptParaNodeAddrStatUpdate) Reset() { *m = ReceiptParaNodeAd
func (m *ReceiptParaNodeAddrStatUpdate) String() string { return proto.CompactTextString(m) }
func (*ReceiptParaNodeAddrStatUpdate) ProtoMessage() {}
func (*ReceiptParaNodeAddrStatUpdate) Descriptor() ([]byte, []int) {
return fileDescriptor_paracross_e0081cf2748ff01a, []int{11}
return fileDescriptor_paracross_313193799a5638f5, []int{11}
}
func (m *ReceiptParaNodeAddrStatUpdate) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ReceiptParaNodeAddrStatUpdate.Unmarshal(m, b)
......@@ -849,7 +849,7 @@ func (m *ReceiptParaNodeVoteDone) Reset() { *m = ReceiptParaNodeVoteDone
func (m *ReceiptParaNodeVoteDone) String() string { return proto.CompactTextString(m) }
func (*ReceiptParaNodeVoteDone) ProtoMessage() {}
func (*ReceiptParaNodeVoteDone) Descriptor() ([]byte, []int) {
return fileDescriptor_paracross_e0081cf2748ff01a, []int{12}
return fileDescriptor_paracross_313193799a5638f5, []int{12}
}
func (m *ReceiptParaNodeVoteDone) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ReceiptParaNodeVoteDone.Unmarshal(m, b)
......@@ -940,7 +940,7 @@ func (m *ParaNodeGroupConfig) Reset() { *m = ParaNodeGroupConfig{} }
func (m *ParaNodeGroupConfig) String() string { return proto.CompactTextString(m) }
func (*ParaNodeGroupConfig) ProtoMessage() {}
func (*ParaNodeGroupConfig) Descriptor() ([]byte, []int) {
return fileDescriptor_paracross_e0081cf2748ff01a, []int{13}
return fileDescriptor_paracross_313193799a5638f5, []int{13}
}
func (m *ParaNodeGroupConfig) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ParaNodeGroupConfig.Unmarshal(m, b)
......@@ -1012,7 +1012,7 @@ func (m *ParaNodeGroupStatus) Reset() { *m = ParaNodeGroupStatus{} }
func (m *ParaNodeGroupStatus) String() string { return proto.CompactTextString(m) }
func (*ParaNodeGroupStatus) ProtoMessage() {}
func (*ParaNodeGroupStatus) Descriptor() ([]byte, []int) {
return fileDescriptor_paracross_e0081cf2748ff01a, []int{14}
return fileDescriptor_paracross_313193799a5638f5, []int{14}
}
func (m *ParaNodeGroupStatus) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ParaNodeGroupStatus.Unmarshal(m, b)
......@@ -1095,7 +1095,7 @@ func (m *ReceiptParaNodeGroupConfig) Reset() { *m = ReceiptParaNodeGroup
func (m *ReceiptParaNodeGroupConfig) String() string { return proto.CompactTextString(m) }
func (*ReceiptParaNodeGroupConfig) ProtoMessage() {}
func (*ReceiptParaNodeGroupConfig) Descriptor() ([]byte, []int) {
return fileDescriptor_paracross_e0081cf2748ff01a, []int{15}
return fileDescriptor_paracross_313193799a5638f5, []int{15}
}
func (m *ReceiptParaNodeGroupConfig) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ReceiptParaNodeGroupConfig.Unmarshal(m, b)
......@@ -1158,7 +1158,7 @@ func (m *ReqParacrossNodeInfo) Reset() { *m = ReqParacrossNodeInfo{} }
func (m *ReqParacrossNodeInfo) String() string { return proto.CompactTextString(m) }
func (*ReqParacrossNodeInfo) ProtoMessage() {}
func (*ReqParacrossNodeInfo) Descriptor() ([]byte, []int) {
return fileDescriptor_paracross_e0081cf2748ff01a, []int{16}
return fileDescriptor_paracross_313193799a5638f5, []int{16}
}
func (m *ReqParacrossNodeInfo) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ReqParacrossNodeInfo.Unmarshal(m, b)
......@@ -1217,7 +1217,7 @@ func (m *RespParacrossNodeAddrs) Reset() { *m = RespParacrossNodeAddrs{}
func (m *RespParacrossNodeAddrs) String() string { return proto.CompactTextString(m) }
func (*RespParacrossNodeAddrs) ProtoMessage() {}
func (*RespParacrossNodeAddrs) Descriptor() ([]byte, []int) {
return fileDescriptor_paracross_e0081cf2748ff01a, []int{17}
return fileDescriptor_paracross_313193799a5638f5, []int{17}
}
func (m *RespParacrossNodeAddrs) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_RespParacrossNodeAddrs.Unmarshal(m, b)
......@@ -1255,7 +1255,7 @@ func (m *RespParacrossNodeGroups) Reset() { *m = RespParacrossNodeGroups
func (m *RespParacrossNodeGroups) String() string { return proto.CompactTextString(m) }
func (*RespParacrossNodeGroups) ProtoMessage() {}
func (*RespParacrossNodeGroups) Descriptor() ([]byte, []int) {
return fileDescriptor_paracross_e0081cf2748ff01a, []int{18}
return fileDescriptor_paracross_313193799a5638f5, []int{18}
}
func (m *RespParacrossNodeGroups) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_RespParacrossNodeGroups.Unmarshal(m, b)
......@@ -1296,7 +1296,7 @@ func (m *ParaBlock2MainMap) Reset() { *m = ParaBlock2MainMap{} }
func (m *ParaBlock2MainMap) String() string { return proto.CompactTextString(m) }
func (*ParaBlock2MainMap) ProtoMessage() {}
func (*ParaBlock2MainMap) Descriptor() ([]byte, []int) {
return fileDescriptor_paracross_e0081cf2748ff01a, []int{19}
return fileDescriptor_paracross_313193799a5638f5, []int{19}
}
func (m *ParaBlock2MainMap) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ParaBlock2MainMap.Unmarshal(m, b)
......@@ -1355,7 +1355,7 @@ func (m *ParaBlock2MainInfo) Reset() { *m = ParaBlock2MainInfo{} }
func (m *ParaBlock2MainInfo) String() string { return proto.CompactTextString(m) }
func (*ParaBlock2MainInfo) ProtoMessage() {}
func (*ParaBlock2MainInfo) Descriptor() ([]byte, []int) {
return fileDescriptor_paracross_e0081cf2748ff01a, []int{20}
return fileDescriptor_paracross_313193799a5638f5, []int{20}
}
func (m *ParaBlock2MainInfo) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ParaBlock2MainInfo.Unmarshal(m, b)
......@@ -1407,7 +1407,7 @@ func (m *ParacrossNodeStatus) Reset() { *m = ParacrossNodeStatus{} }
func (m *ParacrossNodeStatus) String() string { return proto.CompactTextString(m) }
func (*ParacrossNodeStatus) ProtoMessage() {}
func (*ParacrossNodeStatus) Descriptor() ([]byte, []int) {
return fileDescriptor_paracross_e0081cf2748ff01a, []int{21}
return fileDescriptor_paracross_313193799a5638f5, []int{21}
}
func (m *ParacrossNodeStatus) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ParacrossNodeStatus.Unmarshal(m, b)
......@@ -1536,7 +1536,7 @@ func (m *SelfConsensStages) Reset() { *m = SelfConsensStages{} }
func (m *SelfConsensStages) String() string { return proto.CompactTextString(m) }
func (*SelfConsensStages) ProtoMessage() {}
func (*SelfConsensStages) Descriptor() ([]byte, []int) {
return fileDescriptor_paracross_e0081cf2748ff01a, []int{22}
return fileDescriptor_paracross_313193799a5638f5, []int{22}
}
func (m *SelfConsensStages) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_SelfConsensStages.Unmarshal(m, b)
......@@ -1575,7 +1575,7 @@ func (m *SelfConsensStage) Reset() { *m = SelfConsensStage{} }
func (m *SelfConsensStage) String() string { return proto.CompactTextString(m) }
func (*SelfConsensStage) ProtoMessage() {}
func (*SelfConsensStage) Descriptor() ([]byte, []int) {
return fileDescriptor_paracross_e0081cf2748ff01a, []int{23}
return fileDescriptor_paracross_313193799a5638f5, []int{23}
}
func (m *SelfConsensStage) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_SelfConsensStage.Unmarshal(m, b)
......@@ -1625,7 +1625,7 @@ func (m *SelfConsensStageInfo) Reset() { *m = SelfConsensStageInfo{} }
func (m *SelfConsensStageInfo) String() string { return proto.CompactTextString(m) }
func (*SelfConsensStageInfo) ProtoMessage() {}
func (*SelfConsensStageInfo) Descriptor() ([]byte, []int) {
return fileDescriptor_paracross_e0081cf2748ff01a, []int{24}
return fileDescriptor_paracross_313193799a5638f5, []int{24}
}
func (m *SelfConsensStageInfo) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_SelfConsensStageInfo.Unmarshal(m, b)
......@@ -1699,7 +1699,7 @@ func (m *LocalSelfConsStageInfo) Reset() { *m = LocalSelfConsStageInfo{}
func (m *LocalSelfConsStageInfo) String() string { return proto.CompactTextString(m) }
func (*LocalSelfConsStageInfo) ProtoMessage() {}
func (*LocalSelfConsStageInfo) Descriptor() ([]byte, []int) {
return fileDescriptor_paracross_e0081cf2748ff01a, []int{25}
return fileDescriptor_paracross_313193799a5638f5, []int{25}
}
func (m *LocalSelfConsStageInfo) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_LocalSelfConsStageInfo.Unmarshal(m, b)
......@@ -1746,7 +1746,7 @@ func (m *ConfigVoteInfo) Reset() { *m = ConfigVoteInfo{} }
func (m *ConfigVoteInfo) String() string { return proto.CompactTextString(m) }
func (*ConfigVoteInfo) ProtoMessage() {}
func (*ConfigVoteInfo) Descriptor() ([]byte, []int) {
return fileDescriptor_paracross_e0081cf2748ff01a, []int{26}
return fileDescriptor_paracross_313193799a5638f5, []int{26}
}
func (m *ConfigVoteInfo) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ConfigVoteInfo.Unmarshal(m, b)
......@@ -1791,7 +1791,7 @@ func (m *ConfigCancelInfo) Reset() { *m = ConfigCancelInfo{} }
func (m *ConfigCancelInfo) String() string { return proto.CompactTextString(m) }
func (*ConfigCancelInfo) ProtoMessage() {}
func (*ConfigCancelInfo) Descriptor() ([]byte, []int) {
return fileDescriptor_paracross_e0081cf2748ff01a, []int{27}
return fileDescriptor_paracross_313193799a5638f5, []int{27}
}
func (m *ConfigCancelInfo) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ConfigCancelInfo.Unmarshal(m, b)
......@@ -1837,7 +1837,7 @@ func (m *ParaStageConfig) Reset() { *m = ParaStageConfig{} }
func (m *ParaStageConfig) String() string { return proto.CompactTextString(m) }
func (*ParaStageConfig) ProtoMessage() {}
func (*ParaStageConfig) Descriptor() ([]byte, []int) {
return fileDescriptor_paracross_e0081cf2748ff01a, []int{28}
return fileDescriptor_paracross_313193799a5638f5, []int{28}
}
func (m *ParaStageConfig) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ParaStageConfig.Unmarshal(m, b)
......@@ -2026,7 +2026,7 @@ func (m *ReceiptSelfConsStageConfig) Reset() { *m = ReceiptSelfConsStage
func (m *ReceiptSelfConsStageConfig) String() string { return proto.CompactTextString(m) }
func (*ReceiptSelfConsStageConfig) ProtoMessage() {}
func (*ReceiptSelfConsStageConfig) Descriptor() ([]byte, []int) {
return fileDescriptor_paracross_e0081cf2748ff01a, []int{29}
return fileDescriptor_paracross_313193799a5638f5, []int{29}
}
func (m *ReceiptSelfConsStageConfig) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ReceiptSelfConsStageConfig.Unmarshal(m, b)
......@@ -2076,7 +2076,7 @@ func (m *ReceiptSelfConsStageVoteDone) Reset() { *m = ReceiptSelfConsSta
func (m *ReceiptSelfConsStageVoteDone) String() string { return proto.CompactTextString(m) }
func (*ReceiptSelfConsStageVoteDone) ProtoMessage() {}
func (*ReceiptSelfConsStageVoteDone) Descriptor() ([]byte, []int) {
return fileDescriptor_paracross_e0081cf2748ff01a, []int{30}
return fileDescriptor_paracross_313193799a5638f5, []int{30}
}
func (m *ReceiptSelfConsStageVoteDone) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ReceiptSelfConsStageVoteDone.Unmarshal(m, b)
......@@ -2150,7 +2150,7 @@ func (m *ReceiptSelfConsStagesUpdate) Reset() { *m = ReceiptSelfConsStag
func (m *ReceiptSelfConsStagesUpdate) String() string { return proto.CompactTextString(m) }
func (*ReceiptSelfConsStagesUpdate) ProtoMessage() {}
func (*ReceiptSelfConsStagesUpdate) Descriptor() ([]byte, []int) {
return fileDescriptor_paracross_e0081cf2748ff01a, []int{31}
return fileDescriptor_paracross_313193799a5638f5, []int{31}
}
func (m *ReceiptSelfConsStagesUpdate) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ReceiptSelfConsStagesUpdate.Unmarshal(m, b)
......@@ -2201,7 +2201,7 @@ func (m *ReqQuerySelfStages) Reset() { *m = ReqQuerySelfStages{} }
func (m *ReqQuerySelfStages) String() string { return proto.CompactTextString(m) }
func (*ReqQuerySelfStages) ProtoMessage() {}
func (*ReqQuerySelfStages) Descriptor() ([]byte, []int) {
return fileDescriptor_paracross_e0081cf2748ff01a, []int{32}
return fileDescriptor_paracross_313193799a5638f5, []int{32}
}
func (m *ReqQuerySelfStages) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ReqQuerySelfStages.Unmarshal(m, b)
......@@ -2274,7 +2274,7 @@ func (m *ReplyQuerySelfStages) Reset() { *m = ReplyQuerySelfStages{} }
func (m *ReplyQuerySelfStages) String() string { return proto.CompactTextString(m) }
func (*ReplyQuerySelfStages) ProtoMessage() {}
func (*ReplyQuerySelfStages) Descriptor() ([]byte, []int) {
return fileDescriptor_paracross_e0081cf2748ff01a, []int{33}
return fileDescriptor_paracross_313193799a5638f5, []int{33}
}
func (m *ReplyQuerySelfStages) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ReplyQuerySelfStages.Unmarshal(m, b)
......@@ -2312,7 +2312,7 @@ func (m *ParacrossCommitAction) Reset() { *m = ParacrossCommitAction{} }
func (m *ParacrossCommitAction) String() string { return proto.CompactTextString(m) }
func (*ParacrossCommitAction) ProtoMessage() {}
func (*ParacrossCommitAction) Descriptor() ([]byte, []int) {
return fileDescriptor_paracross_e0081cf2748ff01a, []int{34}
return fileDescriptor_paracross_313193799a5638f5, []int{34}
}
func (m *ParacrossCommitAction) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ParacrossCommitAction.Unmarshal(m, b)
......@@ -2351,7 +2351,7 @@ func (m *ParacrossMinerAction) Reset() { *m = ParacrossMinerAction{} }
func (m *ParacrossMinerAction) String() string { return proto.CompactTextString(m) }
func (*ParacrossMinerAction) ProtoMessage() {}
func (*ParacrossMinerAction) Descriptor() ([]byte, []int) {
return fileDescriptor_paracross_e0081cf2748ff01a, []int{35}
return fileDescriptor_paracross_313193799a5638f5, []int{35}
}
func (m *ParacrossMinerAction) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ParacrossMinerAction.Unmarshal(m, b)
......@@ -2408,7 +2408,7 @@ func (m *ParacrossAction) Reset() { *m = ParacrossAction{} }
func (m *ParacrossAction) String() string { return proto.CompactTextString(m) }
func (*ParacrossAction) ProtoMessage() {}
func (*ParacrossAction) Descriptor() ([]byte, []int) {
return fileDescriptor_paracross_e0081cf2748ff01a, []int{36}
return fileDescriptor_paracross_313193799a5638f5, []int{36}
}
func (m *ParacrossAction) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ParacrossAction.Unmarshal(m, b)
......@@ -2817,7 +2817,7 @@ func (m *ReceiptParacrossCommit) Reset() { *m = ReceiptParacrossCommit{}
func (m *ReceiptParacrossCommit) String() string { return proto.CompactTextString(m) }
func (*ReceiptParacrossCommit) ProtoMessage() {}
func (*ReceiptParacrossCommit) Descriptor() ([]byte, []int) {
return fileDescriptor_paracross_e0081cf2748ff01a, []int{37}
return fileDescriptor_paracross_313193799a5638f5, []int{37}
}
func (m *ReceiptParacrossCommit) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ReceiptParacrossCommit.Unmarshal(m, b)
......@@ -2876,7 +2876,7 @@ func (m *ReceiptParacrossMiner) Reset() { *m = ReceiptParacrossMiner{} }
func (m *ReceiptParacrossMiner) String() string { return proto.CompactTextString(m) }
func (*ReceiptParacrossMiner) ProtoMessage() {}
func (*ReceiptParacrossMiner) Descriptor() ([]byte, []int) {
return fileDescriptor_paracross_e0081cf2748ff01a, []int{38}
return fileDescriptor_paracross_313193799a5638f5, []int{38}
}
func (m *ReceiptParacrossMiner) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ReceiptParacrossMiner.Unmarshal(m, b)
......@@ -2927,7 +2927,7 @@ func (m *ReceiptParacrossDone) Reset() { *m = ReceiptParacrossDone{} }
func (m *ReceiptParacrossDone) String() string { return proto.CompactTextString(m) }
func (*ReceiptParacrossDone) ProtoMessage() {}
func (*ReceiptParacrossDone) Descriptor() ([]byte, []int) {
return fileDescriptor_paracross_e0081cf2748ff01a, []int{39}
return fileDescriptor_paracross_313193799a5638f5, []int{39}
}
func (m *ReceiptParacrossDone) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ReceiptParacrossDone.Unmarshal(m, b)
......@@ -3057,7 +3057,7 @@ func (m *ReceiptParacrossRecord) Reset() { *m = ReceiptParacrossRecord{}
func (m *ReceiptParacrossRecord) String() string { return proto.CompactTextString(m) }
func (*ReceiptParacrossRecord) ProtoMessage() {}
func (*ReceiptParacrossRecord) Descriptor() ([]byte, []int) {
return fileDescriptor_paracross_e0081cf2748ff01a, []int{40}
return fileDescriptor_paracross_313193799a5638f5, []int{40}
}
func (m *ReceiptParacrossRecord) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ReceiptParacrossRecord.Unmarshal(m, b)
......@@ -3104,7 +3104,7 @@ func (m *ParacrossTx) Reset() { *m = ParacrossTx{} }
func (m *ParacrossTx) String() string { return proto.CompactTextString(m) }
func (*ParacrossTx) ProtoMessage() {}
func (*ParacrossTx) Descriptor() ([]byte, []int) {
return fileDescriptor_paracross_e0081cf2748ff01a, []int{41}
return fileDescriptor_paracross_313193799a5638f5, []int{41}
}
func (m *ParacrossTx) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ParacrossTx.Unmarshal(m, b)
......@@ -3144,7 +3144,7 @@ func (m *ReqParacrossTitleHeight) Reset() { *m = ReqParacrossTitleHeight
func (m *ReqParacrossTitleHeight) String() string { return proto.CompactTextString(m) }
func (*ReqParacrossTitleHeight) ProtoMessage() {}
func (*ReqParacrossTitleHeight) Descriptor() ([]byte, []int) {
return fileDescriptor_paracross_e0081cf2748ff01a, []int{42}
return fileDescriptor_paracross_313193799a5638f5, []int{42}
}
func (m *ReqParacrossTitleHeight) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ReqParacrossTitleHeight.Unmarshal(m, b)
......@@ -3196,7 +3196,7 @@ func (m *RespParacrossDone) Reset() { *m = RespParacrossDone{} }
func (m *RespParacrossDone) String() string { return proto.CompactTextString(m) }
func (*RespParacrossDone) ProtoMessage() {}
func (*RespParacrossDone) Descriptor() ([]byte, []int) {
return fileDescriptor_paracross_e0081cf2748ff01a, []int{43}
return fileDescriptor_paracross_313193799a5638f5, []int{43}
}
func (m *RespParacrossDone) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_RespParacrossDone.Unmarshal(m, b)
......@@ -3283,7 +3283,7 @@ func (m *RespParacrossTitles) Reset() { *m = RespParacrossTitles{} }
func (m *RespParacrossTitles) String() string { return proto.CompactTextString(m) }
func (*RespParacrossTitles) ProtoMessage() {}
func (*RespParacrossTitles) Descriptor() ([]byte, []int) {
return fileDescriptor_paracross_e0081cf2748ff01a, []int{44}
return fileDescriptor_paracross_313193799a5638f5, []int{44}
}
func (m *RespParacrossTitles) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_RespParacrossTitles.Unmarshal(m, b)
......@@ -3322,7 +3322,7 @@ func (m *ReqParacrossTitleHash) Reset() { *m = ReqParacrossTitleHash{} }
func (m *ReqParacrossTitleHash) String() string { return proto.CompactTextString(m) }
func (*ReqParacrossTitleHash) ProtoMessage() {}
func (*ReqParacrossTitleHash) Descriptor() ([]byte, []int) {
return fileDescriptor_paracross_e0081cf2748ff01a, []int{45}
return fileDescriptor_paracross_313193799a5638f5, []int{45}
}
func (m *ReqParacrossTitleHash) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ReqParacrossTitleHash.Unmarshal(m, b)
......@@ -3381,7 +3381,7 @@ func (m *ParacrossAsset) Reset() { *m = ParacrossAsset{} }
func (m *ParacrossAsset) String() string { return proto.CompactTextString(m) }
func (*ParacrossAsset) ProtoMessage() {}
func (*ParacrossAsset) Descriptor() ([]byte, []int) {
return fileDescriptor_paracross_e0081cf2748ff01a, []int{46}
return fileDescriptor_paracross_313193799a5638f5, []int{46}
}
func (m *ParacrossAsset) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ParacrossAsset.Unmarshal(m, b)
......@@ -3478,6 +3478,127 @@ func (m *ParacrossAsset) GetSuccess() bool {
return false
}
type ParacrossAssetRsp struct {
// input
From string `protobuf:"bytes,1,opt,name=from,proto3" json:"from,omitempty"`
To string `protobuf:"bytes,2,opt,name=to,proto3" json:"to,omitempty"`
IsWithdraw string `protobuf:"bytes,3,opt,name=isWithdraw,proto3" json:"isWithdraw,omitempty"`
TxHash string `protobuf:"bytes,4,opt,name=txHash,proto3" json:"txHash,omitempty"`
Amount int64 `protobuf:"varint,5,opt,name=amount,proto3" json:"amount,omitempty"`
Exec string `protobuf:"bytes,6,opt,name=exec,proto3" json:"exec,omitempty"`
Symbol string `protobuf:"bytes,7,opt,name=symbol,proto3" json:"symbol,omitempty"`
// 主链部分
Height int64 `protobuf:"varint,10,opt,name=height,proto3" json:"height,omitempty"`
// 平行链部分
CommitDoneHeight int64 `protobuf:"varint,21,opt,name=commitDoneHeight,proto3" json:"commitDoneHeight,omitempty"`
ParaHeight int64 `protobuf:"varint,22,opt,name=paraHeight,proto3" json:"paraHeight,omitempty"`
Success string `protobuf:"bytes,23,opt,name=success,proto3" json:"success,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *ParacrossAssetRsp) Reset() { *m = ParacrossAssetRsp{} }
func (m *ParacrossAssetRsp) String() string { return proto.CompactTextString(m) }
func (*ParacrossAssetRsp) ProtoMessage() {}
func (*ParacrossAssetRsp) Descriptor() ([]byte, []int) {
return fileDescriptor_paracross_313193799a5638f5, []int{47}
}
func (m *ParacrossAssetRsp) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ParacrossAssetRsp.Unmarshal(m, b)
}
func (m *ParacrossAssetRsp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_ParacrossAssetRsp.Marshal(b, m, deterministic)
}
func (dst *ParacrossAssetRsp) XXX_Merge(src proto.Message) {
xxx_messageInfo_ParacrossAssetRsp.Merge(dst, src)
}
func (m *ParacrossAssetRsp) XXX_Size() int {
return xxx_messageInfo_ParacrossAssetRsp.Size(m)
}
func (m *ParacrossAssetRsp) XXX_DiscardUnknown() {
xxx_messageInfo_ParacrossAssetRsp.DiscardUnknown(m)
}
var xxx_messageInfo_ParacrossAssetRsp proto.InternalMessageInfo
func (m *ParacrossAssetRsp) GetFrom() string {
if m != nil {
return m.From
}
return ""
}
func (m *ParacrossAssetRsp) GetTo() string {
if m != nil {
return m.To
}
return ""
}
func (m *ParacrossAssetRsp) GetIsWithdraw() string {
if m != nil {
return m.IsWithdraw
}
return ""
}
func (m *ParacrossAssetRsp) GetTxHash() string {
if m != nil {
return m.TxHash
}
return ""
}
func (m *ParacrossAssetRsp) GetAmount() int64 {
if m != nil {
return m.Amount
}
return 0
}
func (m *ParacrossAssetRsp) GetExec() string {
if m != nil {
return m.Exec
}
return ""
}
func (m *ParacrossAssetRsp) GetSymbol() string {
if m != nil {
return m.Symbol
}
return ""
}
func (m *ParacrossAssetRsp) GetHeight() int64 {
if m != nil {
return m.Height
}
return 0
}
func (m *ParacrossAssetRsp) GetCommitDoneHeight() int64 {
if m != nil {
return m.CommitDoneHeight
}
return 0
}
func (m *ParacrossAssetRsp) GetParaHeight() int64 {
if m != nil {
return m.ParaHeight
}
return 0
}
func (m *ParacrossAssetRsp) GetSuccess() string {
if m != nil {
return m.Success
}
return ""
}
type ParaLocalDbBlock struct {
Height int64 `protobuf:"varint,1,opt,name=height,proto3" json:"height,omitempty"`
MainHash []byte `protobuf:"bytes,2,opt,name=mainHash,proto3" json:"mainHash,omitempty"`
......@@ -3494,7 +3615,7 @@ func (m *ParaLocalDbBlock) Reset() { *m = ParaLocalDbBlock{} }
func (m *ParaLocalDbBlock) String() string { return proto.CompactTextString(m) }
func (*ParaLocalDbBlock) ProtoMessage() {}
func (*ParaLocalDbBlock) Descriptor() ([]byte, []int) {
return fileDescriptor_paracross_e0081cf2748ff01a, []int{47}
return fileDescriptor_paracross_313193799a5638f5, []int{48}
}
func (m *ParaLocalDbBlock) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ParaLocalDbBlock.Unmarshal(m, b)
......@@ -3572,7 +3693,7 @@ func (m *ParaLocalDbBlockInfo) Reset() { *m = ParaLocalDbBlockInfo{} }
func (m *ParaLocalDbBlockInfo) String() string { return proto.CompactTextString(m) }
func (*ParaLocalDbBlockInfo) ProtoMessage() {}
func (*ParaLocalDbBlockInfo) Descriptor() ([]byte, []int) {
return fileDescriptor_paracross_e0081cf2748ff01a, []int{48}
return fileDescriptor_paracross_313193799a5638f5, []int{49}
}
func (m *ParaLocalDbBlockInfo) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ParaLocalDbBlockInfo.Unmarshal(m, b)
......@@ -3682,6 +3803,7 @@ func init() {
proto.RegisterType((*RespParacrossTitles)(nil), "types.RespParacrossTitles")
proto.RegisterType((*ReqParacrossTitleHash)(nil), "types.ReqParacrossTitleHash")
proto.RegisterType((*ParacrossAsset)(nil), "types.ParacrossAsset")
proto.RegisterType((*ParacrossAssetRsp)(nil), "types.ParacrossAssetRsp")
proto.RegisterType((*ParaLocalDbBlock)(nil), "types.ParaLocalDbBlock")
proto.RegisterType((*ParaLocalDbBlockInfo)(nil), "types.ParaLocalDbBlockInfo")
}
......@@ -3702,7 +3824,7 @@ type ParacrossClient interface {
ListTitles(ctx context.Context, in *types.ReqNil, opts ...grpc.CallOption) (*RespParacrossTitles, error)
GetDoneTitleHeight(ctx context.Context, in *ReqParacrossTitleHeight, opts ...grpc.CallOption) (*RespParacrossDone, error)
GetTitleHeight(ctx context.Context, in *ReqParacrossTitleHeight, opts ...grpc.CallOption) (*ParacrossHeightStatusRsp, error)
GetAssetTxResult(ctx context.Context, in *types.ReqHash, opts ...grpc.CallOption) (*ParacrossAsset, error)
GetAssetTxResult(ctx context.Context, in *types.ReqString, opts ...grpc.CallOption) (*ParacrossAssetRsp, error)
IsSync(ctx context.Context, in *types.ReqNil, opts ...grpc.CallOption) (*types.IsCaughtUp, error)
}
......@@ -3750,8 +3872,8 @@ func (c *paracrossClient) GetTitleHeight(ctx context.Context, in *ReqParacrossTi
return out, nil
}
func (c *paracrossClient) GetAssetTxResult(ctx context.Context, in *types.ReqHash, opts ...grpc.CallOption) (*ParacrossAsset, error) {
out := new(ParacrossAsset)
func (c *paracrossClient) GetAssetTxResult(ctx context.Context, in *types.ReqString, opts ...grpc.CallOption) (*ParacrossAssetRsp, error) {
out := new(ParacrossAssetRsp)
err := c.cc.Invoke(ctx, "/types.paracross/GetAssetTxResult", in, out, opts...)
if err != nil {
return nil, err
......@@ -3774,7 +3896,7 @@ type ParacrossServer interface {
ListTitles(context.Context, *types.ReqNil) (*RespParacrossTitles, error)
GetDoneTitleHeight(context.Context, *ReqParacrossTitleHeight) (*RespParacrossDone, error)
GetTitleHeight(context.Context, *ReqParacrossTitleHeight) (*ParacrossHeightStatusRsp, error)
GetAssetTxResult(context.Context, *types.ReqHash) (*ParacrossAsset, error)
GetAssetTxResult(context.Context, *types.ReqString) (*ParacrossAssetRsp, error)
IsSync(context.Context, *types.ReqNil) (*types.IsCaughtUp, error)
}
......@@ -3855,7 +3977,7 @@ func _Paracross_GetTitleHeight_Handler(srv interface{}, ctx context.Context, dec
}
func _Paracross_GetAssetTxResult_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(types.ReqHash)
in := new(types.ReqString)
if err := dec(in); err != nil {
return nil, err
}
......@@ -3867,7 +3989,7 @@ func _Paracross_GetAssetTxResult_Handler(srv interface{}, ctx context.Context, d
FullMethod: "/types.paracross/GetAssetTxResult",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ParacrossServer).GetAssetTxResult(ctx, req.(*types.ReqHash))
return srv.(ParacrossServer).GetAssetTxResult(ctx, req.(*types.ReqString))
}
return interceptor(ctx, in, info, handler)
}
......@@ -3923,157 +4045,158 @@ var _Paracross_serviceDesc = grpc.ServiceDesc{
Metadata: "paracross.proto",
}
func init() { proto.RegisterFile("paracross.proto", fileDescriptor_paracross_e0081cf2748ff01a) }
var fileDescriptor_paracross_e0081cf2748ff01a = []byte{
// 2376 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xd4, 0x5a, 0x4f, 0x73, 0x1c, 0x47,
0x15, 0xdf, 0xd9, 0xbf, 0xda, 0x27, 0xed, 0x5a, 0x9a, 0xc8, 0xca, 0xb2, 0x76, 0x1c, 0x55, 0x97,
0x49, 0x09, 0xe2, 0xd8, 0x58, 0x06, 0x53, 0xa9, 0x14, 0x05, 0xb6, 0x1c, 0x6b, 0x55, 0xb1, 0x53,
0xc9, 0x48, 0x81, 0x03, 0x17, 0x46, 0xbb, 0x6d, 0x69, 0x8a, 0xdd, 0x99, 0xf5, 0x4c, 0x6f, 0x22,
0x71, 0xa1, 0x28, 0xe0, 0x0c, 0x27, 0xaa, 0xc2, 0x81, 0x0b, 0x9c, 0xf9, 0x08, 0x1c, 0x38, 0x86,
0x53, 0x38, 0x70, 0xe0, 0xc6, 0x8d, 0x3b, 0x07, 0xae, 0xd4, 0x7b, 0xdd, 0x3d, 0xd3, 0xdd, 0x3b,
0xbb, 0x92, 0x1d, 0x5f, 0xb8, 0x6d, 0xbf, 0x7e, 0xfd, 0xfa, 0xbd, 0x5f, 0xbf, 0xf7, 0xfa, 0xbd,
0x9e, 0x85, 0x2b, 0xd3, 0x30, 0x0d, 0x87, 0x69, 0x92, 0x65, 0xb7, 0xa7, 0x69, 0x22, 0x12, 0xbf,
0x21, 0xce, 0xa7, 0x3c, 0xeb, 0x6f, 0x88, 0x34, 0x8c, 0xb3, 0x70, 0x28, 0xa2, 0x24, 0x96, 0x33,
0xfd, 0xb5, 0x61, 0x32, 0x99, 0xe4, 0xa3, 0xf5, 0xe3, 0x71, 0x32, 0xfc, 0xe9, 0xf0, 0x34, 0x8c,
0x14, 0x85, 0x3d, 0x81, 0xad, 0x8f, 0xb4, 0xb0, 0x43, 0x11, 0x8a, 0x59, 0xf6, 0x88, 0x8b, 0x30,
0x1a, 0x67, 0xfe, 0x26, 0x34, 0xc2, 0xd1, 0x28, 0xcd, 0x7a, 0xde, 0x76, 0x6d, 0xa7, 0x1d, 0xc8,
0x81, 0x7f, 0x1d, 0xda, 0x24, 0x63, 0x10, 0x66, 0xa7, 0xbd, 0xea, 0x76, 0x6d, 0x67, 0x2d, 0x28,
0x08, 0xec, 0xc7, 0x70, 0xcd, 0x91, 0xf6, 0x10, 0xe7, 0xb4, 0xc8, 0x1b, 0x00, 0x39, 0xaf, 0x94,
0xbb, 0x16, 0x18, 0x14, 0x14, 0x2e, 0xce, 0x02, 0x9e, 0xcd, 0xc6, 0x22, 0xd3, 0xc2, 0x73, 0x02,
0xfb, 0x7d, 0x15, 0xae, 0xe6, 0xd2, 0x07, 0x3c, 0x3a, 0x39, 0x15, 0x72, 0x0f, 0x7f, 0x0b, 0x9a,
0x19, 0xfd, 0xea, 0x79, 0xdb, 0xde, 0x4e, 0x23, 0x50, 0x23, 0x34, 0x41, 0x44, 0x62, 0xcc, 0x7b,
0xd5, 0x6d, 0x0f, 0x4d, 0xa0, 0x01, 0x72, 0x9f, 0xd2, 0xea, 0x5e, 0x6d, 0xdb, 0xdb, 0xa9, 0x05,
0x6a, 0xe4, 0x7f, 0x17, 0x5a, 0x23, 0xa9, 0x68, 0xaf, 0xbe, 0xed, 0xed, 0xac, 0xee, 0xbe, 0x71,
0x9b, 0x60, 0xbd, 0x5d, 0x0e, 0x50, 0xa0, 0xb9, 0xd1, 0xac, 0x49, 0x18, 0xc5, 0x52, 0xa5, 0x5e,
0x83, 0x84, 0x1a, 0x14, 0xbf, 0x0f, 0x2b, 0x34, 0x42, 0xc8, 0x9a, 0xdb, 0xde, 0xce, 0x5a, 0x90,
0x8f, 0xfd, 0xc7, 0xb0, 0x76, 0x6c, 0x40, 0xd4, 0x6b, 0xd1, 0xce, 0xac, 0x7c, 0x67, 0x13, 0xcc,
0xc0, 0x5a, 0xc7, 0xfe, 0xed, 0x41, 0xaf, 0x14, 0x9c, 0x20, 0x9b, 0xbe, 0x22, 0x7c, 0x6c, 0x33,
0xeb, 0x4b, 0xcd, 0x6c, 0x90, 0xc0, 0xc2, 0xcc, 0x6d, 0x58, 0x45, 0x47, 0x8c, 0xc4, 0x03, 0x72,
0xa9, 0x26, 0xb9, 0x94, 0x49, 0xf2, 0x77, 0xe0, 0x8a, 0x1c, 0x3e, 0xcc, 0xdd, 0xab, 0x45, 0x5c,
0x2e, 0x99, 0x7d, 0xee, 0xc1, 0x15, 0x07, 0x98, 0xc2, 0x12, 0xaf, 0xdc, 0x92, 0xaa, 0x65, 0x89,
0xe5, 0xc4, 0x35, 0x3a, 0x91, 0x82, 0xf0, 0xc2, 0x76, 0x1a, 0xc7, 0xc9, 0xfe, 0x64, 0x1e, 0xc3,
0x5e, 0x12, 0x67, 0x3c, 0xce, 0x66, 0xcb, 0x95, 0x44, 0x68, 0x4e, 0x8b, 0xfd, 0xa4, 0xa6, 0x26,
0xc9, 0xbf, 0x09, 0x9d, 0xa1, 0x14, 0x35, 0x30, 0xcf, 0xc5, 0x26, 0xfa, 0xdf, 0x84, 0x75, 0x45,
0x28, 0x10, 0xac, 0xd3, 0x46, 0x73, 0x74, 0xf6, 0x3b, 0x0f, 0x7c, 0x54, 0xf3, 0xc3, 0x64, 0xc4,
0x11, 0xfe, 0xbd, 0x24, 0x7e, 0x16, 0x9d, 0x2c, 0x50, 0xb0, 0x0b, 0xd5, 0x64, 0x4a, 0x7a, 0x75,
0x82, 0x6a, 0x32, 0xc5, 0x71, 0x34, 0x22, 0x1d, 0xda, 0x41, 0x35, 0x1a, 0xf9, 0x3e, 0xd4, 0x31,
0x37, 0xa8, 0xcd, 0xe8, 0x37, 0x4a, 0xfa, 0x34, 0x1c, 0xcf, 0x38, 0x01, 0xd4, 0x09, 0xe4, 0x40,
0x7a, 0x41, 0x14, 0x67, 0x8f, 0xd3, 0xe4, 0x67, 0x3c, 0xa6, 0x58, 0x40, 0x53, 0x0b, 0x12, 0xfb,
0x41, 0xa1, 0xd7, 0x0f, 0x13, 0xc1, 0xa5, 0x77, 0x2f, 0x48, 0x45, 0xb8, 0x47, 0x22, 0xb8, 0xcc,
0x14, 0xed, 0x40, 0x0e, 0xd8, 0x6f, 0x3d, 0xd8, 0x34, 0x4d, 0x3b, 0x18, 0x29, 0xf4, 0xb5, 0x9a,
0x9e, 0xa1, 0xe6, 0x0d, 0x80, 0x69, 0x9a, 0x4c, 0x93, 0x2c, 0x1c, 0x1f, 0x8c, 0x54, 0x14, 0x18,
0x14, 0x74, 0xa0, 0xe7, 0xb3, 0x48, 0x1c, 0x68, 0x73, 0xd5, 0xc8, 0x08, 0xa8, 0x7a, 0x79, 0x40,
0x35, 0x0c, 0x00, 0xd9, 0x7f, 0x3d, 0x58, 0xd7, 0x2a, 0xe5, 0xea, 0x48, 0x14, 0xbd, 0x1c, 0xc5,
0x42, 0x64, 0xb5, 0x5c, 0x64, 0xcd, 0x3c, 0x93, 0x1b, 0x00, 0x22, 0x4c, 0x4f, 0x38, 0x05, 0x8f,
0x42, 0xde, 0xa0, 0xb8, 0x48, 0x37, 0xe6, 0x90, 0xf6, 0xef, 0x68, 0xf4, 0x9a, 0x94, 0x71, 0xbe,
0x66, 0x64, 0x1c, 0x1b, 0x7d, 0x05, 0x2c, 0xba, 0xfd, 0xb3, 0x34, 0x99, 0xd0, 0x86, 0x2d, 0x19,
0xde, 0x7a, 0x6c, 0x04, 0xda, 0x8a, 0x19, 0x68, 0xec, 0x2f, 0x1e, 0x5c, 0x0d, 0xf8, 0x90, 0x47,
0x53, 0xa1, 0x05, 0x2b, 0x57, 0x2b, 0x3b, 0x8d, 0xbb, 0xd0, 0x1c, 0xd2, 0x2c, 0x41, 0x30, 0xaf,
0x53, 0xe1, 0xa9, 0x81, 0x62, 0xf4, 0xdf, 0x86, 0xfa, 0x34, 0xe5, 0x9f, 0x12, 0x38, 0xab, 0xbb,
0xaf, 0x3b, 0x0b, 0x34, 0xd8, 0x01, 0x31, 0xf9, 0x77, 0xa1, 0x35, 0x9c, 0xa5, 0x29, 0x8f, 0x85,
0x4a, 0xf0, 0x0b, 0xf9, 0x35, 0x1f, 0xfb, 0xa3, 0x07, 0x6f, 0x38, 0x06, 0xa0, 0x16, 0xc8, 0xf6,
0xc9, 0x74, 0x14, 0x0a, 0x6e, 0xc1, 0xe2, 0x39, 0xb0, 0xdc, 0x51, 0xda, 0x49, 0x73, 0xae, 0x95,
0x98, 0xe3, 0x68, 0xf8, 0x9d, 0x42, 0xc3, 0xda, 0xc5, 0x6b, 0x72, 0x2d, 0xff, 0xe3, 0xc1, 0xeb,
0x8e, 0x96, 0x74, 0x7e, 0x49, 0xcc, 0xe7, 0xfc, 0xac, 0x3c, 0xe7, 0xdb, 0xfe, 0x54, 0x9b, 0xf3,
0x27, 0x9c, 0x4f, 0x44, 0x38, 0x46, 0xd1, 0xda, 0xe9, 0x0d, 0x0a, 0xdd, 0xdc, 0x38, 0xc2, 0x6d,
0xc9, 0xdb, 0x1a, 0x41, 0x41, 0xa0, 0x8c, 0x99, 0x64, 0x82, 0x26, 0x9b, 0x34, 0x99, 0x8f, 0xfd,
0x1e, 0xb4, 0xd0, 0xbf, 0x82, 0x4c, 0x28, 0xaf, 0xd2, 0x43, 0xdc, 0x73, 0x94, 0xc4, 0x5c, 0x1a,
0x4b, 0x8e, 0xd5, 0x08, 0x0c, 0x0a, 0xfb, 0xa5, 0x07, 0xaf, 0x69, 0x73, 0xf7, 0xd3, 0x64, 0x36,
0xfd, 0x4a, 0x59, 0x2c, 0xcf, 0x31, 0x32, 0x98, 0x54, 0x8e, 0xb9, 0x30, 0x8e, 0xd8, 0xdf, 0x5c,
0x2d, 0x5e, 0x49, 0x7c, 0x6f, 0xc3, 0x6a, 0x81, 0xbe, 0xd6, 0xc9, 0x24, 0x5d, 0x22, 0xc2, 0x4d,
0xcf, 0x6c, 0x2e, 0x0c, 0xd8, 0x96, 0x15, 0xb0, 0x5f, 0x78, 0xd0, 0x77, 0x3c, 0xc9, 0x84, 0xb6,
0x2c, 0x6a, 0x77, 0x9d, 0xa8, 0xed, 0x3b, 0x2e, 0x6b, 0xac, 0xcf, 0xc3, 0xf6, 0xb6, 0x15, 0xb6,
0xa5, 0x2b, 0xac, 0xb8, 0xf8, 0xb6, 0x1b, 0xb9, 0xcb, 0x96, 0xe4, 0x61, 0x71, 0x0a, 0x9b, 0x01,
0x7f, 0x9e, 0x5f, 0xc7, 0x14, 0xe1, 0xf1, 0xb3, 0x64, 0xb1, 0x83, 0x44, 0xfa, 0x0e, 0x30, 0xaf,
0xb5, 0x9a, 0x61, 0xeb, 0x82, 0xbc, 0xcf, 0xf6, 0x60, 0x2b, 0xe0, 0xd9, 0xd4, 0xda, 0x4a, 0x1e,
0xd3, 0x37, 0xa0, 0x16, 0x8d, 0xe4, 0xc5, 0xb5, 0x24, 0xdf, 0x20, 0x0f, 0xdb, 0xc7, 0x20, 0x76,
0x84, 0x90, 0x5d, 0x99, 0x7f, 0xcb, 0x94, 0xb2, 0xcc, 0x76, 0x12, 0xf4, 0x6b, 0x0f, 0x36, 0x70,
0x92, 0xee, 0xfb, 0xdd, 0xa7, 0x61, 0x14, 0x3f, 0x0d, 0xa7, 0xc6, 0x91, 0x7b, 0x8b, 0x8b, 0x21,
0x69, 0xfe, 0xc2, 0x62, 0xa8, 0xb6, 0xb4, 0x18, 0xaa, 0xdb, 0x45, 0x1f, 0x7b, 0x24, 0x2f, 0xf3,
0x42, 0x0d, 0x42, 0xff, 0x36, 0x34, 0x22, 0xc1, 0x27, 0xda, 0x9a, 0x9e, 0x61, 0x8d, 0xa5, 0x70,
0x20, 0xd9, 0xd8, 0xbf, 0x6a, 0x32, 0xc0, 0x72, 0x4c, 0x54, 0x80, 0xdd, 0x84, 0x0e, 0xee, 0x54,
0x14, 0x3b, 0x1e, 0xd5, 0x62, 0x36, 0x11, 0xcb, 0xca, 0x82, 0x60, 0x56, 0x58, 0x2e, 0x79, 0x41,
0x20, 0x16, 0xa8, 0xd5, 0x2d, 0xd4, 0x18, 0xac, 0x4d, 0x53, 0x5e, 0x6c, 0x2e, 0x0b, 0x41, 0x8b,
0x66, 0x23, 0xdb, 0x74, 0xcb, 0x4c, 0x29, 0x01, 0x8d, 0xe1, 0xaa, 0xda, 0xd5, 0x12, 0x72, 0x1a,
0x4a, 0xc8, 0x72, 0x86, 0x15, 0x29, 0x21, 0x27, 0x20, 0xf6, 0xe2, 0x6c, 0x2f, 0x99, 0xc5, 0x22,
0xeb, 0xb5, 0x29, 0xb1, 0xe5, 0x63, 0x39, 0x27, 0x3b, 0xa7, 0x1e, 0xc8, 0x22, 0x55, 0x8f, 0x31,
0xe5, 0x8a, 0x33, 0xd9, 0x83, 0xad, 0x52, 0x93, 0xa5, 0x87, 0x54, 0x69, 0x22, 0xcc, 0x47, 0x7a,
0xe9, 0x9a, 0xc4, 0xd4, 0x22, 0xa2, 0xe6, 0x8a, 0x20, 0x85, 0x74, 0x48, 0x88, 0x45, 0xf3, 0x6f,
0xc1, 0x46, 0x9c, 0xc4, 0x7b, 0x54, 0xba, 0x1f, 0x69, 0x25, 0xbb, 0xa4, 0xe4, 0xfc, 0x04, 0x7b,
0x08, 0x1b, 0x87, 0x7c, 0xfc, 0x4c, 0x15, 0xcc, 0x87, 0x22, 0x3c, 0xe1, 0x99, 0xff, 0x8e, 0xed,
0x28, 0x3a, 0x78, 0x5c, 0x46, 0xed, 0x27, 0x4f, 0x60, 0xdd, 0x9d, 0xc2, 0x24, 0x99, 0x89, 0x30,
0x15, 0x03, 0xd3, 0xf1, 0x4d, 0x12, 0x9e, 0x2f, 0x8f, 0xc3, 0x63, 0x75, 0x1f, 0x76, 0x02, 0x35,
0x62, 0xff, 0xf4, 0x60, 0xd3, 0x15, 0x47, 0xee, 0xbb, 0x3c, 0xaf, 0x77, 0xf2, 0xbc, 0xfe, 0x0e,
0x34, 0x32, 0x5c, 0xe4, 0x94, 0x26, 0xf3, 0xda, 0x13, 0x97, 0x95, 0xac, 0xeb, 0x4e, 0xb2, 0xbe,
0x01, 0xc0, 0xcf, 0xf8, 0xd0, 0xee, 0x2f, 0x0b, 0xca, 0x0b, 0x97, 0x72, 0x8c, 0xc3, 0xd6, 0x93,
0x64, 0x18, 0x8e, 0xb5, 0x32, 0x85, 0x75, 0x77, 0xb5, 0xd6, 0x9e, 0x55, 0x7e, 0x94, 0x21, 0xa1,
0x35, 0x27, 0x6f, 0x3a, 0x88, 0x47, 0xfc, 0x4c, 0x65, 0x0f, 0x3d, 0x64, 0xf7, 0xa1, 0x2b, 0xf3,
0x3e, 0x6a, 0x50, 0x0a, 0x5e, 0xde, 0x26, 0x54, 0x8d, 0x36, 0x81, 0x31, 0x58, 0x97, 0xeb, 0xf6,
0xc2, 0x78, 0xc8, 0xc7, 0x65, 0x2b, 0xd9, 0x97, 0xaa, 0x09, 0x24, 0x75, 0x5e, 0xe8, 0xe2, 0xbf,
0xa3, 0x4d, 0x84, 0xa5, 0x07, 0x33, 0xa8, 0x68, 0x03, 0xdf, 0x86, 0x3a, 0xc2, 0xd6, 0x5b, 0x25,
0xfe, 0xab, 0x8a, 0xdf, 0xb6, 0x6c, 0x50, 0x09, 0x88, 0x89, 0x6a, 0x58, 0xd2, 0x9a, 0x42, 0xa7,
0x10, 0xef, 0x1a, 0x34, 0xa8, 0x04, 0x8a, 0xf1, 0x61, 0x4b, 0x81, 0xc0, 0x7e, 0x55, 0x5c, 0xbe,
0xd6, 0xc9, 0x28, 0xf3, 0x74, 0x35, 0x79, 0x89, 0xa3, 0x99, 0xab, 0x26, 0xab, 0x17, 0xaf, 0xc9,
0xaf, 0xcd, 0x2f, 0x3d, 0xb8, 0x5e, 0xa6, 0xc6, 0xc2, 0x92, 0x32, 0x77, 0xf5, 0xea, 0xa5, 0x5c,
0xdd, 0xae, 0x25, 0x6b, 0xcb, 0x6b, 0xc9, 0xfa, 0xb2, 0x5a, 0xb2, 0xb1, 0xb8, 0x96, 0x6c, 0x5a,
0xb5, 0x24, 0xfb, 0x39, 0x5c, 0x2b, 0x33, 0x29, 0x53, 0x45, 0xfc, 0x2d, 0x0b, 0xda, 0xde, 0x02,
0x03, 0x74, 0x35, 0xb2, 0xeb, 0xe2, 0xba, 0x78, 0x41, 0x0e, 0xea, 0x1f, 0x3c, 0xf0, 0x03, 0xfe,
0xfc, 0xe3, 0x19, 0x4f, 0xcf, 0x91, 0x4d, 0xe5, 0x38, 0xfb, 0x65, 0xa6, 0xc8, 0x1e, 0x6e, 0x31,
0xb2, 0x09, 0x8d, 0x21, 0xa6, 0x4a, 0x05, 0x97, 0x1c, 0x20, 0x52, 0xa3, 0x28, 0xe5, 0xf4, 0xde,
0xa7, 0x91, 0xca, 0x09, 0xc6, 0xd5, 0xd5, 0xb0, 0xae, 0xae, 0x4d, 0x68, 0x44, 0x14, 0xae, 0xb2,
0x14, 0x97, 0x03, 0xf6, 0x31, 0x16, 0x4b, 0xd3, 0xf1, 0xb9, 0xab, 0xe1, 0xbb, 0x74, 0x05, 0x49,
0x1f, 0x51, 0x99, 0x78, 0xa9, 0x1b, 0x15, 0xdc, 0xec, 0x03, 0xe3, 0xbd, 0x4e, 0x26, 0xfc, 0x07,
0x52, 0xb3, 0x5d, 0xcb, 0x6a, 0xbb, 0xa2, 0x71, 0xae, 0xf9, 0xbc, 0xc4, 0x12, 0xb2, 0xad, 0xa7,
0xe9, 0xa7, 0x51, 0xcc, 0xd3, 0x97, 0x97, 0x85, 0x45, 0x41, 0x94, 0x19, 0xda, 0xab, 0xe4, 0xbd,
0x12, 0xb8, 0x64, 0xf6, 0x9b, 0x86, 0xf1, 0xd6, 0xa4, 0x76, 0xbc, 0x8f, 0x05, 0x2f, 0x5a, 0xa3,
0x76, 0xbc, 0xee, 0xee, 0x68, 0xda, 0x4a, 0x71, 0x4e, 0x63, 0xff, 0x1e, 0x34, 0x26, 0xa8, 0x78,
0x49, 0x6b, 0xe7, 0x5a, 0x85, 0xc9, 0x87, 0x78, 0xfd, 0xef, 0x41, 0x27, 0xcc, 0x32, 0x2e, 0x8e,
0xd2, 0x30, 0xce, 0x9e, 0xf1, 0x54, 0xd5, 0xbf, 0x3a, 0x0b, 0x3d, 0xc0, 0xb9, 0x4c, 0x4f, 0x0e,
0x2a, 0x81, 0xcd, 0x9d, 0x2f, 0xff, 0x51, 0x24, 0x4e, 0x47, 0x69, 0xf8, 0x19, 0xb9, 0x82, 0xbb,
0x5c, 0x4f, 0xe6, 0xcb, 0x35, 0xc1, 0xbf, 0x07, 0x2b, 0x42, 0x6f, 0xdc, 0x5c, 0xbe, 0x71, 0xce,
0x88, 0x8b, 0x3e, 0xd3, 0xdb, 0xb5, 0x96, 0x6f, 0x97, 0x33, 0xfa, 0xef, 0x43, 0x57, 0x0b, 0x38,
0x4a, 0xde, 0x3f, 0xe3, 0x43, 0x2a, 0x77, 0x0a, 0x94, 0xec, 0xfd, 0x24, 0xcb, 0xa0, 0x12, 0x38,
0x8b, 0xfc, 0xf7, 0x00, 0xe2, 0xfc, 0x91, 0x81, 0x8a, 0xa2, 0x65, 0xcf, 0x08, 0x83, 0x4a, 0x60,
0xb0, 0xfb, 0x8f, 0xe1, 0x4a, 0x6c, 0x37, 0x2c, 0xea, 0x8e, 0x58, 0xd2, 0xd2, 0x0c, 0x2a, 0x81,
0xbb, 0xc8, 0x7f, 0x08, 0x57, 0x32, 0x1d, 0x40, 0x4a, 0x8e, 0xbc, 0x3b, 0xb6, 0x0c, 0x39, 0xc6,
0x2c, 0xca, 0x70, 0x16, 0x60, 0x02, 0x10, 0xe7, 0xaa, 0x55, 0xac, 0x8a, 0xf3, 0xe2, 0x92, 0xf8,
0xc2, 0xc3, 0x5e, 0x23, 0xef, 0xd0, 0x0c, 0x87, 0x5b, 0xd4, 0x9d, 0x19, 0xe5, 0xc9, 0xe5, 0xc2,
0xe3, 0x5b, 0x56, 0x77, 0x36, 0xe7, 0xde, 0xd6, 0xeb, 0xb2, 0xcc, 0x88, 0xf7, 0xdd, 0xfe, 0x6c,
0xf9, 0xa2, 0x3c, 0x2b, 0x7e, 0x60, 0x3d, 0x0f, 0x15, 0x51, 0xf0, 0x52, 0x19, 0xe2, 0x1f, 0x35,
0x4c, 0x61, 0xb6, 0x34, 0xba, 0xaf, 0xec, 0x0b, 0xc7, 0x9b, 0xbb, 0x70, 0xb0, 0xd9, 0xc6, 0x91,
0x84, 0x51, 0x81, 0x6e, 0x92, 0xfc, 0xb7, 0xa0, 0x8b, 0x97, 0xcc, 0x61, 0x38, 0xe1, 0x8a, 0x49,
0xe6, 0x61, 0x87, 0x5a, 0x54, 0x20, 0xf5, 0xf2, 0x1e, 0xa2, 0xe1, 0x76, 0x5e, 0x45, 0x75, 0xdf,
0x5c, 0x56, 0xdd, 0xb7, 0x96, 0x54, 0xf7, 0x2b, 0x4e, 0x75, 0x6f, 0x75, 0x1d, 0x6d, 0xb7, 0xeb,
0x30, 0x6a, 0x7f, 0xb8, 0xa0, 0xf6, 0x5f, 0xbd, 0x4c, 0xed, 0xbf, 0x56, 0x52, 0xfb, 0xcf, 0x75,
0x66, 0x9d, 0x4b, 0x76, 0x66, 0xdd, 0xd2, 0xce, 0x8c, 0xfd, 0x64, 0xde, 0xe3, 0x03, 0x3e, 0x4c,
0xd2, 0xd1, 0xab, 0xf2, 0x78, 0xf6, 0x75, 0x58, 0xcd, 0xa7, 0x8f, 0xce, 0xf0, 0xc0, 0x24, 0x2a,
0x4a, 0xb0, 0x1a, 0xc9, 0x0e, 0xbd, 0x78, 0x50, 0x38, 0xc2, 0xd3, 0x75, 0xbb, 0xc7, 0xcb, 0x7c,
0x80, 0x60, 0xbf, 0xa8, 0xc2, 0x86, 0xd5, 0xeb, 0xff, 0x7f, 0xf9, 0x69, 0xfb, 0x65, 0xfd, 0xb4,
0x5d, 0xf8, 0x29, 0xdb, 0x87, 0xd7, 0x2c, 0x08, 0x08, 0x4d, 0x4c, 0x3e, 0x4d, 0xd2, 0xc6, 0x7d,
0x1f, 0x98, 0x83, 0x2b, 0x50, 0x7c, 0x32, 0x89, 0xb8, 0xa7, 0x82, 0x9a, 0x95, 0x9f, 0xc9, 0xdc,
0x7b, 0x87, 0xf5, 0x05, 0xf3, 0xcf, 0x55, 0xe8, 0x16, 0x17, 0x3e, 0x5e, 0x3a, 0xe8, 0x64, 0xd8,
0x8a, 0x69, 0x27, 0xc3, 0xdf, 0x94, 0x9e, 0x13, 0x5d, 0x9f, 0x89, 0x04, 0x8f, 0x2e, 0xca, 0x2f,
0x36, 0x02, 0x7d, 0x25, 0x30, 0x28, 0x86, 0x47, 0xd5, 0x69, 0x47, 0x35, 0x42, 0x7a, 0x38, 0xa1,
0xc2, 0x4e, 0x41, 0x2e, 0x47, 0xb8, 0x27, 0x36, 0x78, 0x0a, 0x6d, 0xfa, 0x4d, 0xb5, 0xe2, 0xf9,
0xe4, 0x38, 0x19, 0xab, 0x87, 0x52, 0x35, 0x32, 0x8e, 0x0d, 0xac, 0x63, 0xa3, 0x0f, 0x42, 0x78,
0xdc, 0x88, 0x96, 0x8a, 0xb0, 0xab, 0xc4, 0x31, 0x47, 0xa7, 0x0f, 0x21, 0x61, 0x1a, 0x2a, 0xae,
0x2d, 0xd9, 0x62, 0x16, 0x14, 0x4c, 0x1b, 0xd9, 0x6c, 0x38, 0xe4, 0x59, 0xd6, 0x7b, 0x9d, 0x8c,
0xd3, 0x43, 0xf6, 0x77, 0xf5, 0x71, 0x83, 0x1a, 0xca, 0x47, 0xc7, 0x14, 0xb7, 0x0b, 0xdf, 0x9a,
0xcc, 0xd7, 0xa2, 0xaa, 0xf3, 0x25, 0xf4, 0xa2, 0x97, 0xa6, 0xb7, 0xa0, 0x3b, 0x0d, 0xf1, 0xd6,
0x78, 0x6a, 0xbe, 0x37, 0xad, 0x05, 0x0e, 0x35, 0x3f, 0xdf, 0xa3, 0x68, 0xc2, 0x15, 0xaa, 0x05,
0xc1, 0xbf, 0x09, 0x35, 0x71, 0x26, 0x3f, 0x40, 0xae, 0xee, 0xfa, 0xca, 0xb7, 0x8e, 0x8a, 0xcf,
0xe6, 0x01, 0x4e, 0xb3, 0xbf, 0xaa, 0x8f, 0x48, 0xa6, 0x51, 0xd4, 0x86, 0x5e, 0xd6, 0xb0, 0xf6,
0x57, 0x36, 0xac, 0xfd, 0x82, 0x86, 0xad, 0x17, 0x86, 0xb5, 0xc9, 0x88, 0xdd, 0xcf, 0x6b, 0xd0,
0xce, 0xff, 0x28, 0xe0, 0x7f, 0x1f, 0x56, 0xf6, 0xb9, 0xa0, 0xe0, 0xf0, 0xd7, 0xf3, 0x98, 0x7a,
0x7e, 0x28, 0xd2, 0x28, 0x3e, 0xe9, 0xbf, 0x39, 0x5f, 0xc3, 0x5a, 0xdf, 0x2e, 0x59, 0xc5, 0x7f,
0x17, 0xe0, 0x49, 0x94, 0x09, 0x15, 0xa6, 0x9d, 0x42, 0xc4, 0x87, 0xd1, 0xb8, 0xdf, 0x2f, 0x8b,
0x52, 0xc9, 0xca, 0x2a, 0xfe, 0x47, 0xe0, 0xef, 0x73, 0x72, 0x37, 0x33, 0x65, 0xde, 0x28, 0x44,
0x94, 0xa5, 0xd4, 0xfe, 0xc2, 0xc8, 0x67, 0x15, 0xff, 0x10, 0xba, 0xda, 0x9a, 0x4b, 0x4a, 0x7b,
0x73, 0x69, 0x45, 0x92, 0x4d, 0x59, 0xc5, 0x7f, 0x0f, 0xd6, 0xf7, 0xb9, 0xa0, 0xa0, 0xcf, 0xef,
0xbb, 0x6e, 0x21, 0x16, 0x0f, 0xa1, 0x7f, 0xd5, 0x15, 0x43, 0xec, 0xac, 0xe2, 0xdf, 0x82, 0xe6,
0x41, 0x76, 0x78, 0x1e, 0x0f, 0x5d, 0x68, 0x36, 0xd4, 0xf0, 0x20, 0xdb, 0x0b, 0x67, 0x27, 0xa7,
0xe2, 0x93, 0x29, 0xab, 0x1c, 0x37, 0xe9, 0xdf, 0x17, 0xf7, 0xfe, 0x17, 0x00, 0x00, 0xff, 0xff,
0x39, 0x2e, 0xe7, 0xcd, 0xca, 0x21, 0x00, 0x00,
func init() { proto.RegisterFile("paracross.proto", fileDescriptor_paracross_313193799a5638f5) }
var fileDescriptor_paracross_313193799a5638f5 = []byte{
// 2397 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xd4, 0x5a, 0xcd, 0x73, 0x1c, 0x47,
0x15, 0xdf, 0xd9, 0x2f, 0x69, 0x9f, 0x3e, 0x2c, 0x4d, 0x64, 0x79, 0x91, 0x1d, 0x47, 0xd5, 0x65,
0x52, 0x82, 0x38, 0x36, 0x96, 0xc1, 0x54, 0x8a, 0xa2, 0x88, 0x2d, 0xc7, 0x5a, 0x55, 0xec, 0x54,
0x32, 0x52, 0xe0, 0xc0, 0x85, 0xd1, 0x6e, 0x5b, 0x9a, 0x62, 0x77, 0x66, 0x3c, 0xdd, 0x9b, 0x48,
0x5c, 0x28, 0x0a, 0x38, 0xc3, 0x89, 0x2a, 0x38, 0xe4, 0x02, 0x67, 0xaa, 0xf8, 0x07, 0x38, 0x70,
0x0c, 0xa7, 0x70, 0xe0, 0xc0, 0x8d, 0x1b, 0x77, 0x0e, 0x5c, 0xa9, 0x7e, 0xdd, 0x3d, 0xfd, 0xb1,
0xb3, 0x63, 0xd9, 0xf1, 0x25, 0xb7, 0xed, 0xd7, 0xaf, 0x5f, 0xbf, 0xf7, 0xeb, 0xf7, 0x5e, 0xbf,
0xd7, 0xb3, 0x70, 0x29, 0x8f, 0x8b, 0x78, 0x58, 0x64, 0x8c, 0xdd, 0xca, 0x8b, 0x8c, 0x67, 0x61,
0x87, 0x9f, 0xe7, 0x94, 0x6d, 0xad, 0xf3, 0x22, 0x4e, 0x59, 0x3c, 0xe4, 0x49, 0x96, 0xca, 0x99,
0xad, 0xe5, 0x61, 0x36, 0x99, 0x94, 0xa3, 0xb5, 0xe3, 0x71, 0x36, 0xfc, 0xe9, 0xf0, 0x34, 0x4e,
0x14, 0x85, 0x3c, 0x86, 0xcd, 0x0f, 0xb5, 0xb0, 0x43, 0x1e, 0xf3, 0x29, 0x7b, 0x48, 0x79, 0x9c,
0x8c, 0x59, 0xb8, 0x01, 0x9d, 0x78, 0x34, 0x2a, 0x58, 0x3f, 0xd8, 0x6e, 0xed, 0xf4, 0x22, 0x39,
0x08, 0xaf, 0x41, 0x0f, 0x65, 0x0c, 0x62, 0x76, 0xda, 0x6f, 0x6e, 0xb7, 0x76, 0x96, 0x23, 0x43,
0x20, 0x3f, 0x86, 0xab, 0x9e, 0xb4, 0x07, 0x62, 0x4e, 0x8b, 0xbc, 0x0e, 0x50, 0xf2, 0x4a, 0xb9,
0xcb, 0x91, 0x45, 0x11, 0xc2, 0xf9, 0x59, 0x44, 0xd9, 0x74, 0xcc, 0x99, 0x16, 0x5e, 0x12, 0xc8,
0x1f, 0x9a, 0x70, 0xb9, 0x94, 0x3e, 0xa0, 0xc9, 0xc9, 0x29, 0x97, 0x7b, 0x84, 0x9b, 0xd0, 0x65,
0xf8, 0xab, 0x1f, 0x6c, 0x07, 0x3b, 0x9d, 0x48, 0x8d, 0x84, 0x09, 0x3c, 0xe1, 0x63, 0xda, 0x6f,
0x6e, 0x07, 0xc2, 0x04, 0x1c, 0x08, 0xee, 0x53, 0x5c, 0xdd, 0x6f, 0x6d, 0x07, 0x3b, 0xad, 0x48,
0x8d, 0xc2, 0xef, 0xc2, 0xc2, 0x48, 0x2a, 0xda, 0x6f, 0x6f, 0x07, 0x3b, 0x4b, 0xbb, 0xaf, 0xdf,
0x42, 0x58, 0x6f, 0x55, 0x03, 0x14, 0x69, 0x6e, 0x61, 0xd6, 0x24, 0x4e, 0x52, 0xa9, 0x52, 0xbf,
0x83, 0x42, 0x2d, 0x4a, 0xb8, 0x05, 0x8b, 0x38, 0x12, 0x90, 0x75, 0xb7, 0x83, 0x9d, 0xe5, 0xa8,
0x1c, 0x87, 0x8f, 0x60, 0xf9, 0xd8, 0x82, 0xa8, 0xbf, 0x80, 0x3b, 0x93, 0xea, 0x9d, 0x6d, 0x30,
0x23, 0x67, 0x1d, 0xf9, 0x4f, 0x00, 0xfd, 0x4a, 0x70, 0x22, 0x96, 0xbf, 0x22, 0x7c, 0x5c, 0x33,
0xdb, 0xb5, 0x66, 0x76, 0x50, 0xa0, 0x31, 0x73, 0x1b, 0x96, 0x84, 0x23, 0x26, 0xfc, 0x3e, 0xba,
0x54, 0x17, 0x5d, 0xca, 0x26, 0x85, 0x3b, 0x70, 0x49, 0x0e, 0x1f, 0x94, 0xee, 0xb5, 0x80, 0x5c,
0x3e, 0x99, 0xfc, 0x3e, 0x80, 0x4b, 0x1e, 0x30, 0xc6, 0x92, 0xa0, 0xda, 0x92, 0xa6, 0x63, 0x89,
0xe3, 0xc4, 0x2d, 0x3c, 0x11, 0x43, 0x78, 0x61, 0x3b, 0xad, 0xe3, 0x24, 0x7f, 0xb2, 0x8f, 0x61,
0x2f, 0x4b, 0x19, 0x4d, 0xd9, 0xb4, 0x5e, 0x49, 0x01, 0xcd, 0xa9, 0xd9, 0x4f, 0x6a, 0x6a, 0x93,
0xc2, 0x1b, 0xb0, 0x32, 0x94, 0xa2, 0x06, 0xf6, 0xb9, 0xb8, 0xc4, 0xf0, 0x9b, 0xb0, 0xa6, 0x08,
0x06, 0xc1, 0x36, 0x6e, 0x34, 0x43, 0x27, 0xbf, 0x0b, 0x20, 0x14, 0x6a, 0x7e, 0x90, 0x8d, 0xa8,
0x80, 0x7f, 0x2f, 0x4b, 0x9f, 0x26, 0x27, 0x73, 0x14, 0x5c, 0x85, 0x66, 0x96, 0xa3, 0x5e, 0x2b,
0x51, 0x33, 0xcb, 0xc5, 0x38, 0x19, 0xa1, 0x0e, 0xbd, 0xa8, 0x99, 0x8c, 0xc2, 0x10, 0xda, 0x22,
0x37, 0xa8, 0xcd, 0xf0, 0xb7, 0x90, 0xf4, 0x49, 0x3c, 0x9e, 0x52, 0x04, 0x68, 0x25, 0x92, 0x03,
0xe9, 0x05, 0x49, 0xca, 0x1e, 0x15, 0xd9, 0xcf, 0x68, 0x8a, 0xb1, 0x20, 0x4c, 0x35, 0x24, 0xf2,
0xae, 0xd1, 0xeb, 0x87, 0x19, 0xa7, 0xd2, 0xbb, 0xe7, 0xa4, 0x22, 0xb1, 0x47, 0xc6, 0xa9, 0xcc,
0x14, 0xbd, 0x48, 0x0e, 0xc8, 0x6f, 0x03, 0xd8, 0xb0, 0x4d, 0x3b, 0x18, 0x29, 0xf4, 0xb5, 0x9a,
0x81, 0xa5, 0xe6, 0x75, 0x80, 0xbc, 0xc8, 0xf2, 0x8c, 0xc5, 0xe3, 0x83, 0x91, 0x8a, 0x02, 0x8b,
0x22, 0x1c, 0xe8, 0xd9, 0x34, 0xe1, 0x07, 0xda, 0x5c, 0x35, 0xb2, 0x02, 0xaa, 0x5d, 0x1d, 0x50,
0x1d, 0x0b, 0x40, 0xf2, 0xbf, 0x00, 0xd6, 0xb4, 0x4a, 0xa5, 0x3a, 0x12, 0xc5, 0xa0, 0x44, 0xd1,
0x88, 0x6c, 0x56, 0x8b, 0x6c, 0xd9, 0x67, 0x72, 0x1d, 0x80, 0xc7, 0xc5, 0x09, 0xc5, 0xe0, 0x51,
0xc8, 0x5b, 0x14, 0x1f, 0xe9, 0xce, 0x0c, 0xd2, 0xe1, 0x6d, 0x8d, 0x5e, 0x17, 0x33, 0xce, 0xd7,
0xac, 0x8c, 0xe3, 0xa2, 0xaf, 0x80, 0x15, 0x6e, 0xff, 0xb4, 0xc8, 0x26, 0xb8, 0xe1, 0x82, 0x0c,
0x6f, 0x3d, 0xb6, 0x02, 0x6d, 0xd1, 0x0e, 0x34, 0xf2, 0xd7, 0x00, 0x2e, 0x47, 0x74, 0x48, 0x93,
0x9c, 0x6b, 0xc1, 0xca, 0xd5, 0xaa, 0x4e, 0xe3, 0x0e, 0x74, 0x87, 0x38, 0x8b, 0x10, 0xcc, 0xea,
0x64, 0x3c, 0x35, 0x52, 0x8c, 0xe1, 0x5b, 0xd0, 0xce, 0x0b, 0xfa, 0x09, 0x82, 0xb3, 0xb4, 0x7b,
0xc5, 0x5b, 0xa0, 0xc1, 0x8e, 0x90, 0x29, 0xbc, 0x03, 0x0b, 0xc3, 0x69, 0x51, 0xd0, 0x94, 0xab,
0x04, 0x3f, 0x97, 0x5f, 0xf3, 0x91, 0x3f, 0x06, 0xf0, 0xba, 0x67, 0x80, 0xd0, 0x42, 0xb0, 0x7d,
0x9c, 0x8f, 0x62, 0x4e, 0x1d, 0x58, 0x02, 0x0f, 0x96, 0xdb, 0x4a, 0x3b, 0x69, 0xce, 0xd5, 0x0a,
0x73, 0x3c, 0x0d, 0xbf, 0x63, 0x34, 0x6c, 0x3d, 0x7f, 0x4d, 0xa9, 0xe5, 0x7f, 0x03, 0xb8, 0xe2,
0x69, 0x89, 0xe7, 0x97, 0xa5, 0x74, 0xc6, 0xcf, 0xaa, 0x73, 0xbe, 0xeb, 0x4f, 0xad, 0x19, 0x7f,
0x12, 0xf3, 0x19, 0x8f, 0xc7, 0x42, 0xb4, 0x76, 0x7a, 0x8b, 0x82, 0x37, 0xb7, 0x18, 0x89, 0x6d,
0xd1, 0xdb, 0x3a, 0x91, 0x21, 0x60, 0xc6, 0xcc, 0x18, 0xc7, 0xc9, 0x2e, 0x4e, 0x96, 0xe3, 0xb0,
0x0f, 0x0b, 0xc2, 0xbf, 0x22, 0xc6, 0x95, 0x57, 0xe9, 0xa1, 0xd8, 0x73, 0x94, 0xa5, 0x54, 0x1a,
0x8b, 0x8e, 0xd5, 0x89, 0x2c, 0x0a, 0xf9, 0x65, 0x00, 0xaf, 0x69, 0x73, 0xf7, 0x8b, 0x6c, 0x9a,
0x7f, 0xa9, 0x2c, 0x56, 0xe6, 0x18, 0x19, 0x4c, 0x2a, 0xc7, 0x3c, 0x37, 0x8e, 0xc8, 0xdf, 0x7d,
0x2d, 0x5e, 0x49, 0x7c, 0x6f, 0xc3, 0x92, 0x41, 0x5f, 0xeb, 0x64, 0x93, 0x2e, 0x10, 0xe1, 0xb6,
0x67, 0x76, 0xe7, 0x06, 0xec, 0x82, 0x13, 0xb0, 0x9f, 0x07, 0xb0, 0xe5, 0x79, 0x92, 0x0d, 0x6d,
0x55, 0xd4, 0xee, 0x7a, 0x51, 0xbb, 0xe5, 0xb9, 0xac, 0xb5, 0xbe, 0x0c, 0xdb, 0x5b, 0x4e, 0xd8,
0x56, 0xae, 0x70, 0xe2, 0xe2, 0xdb, 0x7e, 0xe4, 0xd6, 0x2d, 0x29, 0xc3, 0xe2, 0x14, 0x36, 0x22,
0xfa, 0xac, 0xbc, 0x8e, 0x31, 0xc2, 0xd3, 0xa7, 0xd9, 0x7c, 0x07, 0x49, 0xf4, 0x1d, 0x60, 0x5f,
0x6b, 0x2d, 0xcb, 0xd6, 0x39, 0x79, 0x9f, 0xec, 0xc1, 0x66, 0x44, 0x59, 0xee, 0x6c, 0x25, 0x8f,
0xe9, 0x1b, 0xd0, 0x4a, 0x46, 0xf2, 0xe2, 0xaa, 0xc9, 0x37, 0x82, 0x87, 0xec, 0x8b, 0x20, 0xf6,
0x84, 0xa0, 0x5d, 0x2c, 0xbc, 0x69, 0x4b, 0xa9, 0xb3, 0x1d, 0x05, 0xfd, 0x3a, 0x80, 0x75, 0x31,
0x89, 0xf7, 0xfd, 0xee, 0x93, 0x38, 0x49, 0x9f, 0xc4, 0xb9, 0x75, 0xe4, 0xc1, 0xfc, 0x62, 0x48,
0x9a, 0x3f, 0xb7, 0x18, 0x6a, 0xd5, 0x16, 0x43, 0x6d, 0xb7, 0xe8, 0x23, 0x0f, 0xe5, 0x65, 0x6e,
0xd4, 0x40, 0xf4, 0x6f, 0x41, 0x27, 0xe1, 0x74, 0xa2, 0xad, 0xe9, 0x5b, 0xd6, 0x38, 0x0a, 0x47,
0x92, 0x8d, 0xfc, 0xbb, 0x25, 0x03, 0xac, 0xc4, 0x44, 0x05, 0xd8, 0x0d, 0x58, 0x11, 0x3b, 0x99,
0x62, 0x27, 0xc0, 0x5a, 0xcc, 0x25, 0x8a, 0xb2, 0xd2, 0x10, 0xec, 0x0a, 0xcb, 0x27, 0xcf, 0x09,
0x44, 0x83, 0x5a, 0xdb, 0x41, 0x8d, 0xc0, 0x72, 0x5e, 0x50, 0xb3, 0xb9, 0x2c, 0x04, 0x1d, 0x9a,
0x8b, 0x6c, 0xd7, 0x2f, 0x33, 0xa5, 0x04, 0x61, 0x0c, 0x55, 0xd5, 0xae, 0x96, 0x50, 0xd2, 0x84,
0x04, 0x56, 0x32, 0x2c, 0x4a, 0x09, 0x25, 0x41, 0x60, 0xcf, 0xcf, 0xf6, 0xb2, 0x69, 0xca, 0x59,
0xbf, 0x87, 0x89, 0xad, 0x1c, 0xcb, 0x39, 0xd9, 0x39, 0xf5, 0x41, 0x16, 0xa9, 0x7a, 0x2c, 0x52,
0x2e, 0x3f, 0x93, 0x3d, 0xd8, 0x12, 0x36, 0x59, 0x7a, 0x88, 0x95, 0xa6, 0x80, 0xf9, 0x48, 0x2f,
0x5d, 0x96, 0x98, 0x3a, 0x44, 0xa1, 0xb9, 0x22, 0x48, 0x21, 0x2b, 0x28, 0xc4, 0xa1, 0x85, 0x37,
0x61, 0x3d, 0xcd, 0xd2, 0x3d, 0x2c, 0xdd, 0x8f, 0xb4, 0x92, 0xab, 0xa8, 0xe4, 0xec, 0x04, 0x79,
0x00, 0xeb, 0x87, 0x74, 0xfc, 0x54, 0x15, 0xcc, 0x87, 0x3c, 0x3e, 0xa1, 0x2c, 0x7c, 0xdb, 0x75,
0x14, 0x1d, 0x3c, 0x3e, 0xa3, 0xf6, 0x93, 0xc7, 0xb0, 0xe6, 0x4f, 0x89, 0x24, 0xc9, 0x78, 0x5c,
0xf0, 0x81, 0xed, 0xf8, 0x36, 0x49, 0x9c, 0x2f, 0x4d, 0xe3, 0x63, 0x75, 0x1f, 0xae, 0x44, 0x6a,
0x44, 0xfe, 0x15, 0xc0, 0x86, 0x2f, 0x0e, 0xdd, 0xb7, 0x3e, 0xaf, 0xaf, 0x94, 0x79, 0xfd, 0x6d,
0xe8, 0x30, 0xb1, 0xc8, 0x2b, 0x4d, 0x66, 0xb5, 0x47, 0x2e, 0x27, 0x59, 0xb7, 0xbd, 0x64, 0x7d,
0x1d, 0x80, 0x9e, 0xd1, 0xa1, 0xdb, 0x5f, 0x1a, 0xca, 0x0b, 0x97, 0x72, 0x84, 0xc2, 0xe6, 0xe3,
0x6c, 0x18, 0x8f, 0xb5, 0x32, 0xc6, 0xba, 0x3b, 0x5a, 0xeb, 0xc0, 0x29, 0x3f, 0xaa, 0x90, 0xd0,
0x9a, 0xa3, 0x37, 0x1d, 0xa4, 0x23, 0x7a, 0xa6, 0xb2, 0x87, 0x1e, 0x92, 0x7b, 0xb0, 0x2a, 0xf3,
0xbe, 0xd0, 0xa0, 0x12, 0xbc, 0xb2, 0x4d, 0x68, 0x5a, 0x6d, 0x02, 0x21, 0xb0, 0x26, 0xd7, 0xed,
0xc5, 0xe9, 0x90, 0x8e, 0xab, 0x56, 0x92, 0x2f, 0x54, 0x13, 0x88, 0xea, 0xbc, 0xd0, 0xc5, 0x7f,
0x5b, 0x9b, 0x08, 0xb5, 0x07, 0x33, 0x68, 0x68, 0x03, 0xdf, 0x82, 0xb6, 0x80, 0xad, 0xbf, 0x84,
0xfc, 0x97, 0x15, 0xbf, 0x6b, 0xd9, 0xa0, 0x11, 0x21, 0x13, 0xd6, 0xb0, 0xa8, 0x35, 0x86, 0x8e,
0x11, 0xef, 0x1b, 0x34, 0x68, 0x44, 0x8a, 0xf1, 0xc1, 0x82, 0x02, 0x81, 0xfc, 0xca, 0x5c, 0xbe,
0xce, 0xc9, 0x28, 0xf3, 0x74, 0x35, 0x79, 0x81, 0xa3, 0x99, 0xa9, 0x26, 0x9b, 0xcf, 0x5f, 0x53,
0x5e, 0x9b, 0x5f, 0x04, 0x70, 0xad, 0x4a, 0x8d, 0xb9, 0x25, 0x65, 0xe9, 0xea, 0xcd, 0x0b, 0xb9,
0xba, 0x5b, 0x4b, 0xb6, 0xea, 0x6b, 0xc9, 0x76, 0x5d, 0x2d, 0xd9, 0x99, 0x5f, 0x4b, 0x76, 0x9d,
0x5a, 0x92, 0xfc, 0x1c, 0xae, 0x56, 0x99, 0xc4, 0x54, 0x11, 0x7f, 0xd3, 0x81, 0xb6, 0x3f, 0xc7,
0x00, 0x5d, 0x8d, 0xec, 0xfa, 0xb8, 0xce, 0x5f, 0x50, 0x82, 0xfa, 0x59, 0x00, 0x61, 0x44, 0x9f,
0x7d, 0x34, 0xa5, 0xc5, 0xb9, 0x60, 0x53, 0x39, 0xce, 0x7d, 0x99, 0x31, 0xd9, 0xc3, 0x2f, 0x46,
0x36, 0xa0, 0x33, 0x14, 0xa9, 0x52, 0xc1, 0x25, 0x07, 0x02, 0xa9, 0x51, 0x52, 0x50, 0x7c, 0xef,
0xd3, 0x48, 0x95, 0x04, 0xeb, 0xea, 0xea, 0x38, 0x57, 0xd7, 0x06, 0x74, 0x12, 0x0c, 0x57, 0x59,
0x8a, 0xcb, 0x01, 0xf9, 0x48, 0x14, 0x4b, 0xf9, 0xf8, 0xdc, 0xd7, 0xf0, 0x1d, 0xbc, 0x82, 0xa4,
0x8f, 0xa8, 0x4c, 0x5c, 0xeb, 0x46, 0x86, 0x9b, 0xbc, 0x6f, 0xbd, 0xd7, 0xc9, 0x84, 0x7f, 0x5f,
0x6a, 0xb6, 0xeb, 0x58, 0xed, 0x56, 0x34, 0xde, 0x35, 0x5f, 0x96, 0x58, 0x5c, 0xb6, 0xf5, 0x38,
0xfd, 0x24, 0x49, 0x69, 0xf1, 0xf2, 0xb2, 0x44, 0x51, 0x90, 0x30, 0x4b, 0x7b, 0x95, 0xbc, 0x17,
0x23, 0x9f, 0x4c, 0x7e, 0xd3, 0xb1, 0xde, 0x9a, 0xd4, 0x8e, 0xf7, 0x44, 0xc1, 0x2b, 0xac, 0x51,
0x3b, 0x5e, 0xf3, 0x77, 0xb4, 0x6d, 0xc5, 0x38, 0xc7, 0x71, 0x78, 0x17, 0x3a, 0x13, 0xa1, 0x78,
0x45, 0x6b, 0xe7, 0x5b, 0x25, 0x92, 0x0f, 0xf2, 0x86, 0xdf, 0x87, 0x95, 0x98, 0x31, 0xca, 0x8f,
0x8a, 0x38, 0x65, 0x4f, 0x69, 0xa1, 0xea, 0x5f, 0x9d, 0x85, 0xee, 0x8b, 0x39, 0xa6, 0x27, 0x07,
0x8d, 0xc8, 0xe5, 0x2e, 0x97, 0xff, 0x28, 0xe1, 0xa7, 0xa3, 0x22, 0xfe, 0x14, 0x5d, 0xc1, 0x5f,
0xae, 0x27, 0xcb, 0xe5, 0x9a, 0x10, 0xde, 0x85, 0x45, 0xae, 0x37, 0xee, 0xd6, 0x6f, 0x5c, 0x32,
0x8a, 0x45, 0x9f, 0xea, 0xed, 0x16, 0xea, 0xb7, 0x2b, 0x19, 0xc3, 0xf7, 0x60, 0x55, 0x0b, 0x38,
0xca, 0xde, 0x3b, 0xa3, 0x43, 0x2c, 0x77, 0x0c, 0x4a, 0xee, 0x7e, 0x92, 0x65, 0xd0, 0x88, 0xbc,
0x45, 0xe1, 0xf7, 0x00, 0xd2, 0xf2, 0x91, 0x01, 0x8b, 0xa2, 0xba, 0x67, 0x84, 0x41, 0x23, 0xb2,
0xd8, 0xc3, 0x47, 0x70, 0x29, 0x75, 0x1b, 0x16, 0x75, 0x47, 0xd4, 0xb4, 0x34, 0x83, 0x46, 0xe4,
0x2f, 0x0a, 0x1f, 0xc0, 0x25, 0xa6, 0x03, 0x48, 0xc9, 0x91, 0x77, 0xc7, 0xa6, 0x25, 0xc7, 0x9a,
0x15, 0x32, 0xbc, 0x05, 0x22, 0x01, 0xf0, 0x73, 0xd5, 0x2a, 0x36, 0xf9, 0xb9, 0xb9, 0x24, 0x3e,
0x0f, 0x44, 0xaf, 0x51, 0x76, 0x68, 0x96, 0xc3, 0xcd, 0xeb, 0xce, 0xac, 0xf2, 0xe4, 0x62, 0xe1,
0xf1, 0x2d, 0xa7, 0x3b, 0x9b, 0x71, 0x6f, 0xe7, 0x75, 0x59, 0x66, 0xc4, 0x7b, 0x7e, 0x7f, 0x56,
0xbf, 0xa8, 0xcc, 0x8a, 0xef, 0x3b, 0xcf, 0x43, 0x26, 0x0a, 0x5e, 0x2a, 0x43, 0xfc, 0xb3, 0x25,
0x52, 0x98, 0x2b, 0x0d, 0xef, 0x2b, 0xf7, 0xc2, 0x09, 0x66, 0x2e, 0x1c, 0xd1, 0x6c, 0x8b, 0x91,
0x84, 0x51, 0x81, 0x6e, 0x93, 0xc2, 0x37, 0x61, 0x55, 0x5c, 0x32, 0x87, 0xf1, 0x84, 0x2a, 0x26,
0x99, 0x87, 0x3d, 0xaa, 0xa9, 0x40, 0xda, 0xd5, 0x3d, 0x44, 0xc7, 0xef, 0xbc, 0x4c, 0x75, 0xdf,
0xad, 0xab, 0xee, 0x17, 0x6a, 0xaa, 0xfb, 0x45, 0xaf, 0xba, 0x77, 0xba, 0x8e, 0x9e, 0xdf, 0x75,
0x58, 0xb5, 0x3f, 0x3c, 0xa7, 0xf6, 0x5f, 0xba, 0x48, 0xed, 0xbf, 0x5c, 0x51, 0xfb, 0xcf, 0x74,
0x66, 0x2b, 0x17, 0xec, 0xcc, 0x56, 0x2b, 0x3b, 0x33, 0xf2, 0x93, 0x59, 0x8f, 0x8f, 0xe8, 0x30,
0x2b, 0x46, 0xaf, 0xca, 0xe3, 0xc9, 0xd7, 0x61, 0xa9, 0x9c, 0x3e, 0x3a, 0x13, 0x07, 0x26, 0x51,
0x51, 0x82, 0xd5, 0x48, 0x76, 0xe8, 0xe6, 0x41, 0xe1, 0x48, 0x9c, 0xae, 0xdf, 0x3d, 0x5e, 0xe4,
0x03, 0x04, 0xf9, 0x45, 0x13, 0xd6, 0x9d, 0x5e, 0xff, 0xab, 0xe5, 0xa7, 0xbd, 0x97, 0xf5, 0xd3,
0x9e, 0xf1, 0x53, 0xb2, 0x0f, 0xaf, 0x39, 0x10, 0x20, 0x9a, 0x22, 0xf9, 0x74, 0x51, 0x1b, 0xff,
0x7d, 0x60, 0x06, 0xae, 0x48, 0xf1, 0xc9, 0x24, 0xe2, 0x9f, 0x8a, 0xd0, 0xac, 0xfa, 0x4c, 0x66,
0xde, 0x3b, 0x9c, 0x2f, 0x98, 0x7f, 0x6e, 0xc2, 0xaa, 0xb9, 0xf0, 0xc5, 0xa5, 0x23, 0x9c, 0x4c,
0xb4, 0x62, 0xda, 0xc9, 0xc4, 0x6f, 0x4c, 0xcf, 0x99, 0xae, 0xcf, 0x78, 0x26, 0x8e, 0x2e, 0x29,
0x2f, 0x36, 0x04, 0x7d, 0x31, 0xb2, 0x28, 0x96, 0x47, 0xb5, 0x71, 0x47, 0x35, 0x12, 0xf4, 0x78,
0x82, 0x85, 0x9d, 0x82, 0x5c, 0x8e, 0xc4, 0x9e, 0xa2, 0xc1, 0x53, 0x68, 0xe3, 0x6f, 0xac, 0x15,
0xcf, 0x27, 0xc7, 0xd9, 0x58, 0x3d, 0x94, 0xaa, 0x91, 0x75, 0x6c, 0xe0, 0x1c, 0x1b, 0x7e, 0x10,
0x12, 0xc7, 0x2d, 0xd0, 0x52, 0x11, 0x76, 0x19, 0x39, 0x66, 0xe8, 0xf8, 0x21, 0x24, 0x2e, 0x62,
0xc5, 0xb5, 0x29, 0x5b, 0x4c, 0x43, 0x11, 0x69, 0x83, 0x4d, 0x87, 0x43, 0xca, 0x58, 0xff, 0x0a,
0x1a, 0xa7, 0x87, 0xe4, 0x2f, 0x4d, 0xf9, 0xd8, 0x64, 0x00, 0x8b, 0x58, 0xfe, 0x92, 0x98, 0xf5,
0x6a, 0x30, 0xeb, 0x7d, 0xd5, 0x31, 0xeb, 0x19, 0xcc, 0xfe, 0xa1, 0x3e, 0x08, 0x61, 0x13, 0xfe,
0xf0, 0x18, 0x73, 0xdd, 0xdc, 0xf7, 0x39, 0xfb, 0x85, 0xad, 0xe9, 0x7d, 0x3d, 0x7e, 0xde, 0xeb,
0xdc, 0x9b, 0xb0, 0x9a, 0xc7, 0xe2, 0xa6, 0x7d, 0x62, 0xbf, 0xd1, 0x2d, 0x47, 0x1e, 0xb5, 0x8c,
0x89, 0xa3, 0x64, 0x42, 0x15, 0xaa, 0x86, 0x10, 0xde, 0x80, 0x16, 0x3f, 0x93, 0x1f, 0x6d, 0x97,
0x76, 0x43, 0x15, 0x8f, 0x47, 0xe6, 0xaf, 0x06, 0x91, 0x98, 0x26, 0x7f, 0x53, 0x1f, 0xde, 0x6c,
0xa3, 0xb0, 0x75, 0xbf, 0xa8, 0x61, 0xbd, 0x2f, 0x6d, 0x58, 0xef, 0x05, 0x0d, 0x5b, 0x33, 0x86,
0xf5, 0xd0, 0x88, 0xdd, 0xcf, 0x5a, 0xd0, 0x2b, 0xff, 0x5c, 0x11, 0xfe, 0x00, 0x16, 0xf7, 0x29,
0xc7, 0x84, 0x12, 0xae, 0x95, 0x79, 0xe8, 0xd9, 0x21, 0x2f, 0x92, 0xf4, 0x64, 0xeb, 0x8d, 0xd9,
0xba, 0xdf, 0xf9, 0xde, 0x4b, 0x1a, 0xe1, 0x3b, 0x00, 0x8f, 0x13, 0xc6, 0x55, 0x6a, 0x5b, 0x31,
0x22, 0x3e, 0x48, 0xc6, 0x5b, 0x5b, 0x55, 0x99, 0x4d, 0xb2, 0x92, 0x46, 0xf8, 0x21, 0x84, 0xfb,
0x14, 0xdd, 0xcd, 0xbe, 0x66, 0xae, 0x1b, 0x11, 0x55, 0xd7, 0xd0, 0xd6, 0xdc, 0x6c, 0x49, 0x1a,
0xe1, 0x21, 0xac, 0x6a, 0x6b, 0x2e, 0x28, 0xed, 0x8d, 0xda, 0x2a, 0x8e, 0xe5, 0xa4, 0x11, 0xbe,
0x0b, 0x6b, 0xfb, 0x94, 0x63, 0xdc, 0x97, 0x35, 0xc2, 0x2c, 0x54, 0x7d, 0x5f, 0x90, 0x4e, 0x14,
0xa4, 0x11, 0xde, 0x84, 0xee, 0x01, 0x3b, 0x3c, 0x4f, 0x87, 0x3e, 0x3e, 0xeb, 0x6a, 0x78, 0xc0,
0xf6, 0xe2, 0xe9, 0xc9, 0x29, 0xff, 0x38, 0x27, 0x8d, 0xe3, 0x2e, 0xfe, 0x6d, 0xe5, 0xee, 0xff,
0x03, 0x00, 0x00, 0xff, 0xff, 0x3c, 0x35, 0x92, 0x17, 0x03, 0x23, 0x00, 0x00,
}
......@@ -26,6 +26,8 @@ var (
MainLoopCheckCommitTxDoneForkHeight = "mainLoopCheckCommitTxDoneForkHeight"
// ForkParaSelfConsStages 平行链自共识分阶段共识
ForkParaSelfConsStages = "ForkParaSelfConsStages"
// ForkParaAssetTransferRbk 平行链资产转移平行链失败主链回滚
ForkParaAssetTransferRbk = "ForkParaAssetTransferRbk"
// ParaConsSubConf sub
ParaConsSubConf = "consensus.sub.para"
......@@ -52,6 +54,8 @@ func InitFork(cfg *types.Chain33Config) {
cfg.RegisterDappFork(ParaX, "ForkParacrossWithdrawFromParachain", 1298600)
cfg.RegisterDappFork(ParaX, ForkCommitTx, 1850000)
cfg.RegisterDappFork(ParaX, ForkLoopCheckCommitTxDone, 3230000)
cfg.RegisterDappFork(ParaX, ForkParaAssetTransferRbk, 4500000)
//只在平行链启用
cfg.RegisterDappFork(ParaX, ForkParaSelfConsStages, types.MaxHeight)
}
......
all:
chmod +x ./build.sh
./build.sh $(OUT) $(FLAG)
#!/bin/sh
# 官方ci集成脚本
strpwd=$(pwd)
strcmd=${strpwd##*dapp/}
strapp=${strcmd%/cmd*}
OUT_DIR="${1}/$strapp"
#FLAG=$2
mkdir -p "${OUT_DIR}"
cp ./build/* "${OUT_DIR}"
/*Package commands implement dapp client commands*/
package commands
import (
"github.com/spf13/cobra"
)
/*
* 实现合约对应客户端
*/
// Cmd storage client command
func Cmd() *cobra.Command {
cmd := &cobra.Command{
Use: "storage",
Short: "storage command",
Args: cobra.MinimumNArgs(1),
}
cmd.AddCommand(
//add sub command
)
return cmd
}
package crypto
import (
"crypto/aes"
"crypto/cipher"
)
type AES struct {
key []byte
//iv的长度必须等于block块的大小,这里是16字节,固定
iv []byte
}
//AES 密钥长度为 16,24,32 字节,三种
func NewAES(key, iv []byte) *AES {
return &AES{key: key, iv: iv}
}
func (a *AES) Encrypt(origData []byte) ([]byte, error) {
block, err := aes.NewCipher(a.key)
if err != nil {
return nil, err
}
blockSize := block.BlockSize()
origData = PKCS5Padding(origData, blockSize)
// origData = ZeroPadding(origData, block.BlockSize())
blockMode := cipher.NewCBCEncrypter(block, a.iv[:blockSize])
crypted := make([]byte, len(origData))
// 根据CryptBlocks方法的说明,如下方式初始化crypted也可以
// crypted := origData
blockMode.CryptBlocks(crypted, origData)
return crypted, nil
}
func (a *AES) Decrypt(crypted []byte) ([]byte, error) {
block, err := aes.NewCipher(a.key)
if err != nil {
return nil, err
}
blockSize := block.BlockSize()
blockMode := cipher.NewCBCDecrypter(block, a.iv[:blockSize])
origData := make([]byte, len(crypted))
// origData := crypted
blockMode.CryptBlocks(origData, crypted)
origData = PKCS5UnPadding(origData)
// origData = ZeroUnPadding(origData)
return origData, nil
}
package crypto
import (
"encoding/base64"
"testing"
"github.com/stretchr/testify/assert"
)
//DES 加解密测试
func TestAes(t *testing.T) {
aes := NewAES(keys[2], ivs[0])
result, err := aes.Encrypt(contents[1])
if err != nil {
t.Error(err)
}
t.Log(base64.StdEncoding.EncodeToString(result))
origData, err := aes.Decrypt(result)
if err != nil {
t.Error(err)
}
assert.Equal(t, contents[1], origData)
}
package crypto
import "bytes"
type Crypto interface {
Encrypt(origData []byte) ([]byte, error)
Decrypt(crypted []byte) ([]byte, error)
}
func ZeroPadding(ciphertext []byte, blockSize int) []byte {
padding := blockSize - len(ciphertext)%blockSize
padtext := bytes.Repeat([]byte{0}, padding)
return append(ciphertext, padtext...)
}
func ZeroUnPadding(origData []byte) []byte {
return bytes.TrimRightFunc(origData, func(r rune) bool {
return r == rune(0)
})
}
func PKCS5Padding(ciphertext []byte, blockSize int) []byte {
padding := blockSize - len(ciphertext)%blockSize
padtext := bytes.Repeat([]byte{byte(padding)}, padding)
return append(ciphertext, padtext...)
}
func PKCS5UnPadding(origData []byte) []byte {
length := len(origData)
// 去掉最后一个字节 unpadding 次
unpadding := int(origData[length-1])
return origData[:(length - unpadding)]
}
package crypto
import (
"crypto/cipher"
"crypto/des"
)
type DES struct {
key []byte
//iv的长度必须等于block块的大小
iv []byte
}
func NewDES(key, iv []byte) *DES {
return &DES{key: key, iv: iv}
}
func (d *DES) Encrypt(origData []byte) ([]byte, error) {
block, err := des.NewCipher(d.key)
if err != nil {
return nil, err
}
origData = PKCS5Padding(origData, block.BlockSize())
// origData = ZeroPadding(origData, block.BlockSize())
blockMode := cipher.NewCBCEncrypter(block, d.iv[:block.BlockSize()])
crypted := make([]byte, len(origData))
// 根据CryptBlocks方法的说明,如下方式初始化crypted也可以
// crypted := origData
blockMode.CryptBlocks(crypted, origData)
return crypted, nil
}
// 密钥key长度固定8字节
func (d *DES) Decrypt(crypted []byte) ([]byte, error) {
block, err := des.NewCipher(d.key)
if err != nil {
return nil, err
}
blockMode := cipher.NewCBCDecrypter(block, d.iv[:block.BlockSize()])
origData := make([]byte, len(crypted))
// origData := crypted
blockMode.CryptBlocks(origData, crypted)
origData = PKCS5UnPadding(origData)
// origData = ZeroUnPadding(origData)
return origData, nil
}
type TripleDES struct {
key []byte
//iv的长度必须等于block块的大小
iv []byte
}
func NewTripleDES(key, iv []byte) *TripleDES {
return &TripleDES{key: key, iv: iv}
}
// 3DES加密 24字节
func (d *TripleDES) Encrypt(origData []byte) ([]byte, error) {
block, err := des.NewTripleDESCipher(d.key)
if err != nil {
return nil, err
}
origData = PKCS5Padding(origData, block.BlockSize())
// origData = ZeroPadding(origData, block.BlockSize())
blockMode := cipher.NewCBCEncrypter(block, d.iv[:block.BlockSize()])
crypted := make([]byte, len(origData))
blockMode.CryptBlocks(crypted, origData)
return crypted, nil
}
// 3DES解密
func (d *TripleDES) Decrypt(crypted []byte) ([]byte, error) {
block, err := des.NewTripleDESCipher(d.key)
if err != nil {
return nil, err
}
blockMode := cipher.NewCBCDecrypter(block, d.iv[:block.BlockSize()])
origData := make([]byte, len(crypted))
// origData := crypted
blockMode.CryptBlocks(origData, crypted)
origData = PKCS5UnPadding(origData)
// origData = ZeroUnPadding(origData)
return origData, nil
}
package crypto
import (
"encoding/base64"
"testing"
"github.com/stretchr/testify/assert"
)
var (
contents = [][]byte{
[]byte("1KSBd17H7ZK8iT37aJztFB22XGwsPTdwE4"),
[]byte("1JRNjdEqp4LJ5fqycUBm9ayCKSeeskgMKR"),
[]byte("1NLHPEcbTWWxxU3dGUZBhayjrCHD3psX7k"),
[]byte("1MCftFynyvG2F4ED5mdHYgziDxx6vDrScs"),
}
keys = [][]byte{
[]byte("123456ab"),
[]byte("G2F4ED5m123456abx6vDrScs"),
[]byte("G2F4ED5m123456abx6vDrScsHD3psX7k"),
}
ivs = [][]byte{
[]byte("1KSBd17H7ZK8iT37aJztFB22XGwsPTdwE4"),
[]byte("1JRNjdEqp4LJ5fqycUBm9ayCKSeeskgMKR"),
[]byte("1NLHPEcbTWWxxU3dGUZBhayjrCHD3psX7k"),
[]byte("1MCftFynyvG2F4ED5mdHYgziDxx6vDrScs"),
}
)
//DES 加解密测试
func TestDes(t *testing.T) {
des := NewDES(keys[0], ivs[0])
result, err := des.Encrypt(contents[0])
if err != nil {
t.Error(err)
}
t.Log(base64.StdEncoding.EncodeToString(result))
origData, err := des.Decrypt(result)
if err != nil {
t.Error(err)
}
assert.Equal(t, contents[0], origData)
}
//3DES 加解密测试
func Test3Des(t *testing.T) {
des := NewTripleDES(keys[1], ivs[1])
result, err := des.Encrypt(contents[0])
if err != nil {
t.Error(err)
}
t.Log(base64.StdEncoding.EncodeToString(result))
origData, err := des.Decrypt(result)
if err != nil {
t.Error(err)
}
assert.Equal(t, contents[0], origData)
}
package executor
import (
"github.com/33cn/chain33/types"
storagetypes "github.com/33cn/plugin/plugin/dapp/storage/types"
)
/*
* 实现交易的链上执行接口
* 关键数据上链(statedb)并生成交易回执(log)
*/
func (s *storage) Exec_ContentStorage(payload *storagetypes.ContentOnlyNotaryStorage, tx *types.Transaction, index int) (*types.Receipt, error) {
action := newStorageAction(s, tx, index)
return action.ContentStorage(&storagetypes.Storage{Value: &storagetypes.Storage_ContentStorage{ContentStorage: payload}})
}
func (s *storage) Exec_HashStorage(payload *storagetypes.HashOnlyNotaryStorage, tx *types.Transaction, index int) (*types.Receipt, error) {
action := newStorageAction(s, tx, index)
return action.HashStorage(&storagetypes.Storage{Value: &storagetypes.Storage_HashStorage{HashStorage: payload}})
}
func (s *storage) Exec_LinkStorage(payload *storagetypes.LinkNotaryStorage, tx *types.Transaction, index int) (*types.Receipt, error) {
action := newStorageAction(s, tx, index)
return action.LinkStorage(&storagetypes.Storage{Value: &storagetypes.Storage_LinkStorage{LinkStorage: payload}})
}
func (s *storage) Exec_EncryptStorage(payload *storagetypes.EncryptNotaryStorage, tx *types.Transaction, index int) (*types.Receipt, error) {
action := newStorageAction(s, tx, index)
return action.EncryptStorage(&storagetypes.Storage{Value: &storagetypes.Storage_EncryptStorage{EncryptStorage: payload}})
}
func (s *storage) Exec_EncryptShareStorage(payload *storagetypes.EncryptShareNotaryStorage, tx *types.Transaction, index int) (*types.Receipt, error) {
action := newStorageAction(s, tx, index)
return action.EncryptShareStorage(&storagetypes.Storage{Value: &storagetypes.Storage_EncryptShareStorage{EncryptShareStorage: payload}})
}
package executor
import (
"github.com/33cn/chain33/types"
)
/*
* 实现区块回退时本地执行的数据清除
*/
// ExecDelLocal 回退自动删除,重写基类
func (s *storage) ExecDelLocal(tx *types.Transaction, receipt *types.ReceiptData, index int) (*types.LocalDBSet, error) {
kvs, err := s.DelRollbackKV(tx, tx.Execer)
if err != nil {
return nil, err
}
dbSet := &types.LocalDBSet{}
dbSet.KV = append(dbSet.KV, kvs...)
return dbSet, nil
}
package executor
import (
"github.com/33cn/chain33/types"
storagetypes "github.com/33cn/plugin/plugin/dapp/storage/types"
)
/*
* 实现交易相关数据本地执行,数据不上链
* 非关键数据,本地存储(localDB), 用于辅助查询,效率高
*/
func (s *storage) ExecLocal_ContentStorage(payload *storagetypes.ContentOnlyNotaryStorage, tx *types.Transaction, receiptData *types.ReceiptData, index int) (*types.LocalDBSet, error) {
dbSet := &types.LocalDBSet{}
//implement code
return s.addAutoRollBack(tx, dbSet.KV), nil
}
func (s *storage) ExecLocal_HashStorage(payload *storagetypes.HashOnlyNotaryStorage, tx *types.Transaction, receiptData *types.ReceiptData, index int) (*types.LocalDBSet, error) {
dbSet := &types.LocalDBSet{}
//implement code
return s.addAutoRollBack(tx, dbSet.KV), nil
}
func (s *storage) ExecLocal_LinkStorage(payload *storagetypes.LinkNotaryStorage, tx *types.Transaction, receiptData *types.ReceiptData, index int) (*types.LocalDBSet, error) {
dbSet := &types.LocalDBSet{}
//implement code
return s.addAutoRollBack(tx, dbSet.KV), nil
}
func (s *storage) ExecLocal_EncryptStorage(payload *storagetypes.EncryptNotaryStorage, tx *types.Transaction, receiptData *types.ReceiptData, index int) (*types.LocalDBSet, error) {
dbSet := &types.LocalDBSet{}
//implement code
return s.addAutoRollBack(tx, dbSet.KV), nil
}
func (s *storage) ExecLocal_EncryptShareStorage(payload *storagetypes.EncryptShareNotaryStorage, tx *types.Transaction, receiptData *types.ReceiptData, index int) (*types.LocalDBSet, error) {
dbSet := &types.LocalDBSet{}
//implement code
return s.addAutoRollBack(tx, dbSet.KV), nil
}
//设置自动回滚
func (s *storage) addAutoRollBack(tx *types.Transaction, kv []*types.KeyValue) *types.LocalDBSet {
dbSet := &types.LocalDBSet{}
dbSet.KV = s.AddRollbackKV(tx, tx.Execer, kv)
return dbSet
}
package executor
/*
* 用户合约存取kv数据时,key值前缀需要满足一定规范
* 即key = keyPrefix + userKey
* 需要字段前缀查询时,使用’-‘作为分割符号
*/
var (
//KeyPrefixStateDB state db key必须前缀
KeyPrefixStateDB = "mavl-storage-"
//KeyPrefixLocalDB local db的key必须前缀
KeyPrefixLocalDB = "LODB-storage-"
)
// Key Storage to save key
func Key(txHash string) (key []byte) {
key = append(key, []byte(KeyPrefixStateDB)...)
key = append(key, []byte(txHash)...)
return key
}
package executor
import (
"github.com/33cn/chain33/types"
storagetypes "github.com/33cn/plugin/plugin/dapp/storage/types"
)
//从statedb 读取原始数据
func (s *storage) Query_QueryStorage(in *storagetypes.QueryStorage) (types.Message, error) {
return QueryStorage(s.GetStateDB(), in)
}
//通过状态查询ids
func (s *storage) Query_BatchQueryStorage(in *storagetypes.BatchQueryStorage) (types.Message, error) {
return BatchQueryStorage(s.GetStateDB(), in)
}
package executor
import (
log "github.com/33cn/chain33/common/log/log15"
drivers "github.com/33cn/chain33/system/dapp"
"github.com/33cn/chain33/types"
storagetypes "github.com/33cn/plugin/plugin/dapp/storage/types"
)
/*
* 执行器相关定义
* 重载基类相关接口
*/
var (
//日志
elog = log.New("module", "storage.executor")
)
var driverName = storagetypes.StorageX
// Init register dapp
func Init(name string, cfg *types.Chain33Config, sub []byte) {
drivers.Register(cfg, GetName(), newStorage, cfg.GetDappFork(driverName, "Enable"))
InitExecType()
}
// InitExecType Init Exec Type
func InitExecType() {
ety := types.LoadExecutorType(driverName)
ety.InitFuncList(types.ListMethod(&storage{}))
}
type storage struct {
drivers.DriverBase
}
func newStorage() drivers.Driver {
t := &storage{}
t.SetChild(t)
t.SetExecutorType(types.LoadExecutorType(driverName))
return t
}
// GetName get driver name
func GetName() string {
return newStorage().GetName()
}
func (s *storage) GetDriverName() string {
return driverName
}
// CheckTx 实现自定义检验交易接口,供框架调用
func (s *storage) CheckTx(tx *types.Transaction, index int) error {
// implement code
return nil
}
package executor
import (
"math/rand"
"testing"
"github.com/33cn/chain33/account"
"github.com/33cn/chain33/client"
"github.com/33cn/chain33/common/address"
"github.com/33cn/chain33/types"
"github.com/33cn/chain33/util"
"github.com/33cn/chain33/common"
"github.com/33cn/chain33/common/crypto"
dbm "github.com/33cn/chain33/common/db"
"github.com/33cn/chain33/queue"
des "github.com/33cn/plugin/plugin/dapp/storage/crypto"
oty "github.com/33cn/plugin/plugin/dapp/storage/types"
"github.com/stretchr/testify/assert"
"strings"
)
type execEnv struct {
blockTime int64
blockHeight int64
difficulty uint64
}
var (
PrivKeyA = "0x6da92a632ab7deb67d38c0f6560bcfed28167998f6496db64c258d5e8393a81b" // 1KSBd17H7ZK8iT37aJztFB22XGwsPTdwE4
Nodes = [][]byte{
[]byte("1KSBd17H7ZK8iT37aJztFB22XGwsPTdwE4"),
[]byte("1JRNjdEqp4LJ5fqycUBm9ayCKSeeskgMKR"),
[]byte("1NLHPEcbTWWxxU3dGUZBhayjrCHD3psX7k"),
[]byte("1MCftFynyvG2F4ED5mdHYgziDxx6vDrScs"),
}
contents = [][]byte{
[]byte("1KSBd17H7ZK8iT37aJztFB22XGwsPTdwE4"),
[]byte("1JRNjdEqp4LJ5fqycUBm9ayCKSeeskgMKR"),
[]byte("1NLHPEcbTWWxxU3dGUZBhayjrCHD3psX7k"),
[]byte("1MCftFynyvG2F4ED5mdHYgziDxx6vDrScs"),
}
keys = [][]byte{
[]byte("123456ab"),
[]byte("G2F4ED5m123456abx6vDrScs"),
[]byte("G2F4ED5m123456abx6vDrScsHD3psX7k"),
}
ivs = [][]byte{
[]byte("1KSBd17H7ZK8iT37aJztFB22XGwsPTdwE4"),
[]byte("1JRNjdEqp4LJ5fqycUBm9ayCKSeeskgMKR"),
[]byte("1NLHPEcbTWWxxU3dGUZBhayjrCHD3psX7k"),
[]byte("1MCftFynyvG2F4ED5mdHYgziDxx6vDrScs"),
}
)
var (
r *rand.Rand
)
func init() {
r = rand.New(rand.NewSource(types.Now().UnixNano()))
}
func TestOrace(t *testing.T) {
cfg := types.NewChain33Config(strings.Replace(types.GetDefaultCfgstring(), "Title=\"local\"", "Title=\"chain33\"", 1))
Init(oty.StorageX, cfg, nil)
total := 100 * types.Coin
accountA := types.Account{
Balance: total,
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]),
}
accountD := types.Account{
Balance: total,
Frozen: 0,
Addr: string(Nodes[3]),
}
execAddr := address.ExecAddress(oty.StorageX)
stateDB, _ := dbm.NewGoMemDB("1", "2", 1000)
_, _, kvdb := util.CreateTestDB()
accA, _ := account.NewAccountDB(cfg, "coins", "bty", stateDB)
accA.SaveExecAccount(execAddr, &accountA)
accB, _ := account.NewAccountDB(cfg, "coins", "bty", stateDB)
accB.SaveExecAccount(execAddr, &accountB)
accC, _ := account.NewAccountDB(cfg, "coins", "bty", stateDB)
accC.SaveExecAccount(execAddr, &accountC)
accD, _ := account.NewAccountDB(cfg, "coins", "bty", stateDB)
accD.SaveExecAccount(execAddr, &accountD)
env := execEnv{
10,
cfg.GetDappFork(oty.StorageX, "Enable"),
1539918074,
}
// publish event
ety := types.LoadExecutorType(oty.StorageX)
tx, err := ety.Create("ContentStorage", &oty.ContentOnlyNotaryStorage{Content: contents[0]})
assert.Nil(t, err)
tx, err = types.FormatTx(cfg, oty.StorageX, tx)
assert.Nil(t, err)
tx, err = signTx(tx, PrivKeyA)
assert.Nil(t, err)
t.Log("tx", tx)
exec := newStorage()
q := queue.New("channel")
q.SetConfig(cfg)
api, _ := client.New(q.Client(), nil)
exec.SetAPI(api)
exec.SetStateDB(stateDB)
exec.SetLocalDB(kvdb)
exec.SetEnv(1, env.blockTime, env.difficulty)
receipt, err := exec.Exec(tx, int(1))
if err != nil {
t.Error(err)
}
for _, kv := range receipt.KV {
stateDB.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 {
t.Error(err)
}
for _, kv := range set.KV {
kvdb.Set(kv.Key, kv.Value)
}
txhash := common.ToHex(tx.Hash())
t.Log("txhash:", txhash)
//根据hash查询存储得明文内容
msg, err := exec.Query(oty.FuncNameQueryStorage, types.Encode(&oty.QueryStorage{
TxHash: txhash}))
if err != nil {
t.Error(err)
}
t.Log(msg)
reply := msg.(*oty.Storage)
assert.Equal(t, contents[0], reply.GetContentStorage().Content)
//根据hash批量查询存储数据
msg, err = exec.Query(oty.FuncNameBatchQueryStorage, types.Encode(&oty.BatchQueryStorage{
TxHashs: []string{txhash}}))
if err != nil {
t.Error(err)
}
t.Log(msg)
reply2 := msg.(*oty.BatchReplyStorage)
assert.Equal(t, contents[0], reply2.Storages[0].GetContentStorage().Content)
tx, err = ety.Create("HashStorage", &oty.HashOnlyNotaryStorage{Hash: common.Sha256(contents[0])})
assert.Nil(t, err)
tx, err = types.FormatTx(cfg, oty.StorageX, tx)
assert.Nil(t, err)
tx, err = signTx(tx, PrivKeyA)
assert.Nil(t, err)
t.Log("tx", tx)
exec.SetEnv(env.blockHeight+1, env.blockTime+20, env.difficulty+1)
receipt, err = exec.Exec(tx, int(1))
if err != nil {
t.Error(err)
}
for _, kv := range receipt.KV {
stateDB.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 {
t.Error(err)
}
for _, kv := range set.KV {
kvdb.Set(kv.Key, kv.Value)
}
txhash = common.ToHex(tx.Hash())
t.Log("txhash:", txhash)
//根据hash查询存储得明文内容
msg, err = exec.Query(oty.FuncNameQueryStorage, types.Encode(&oty.QueryStorage{
TxHash: txhash}))
if err != nil {
t.Error(err)
}
t.Log(msg)
reply = msg.(*oty.Storage)
assert.Equal(t, common.Sha256(contents[0]), reply.GetHashStorage().Hash)
//根据hash批量查询存储数据
msg, err = exec.Query(oty.FuncNameBatchQueryStorage, types.Encode(&oty.BatchQueryStorage{
TxHashs: []string{txhash}}))
if err != nil {
t.Error(err)
}
t.Log(msg)
reply2 = msg.(*oty.BatchReplyStorage)
assert.Equal(t, common.Sha256(contents[0]), reply2.Storages[0].GetHashStorage().Hash)
//存储链接地址
tx, err = ety.Create("LinkStorage", &oty.LinkNotaryStorage{Hash: common.Sha256(contents[0]), Link: contents[0]})
assert.Nil(t, err)
tx, err = types.FormatTx(cfg, oty.StorageX, tx)
assert.Nil(t, err)
tx, err = signTx(tx, PrivKeyA)
assert.Nil(t, err)
t.Log("tx", tx)
exec.SetEnv(env.blockHeight+1, env.blockTime+20, env.difficulty+1)
receipt, err = exec.Exec(tx, int(1))
if err != nil {
t.Error(err)
}
for _, kv := range receipt.KV {
stateDB.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 {
t.Error(err)
}
for _, kv := range set.KV {
kvdb.Set(kv.Key, kv.Value)
}
txhash = common.ToHex(tx.Hash())
t.Log("txhash:", txhash)
//根据hash查询存储得明文内容
msg, err = exec.Query(oty.FuncNameQueryStorage, types.Encode(&oty.QueryStorage{
TxHash: txhash}))
if err != nil {
t.Error(err)
}
t.Log(msg)
reply = msg.(*oty.Storage)
assert.Equal(t, common.Sha256(contents[0]), reply.GetLinkStorage().Hash)
//根据hash批量查询存储数据
msg, err = exec.Query(oty.FuncNameBatchQueryStorage, types.Encode(&oty.BatchQueryStorage{
TxHashs: []string{txhash}}))
if err != nil {
t.Error(err)
}
t.Log(msg)
reply2 = msg.(*oty.BatchReplyStorage)
assert.Equal(t, common.Sha256(contents[0]), reply2.Storages[0].GetLinkStorage().Hash)
//加密存储
aes := des.NewAES(keys[2], ivs[0])
crypted, err := aes.Encrypt(contents[0])
if err != nil {
t.Error(err)
}
tx, err = ety.Create("EncryptStorage", &oty.EncryptNotaryStorage{ContentHash: common.Sha256(contents[0]), EncryptContent: crypted, Nonce: ivs[0]})
assert.Nil(t, err)
tx, err = types.FormatTx(cfg, oty.StorageX, tx)
assert.Nil(t, err)
tx, err = signTx(tx, PrivKeyA)
assert.Nil(t, err)
t.Log("tx", tx)
exec.SetEnv(env.blockHeight+1, env.blockTime+20, env.difficulty+1)
receipt, err = exec.Exec(tx, int(1))
if err != nil {
t.Error(err)
}
for _, kv := range receipt.KV {
stateDB.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 {
t.Error(err)
}
for _, kv := range set.KV {
kvdb.Set(kv.Key, kv.Value)
}
txhash = common.ToHex(tx.Hash())
t.Log("txhash:", txhash)
//根据hash查询存储得明文内容
msg, err = exec.Query(oty.FuncNameQueryStorage, types.Encode(&oty.QueryStorage{
TxHash: txhash}))
if err != nil {
t.Error(err)
}
t.Log(msg)
reply = msg.(*oty.Storage)
assert.Equal(t, common.Sha256(contents[0]), reply.GetEncryptStorage().ContentHash)
assert.Equal(t, crypted, reply.GetEncryptStorage().EncryptContent)
assert.Equal(t, ivs[0], reply.GetEncryptStorage().Nonce)
}
func signTx(tx *types.Transaction, hexPrivKey string) (*types.Transaction, error) {
signType := types.SECP256K1
c, err := crypto.New(types.GetSignName(oty.StorageX, 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
}
package executor
import (
"fmt"
"github.com/33cn/chain33/common"
dbm "github.com/33cn/chain33/common/db"
"github.com/33cn/chain33/types"
storagetypes "github.com/33cn/plugin/plugin/dapp/storage/types"
"github.com/gogo/protobuf/proto"
)
type StorageAction struct {
db dbm.KV
txhash []byte
fromaddr string
blocktime int64
height int64
index int
}
func newStorageAction(s *storage, tx *types.Transaction, index int) *StorageAction {
hash := tx.Hash()
fromaddr := tx.From()
return &StorageAction{s.GetStateDB(), hash, fromaddr,
s.GetBlockTime(), s.GetHeight(), index}
}
func (s *StorageAction) GetKVSet(payload proto.Message) (kvset []*types.KeyValue) {
kvset = append(kvset, &types.KeyValue{Key: Key(common.ToHex(s.txhash)), Value: types.Encode(payload)})
return kvset
}
func (s *StorageAction) ContentStorage(payload proto.Message) (*types.Receipt, error) {
//TODO 这里可以加具体得文本内容限制,超过指定大小的数据不容许写到状态数据库中
var logs []*types.ReceiptLog
log := &types.ReceiptLog{Ty: storagetypes.TyContentStorageLog}
logs = append(logs, log)
kv := s.GetKVSet(payload)
receipt := &types.Receipt{Ty: types.ExecOk, KV: kv, Logs: logs}
return receipt, nil
}
func (s *StorageAction) HashStorage(payload proto.Message) (*types.Receipt, error) {
var logs []*types.ReceiptLog
log := &types.ReceiptLog{Ty: storagetypes.TyHashStorageLog}
logs = append(logs, log)
kv := s.GetKVSet(payload)
receipt := &types.Receipt{Ty: types.ExecOk, KV: kv, Logs: logs}
return receipt, nil
}
func (s *StorageAction) LinkStorage(payload proto.Message) (*types.Receipt, error) {
var logs []*types.ReceiptLog
log := &types.ReceiptLog{Ty: storagetypes.TyLinkStorageLog}
logs = append(logs, log)
kv := s.GetKVSet(payload)
receipt := &types.Receipt{Ty: types.ExecOk, KV: kv, Logs: logs}
return receipt, nil
}
func (s *StorageAction) EncryptStorage(payload proto.Message) (*types.Receipt, error) {
var logs []*types.ReceiptLog
log := &types.ReceiptLog{Ty: storagetypes.TyEncryptStorageLog}
logs = append(logs, log)
kv := s.GetKVSet(payload)
receipt := &types.Receipt{Ty: types.ExecOk, KV: kv, Logs: logs}
return receipt, nil
}
func (s *StorageAction) EncryptShareStorage(payload proto.Message) (*types.Receipt, error) {
var logs []*types.ReceiptLog
log := &types.ReceiptLog{Ty: storagetypes.TyEncryptShareStorageLog}
logs = append(logs, log)
kv := s.GetKVSet(payload)
receipt := &types.Receipt{Ty: types.ExecOk, KV: kv, Logs: logs}
return receipt, nil
}
func QueryStorageByTxHash(db dbm.KV, txhash string) (*storagetypes.Storage, error) {
data, err := db.Get(Key(txhash))
if err != nil {
elog.Debug("QueryStorage", "get", err)
return nil, err
}
var storage storagetypes.Storage
//decode
err = types.Decode(data, &storage)
if err != nil {
elog.Debug("QueryStorage", "decode", err)
return nil, err
}
return &storage, nil
}
func QueryStorage(db dbm.KV, in *storagetypes.QueryStorage) (types.Message, error) {
if in.TxHash == "" {
return nil, fmt.Errorf("txhash can't equail nil")
}
return QueryStorageByTxHash(db, in.TxHash)
}
func BatchQueryStorage(db dbm.KV, in *storagetypes.BatchQueryStorage) (types.Message, error) {
if len(in.TxHashs) > 10 {
return nil, fmt.Errorf("The number of batch queries is too large! the maximux is %d,but current num %d", 10, len(in.TxHashs))
}
var storage storagetypes.BatchReplyStorage
for _, txhash := range in.TxHashs {
msg, err := QueryStorageByTxHash(db, txhash)
if err != nil {
return msg, err
}
storage.Storages = append(storage.Storages, msg)
}
return &storage, nil
}
package types
import (
"github.com/33cn/chain33/pluginmgr"
"github.com/33cn/plugin/plugin/dapp/storage/commands"
"github.com/33cn/plugin/plugin/dapp/storage/executor"
"github.com/33cn/plugin/plugin/dapp/storage/rpc"
storagetypes "github.com/33cn/plugin/plugin/dapp/storage/types"
)
/*
* 初始化dapp相关的组件
*/
func init() {
pluginmgr.Register(&pluginmgr.PluginBase{
Name: storagetypes.StorageX,
ExecName: executor.GetName(),
Exec: executor.Init,
Cmd: commands.Cmd,
RPC: rpc.Init,
})
}
all:
./create_protobuf.sh
#!/bin/sh
# proto生成命令,将pb.go文件生成到types/目录下, chain33_path支持引用chain33框架的proto文件
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 Storage {
oneof value {
ContentOnlyNotaryStorage contentStorage = 1;
HashOnlyNotaryStorage hashStorage = 2;
LinkNotaryStorage linkStorage = 3;
EncryptNotaryStorage encryptStorage = 4;
EncryptShareNotaryStorage encryptShareStorage = 5;
}
}
message StorageAction {
oneof value {
ContentOnlyNotaryStorage contentStorage = 1;
HashOnlyNotaryStorage hashStorage = 2;
LinkNotaryStorage linkStorage = 3;
EncryptNotaryStorage encryptStorage = 4;
EncryptShareNotaryStorage encryptShareStorage = 5;
}
int32 ty = 6;
}
// 内容存证模型
message ContentOnlyNotaryStorage {
//长度需要小于512k
bytes content = 1;
}
//哈希存证模型,推荐使用sha256哈希,限制256位得摘要值
message HashOnlyNotaryStorage {
//长度固定为32字节
bytes hash = 1;
}
// 链接存证模型
message LinkNotaryStorage {
//存证内容的链接,可以写入URL,或者其他可用于定位源文件得线索.
bytes link = 1;
//源文件得hash值,推荐使用sha256哈希,限制256位得摘要值
bytes hash = 2;
}
// 隐私存证模型,如果一个文件需要存证,且不公开内容,可以选择将源文件通过对称加密算法加密后上链
message EncryptNotaryStorage {
//存证明文内容的hash值,推荐使用sha256哈希,限制256位得摘要值
bytes contentHash = 1;
//源文件得密文,由加密key及nonce对明文加密得到该值。
bytes encryptContent = 2;
//加密iv,通过AES进行加密时制定随机生成的iv,解密时需要使用该值
bytes nonce = 3;
}
// 隐私存证模型
message EncryptContentOnlyNotaryStorage {
//存证内容的hash值,推荐使用sha256哈希,限制256位得摘要值
// bytes contentHash = 1;
//源文件得密文。
bytes encryptContent = 1;
//加密iv,通过AES进行加密时制定随机生成的iv,解密时需要使用该值
bytes nonce = 2;
}
// 分享隐私存证模型,需要完备的sdk或者相应的密钥库支持
message EncryptShareNotaryStorage {
//存证明文内容的hash值,推荐使用sha256哈希,限制256位得摘要值
bytes contentHash = 1;
//源文件得密文。
bytes encryptContent = 2;
//密钥的kdf推导路径。密钥tree父节点根据该路径可以推导出私钥key
bytes keyName = 3;
//加密key的wrap key。加密key随机生成,对明文进行加密,该key有私密key进行key wrap后公开。
//使用时,通过私密key对wrap key解密得到加密key对密文进行解密。
bytes keyWrap = 4;
//加密iv,通过AES进行加密时制定随机生成的iv,解密时需要使用该值
bytes nonce = 5;
}
service storage {
}
//根据txhash去状态数据库中查询存储内容
message QueryStorage {
string txHash = 1;
}
//批量查询有可能导致数据库崩溃
message BatchQueryStorage {
repeated string txHashs = 1;
}
message BatchReplyStorage {
repeated Storage storages = 1;
}
\ No newline at end of file
package rpc
/*
* 实现json rpc和grpc service接口
* json rpc用Jrpc结构作为接收实例
* grpc使用channelClient结构作为接收实例
*/
package rpc
import (
rpctypes "github.com/33cn/chain33/rpc/types"
storagetypes "github.com/33cn/plugin/plugin/dapp/storage/types"
)
/*
* rpc相关结构定义和初始化
*/
// 实现grpc的service接口
type channelClient struct {
rpctypes.ChannelClient
}
// Jrpc 实现json rpc调用实例
type Jrpc struct {
cli *channelClient
}
// Grpc grpc
type Grpc struct {
*channelClient
}
// Init init rpc
func Init(name string, s rpctypes.RPCServer) {
cli := &channelClient{}
grpc := &Grpc{channelClient: cli}
cli.Init(name, s, &Jrpc{cli: cli}, grpc)
//存在grpc service时注册grpc server,需要生成对应的pb.go文件
storagetypes.RegisterStorageServer(s.GRPC(), grpc)
}
package types
import (
"github.com/33cn/chain33/types"
)
/*
* 交易相关类型定义
* 交易action通常有对应的log结构,用于交易回执日志记录
* 每一种action和log需要用id数值和name名称加以区分
*/
// action类型id和name,这些常量可以自定义修改
const (
TyUnknowAction = iota
TyContentStorageAction
TyHashStorageAction
TyLinkStorageAction
TyEncryptStorageAction
TyEncryptShareStorageAction
NameContentStorageAction = "ContentStorage"
NameHashStorageAction = "HashStorage"
NameLinkStorageAction = "LinkStorage"
NameEncryptStorageAction = "EncryptStorage"
NameEncryptShareStorageAction = "EncryptShareStorage"
FuncNameQueryStorage = "QueryStorage"
FuncNameBatchQueryStorage = "BatchQueryStorage"
)
// log类型id值
const (
TyUnknownLog = iota
TyContentStorageLog
TyHashStorageLog
TyLinkStorageLog
TyEncryptStorageLog
TyEncryptShareStorageLog
)
var (
//StorageX 执行器名称定义
StorageX = "storage"
//定义actionMap
actionMap = map[string]int32{
NameContentStorageAction: TyContentStorageAction,
NameHashStorageAction: TyHashStorageAction,
NameLinkStorageAction: TyLinkStorageAction,
NameEncryptStorageAction: TyEncryptStorageAction,
NameEncryptShareStorageAction: TyEncryptShareStorageAction,
}
//定义log的id和具体log类型及名称,填入具体自定义log类型
logMap = map[int64]*types.LogInfo{
//LogID: {Ty: reflect.TypeOf(LogStruct), Name: LogName},
}
//tlog = log.New("module", "storage.types")
)
// init defines a register function
func init() {
types.AllowUserExec = append(types.AllowUserExec, []byte(StorageX))
//注册合约启用高度
types.RegFork(StorageX, InitFork)
types.RegExec(StorageX, InitExecutor)
}
// InitFork defines register fork
func InitFork(cfg *types.Chain33Config) {
cfg.RegisterDappFork(StorageX, "Enable", 0)
}
// InitExecutor defines register executor
func InitExecutor(cfg *types.Chain33Config) {
types.RegistorExecutor(StorageX, NewType(cfg))
}
type StorageType struct {
types.ExecTypeBase
}
func NewType(cfg *types.Chain33Config) *StorageType {
c := &StorageType{}
c.SetChild(c)
c.SetConfig(cfg)
return c
}
// GetPayload 获取合约action结构
func (s *StorageType) GetPayload() types.Message {
return &StorageAction{}
}
// GeTypeMap 获取合约action的id和name信息
func (s *StorageType) GetTypeMap() map[string]int32 {
return actionMap
}
// GetLogMap 获取合约log相关信息
func (s *StorageType) GetLogMap() map[int64]*types.LogInfo {
return logMap
}
// Code generated by protoc-gen-go. DO NOT EDIT.
// source: storage.proto
/*
Package types is a generated protocol buffer package.
It is generated from these files:
storage.proto
It has these top-level messages:
Storage
StorageAction
ContentOnlyNotaryStorage
HashOnlyNotaryStorage
LinkNotaryStorage
EncryptNotaryStorage
EncryptContentOnlyNotaryStorage
EncryptShareNotaryStorage
QueryStorage
BatchQueryStorage
BatchReplyStorage
*/
package types
import (
fmt "fmt"
proto "github.com/golang/protobuf/proto"
math "math"
context "golang.org/x/net/context"
grpc "google.golang.org/grpc"
)
// 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 Storage struct {
// Types that are valid to be assigned to Value:
// *Storage_ContentStorage
// *Storage_HashStorage
// *Storage_LinkStorage
// *Storage_EncryptStorage
// *Storage_EncryptShareStorage
Value isStorage_Value `protobuf_oneof:"value"`
}
func (m *Storage) Reset() { *m = Storage{} }
func (m *Storage) String() string { return proto.CompactTextString(m) }
func (*Storage) ProtoMessage() {}
func (*Storage) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
type isStorage_Value interface {
isStorage_Value()
}
type Storage_ContentStorage struct {
ContentStorage *ContentOnlyNotaryStorage `protobuf:"bytes,1,opt,name=contentStorage,oneof"`
}
type Storage_HashStorage struct {
HashStorage *HashOnlyNotaryStorage `protobuf:"bytes,2,opt,name=hashStorage,oneof"`
}
type Storage_LinkStorage struct {
LinkStorage *LinkNotaryStorage `protobuf:"bytes,3,opt,name=linkStorage,oneof"`
}
type Storage_EncryptStorage struct {
EncryptStorage *EncryptNotaryStorage `protobuf:"bytes,4,opt,name=encryptStorage,oneof"`
}
type Storage_EncryptShareStorage struct {
EncryptShareStorage *EncryptShareNotaryStorage `protobuf:"bytes,5,opt,name=encryptShareStorage,oneof"`
}
func (*Storage_ContentStorage) isStorage_Value() {}
func (*Storage_HashStorage) isStorage_Value() {}
func (*Storage_LinkStorage) isStorage_Value() {}
func (*Storage_EncryptStorage) isStorage_Value() {}
func (*Storage_EncryptShareStorage) isStorage_Value() {}
func (m *Storage) GetValue() isStorage_Value {
if m != nil {
return m.Value
}
return nil
}
func (m *Storage) GetContentStorage() *ContentOnlyNotaryStorage {
if x, ok := m.GetValue().(*Storage_ContentStorage); ok {
return x.ContentStorage
}
return nil
}
func (m *Storage) GetHashStorage() *HashOnlyNotaryStorage {
if x, ok := m.GetValue().(*Storage_HashStorage); ok {
return x.HashStorage
}
return nil
}
func (m *Storage) GetLinkStorage() *LinkNotaryStorage {
if x, ok := m.GetValue().(*Storage_LinkStorage); ok {
return x.LinkStorage
}
return nil
}
func (m *Storage) GetEncryptStorage() *EncryptNotaryStorage {
if x, ok := m.GetValue().(*Storage_EncryptStorage); ok {
return x.EncryptStorage
}
return nil
}
func (m *Storage) GetEncryptShareStorage() *EncryptShareNotaryStorage {
if x, ok := m.GetValue().(*Storage_EncryptShareStorage); ok {
return x.EncryptShareStorage
}
return nil
}
// XXX_OneofFuncs is for the internal use of the proto package.
func (*Storage) 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 _Storage_OneofMarshaler, _Storage_OneofUnmarshaler, _Storage_OneofSizer, []interface{}{
(*Storage_ContentStorage)(nil),
(*Storage_HashStorage)(nil),
(*Storage_LinkStorage)(nil),
(*Storage_EncryptStorage)(nil),
(*Storage_EncryptShareStorage)(nil),
}
}
func _Storage_OneofMarshaler(msg proto.Message, b *proto.Buffer) error {
m := msg.(*Storage)
// value
switch x := m.Value.(type) {
case *Storage_ContentStorage:
b.EncodeVarint(1<<3 | proto.WireBytes)
if err := b.EncodeMessage(x.ContentStorage); err != nil {
return err
}
case *Storage_HashStorage:
b.EncodeVarint(2<<3 | proto.WireBytes)
if err := b.EncodeMessage(x.HashStorage); err != nil {
return err
}
case *Storage_LinkStorage:
b.EncodeVarint(3<<3 | proto.WireBytes)
if err := b.EncodeMessage(x.LinkStorage); err != nil {
return err
}
case *Storage_EncryptStorage:
b.EncodeVarint(4<<3 | proto.WireBytes)
if err := b.EncodeMessage(x.EncryptStorage); err != nil {
return err
}
case *Storage_EncryptShareStorage:
b.EncodeVarint(5<<3 | proto.WireBytes)
if err := b.EncodeMessage(x.EncryptShareStorage); err != nil {
return err
}
case nil:
default:
return fmt.Errorf("Storage.Value has unexpected type %T", x)
}
return nil
}
func _Storage_OneofUnmarshaler(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error) {
m := msg.(*Storage)
switch tag {
case 1: // value.contentStorage
if wire != proto.WireBytes {
return true, proto.ErrInternalBadWireType
}
msg := new(ContentOnlyNotaryStorage)
err := b.DecodeMessage(msg)
m.Value = &Storage_ContentStorage{msg}
return true, err
case 2: // value.hashStorage
if wire != proto.WireBytes {
return true, proto.ErrInternalBadWireType
}
msg := new(HashOnlyNotaryStorage)
err := b.DecodeMessage(msg)
m.Value = &Storage_HashStorage{msg}
return true, err
case 3: // value.linkStorage
if wire != proto.WireBytes {
return true, proto.ErrInternalBadWireType
}
msg := new(LinkNotaryStorage)
err := b.DecodeMessage(msg)
m.Value = &Storage_LinkStorage{msg}
return true, err
case 4: // value.encryptStorage
if wire != proto.WireBytes {
return true, proto.ErrInternalBadWireType
}
msg := new(EncryptNotaryStorage)
err := b.DecodeMessage(msg)
m.Value = &Storage_EncryptStorage{msg}
return true, err
case 5: // value.encryptShareStorage
if wire != proto.WireBytes {
return true, proto.ErrInternalBadWireType
}
msg := new(EncryptShareNotaryStorage)
err := b.DecodeMessage(msg)
m.Value = &Storage_EncryptShareStorage{msg}
return true, err
default:
return false, nil
}
}
func _Storage_OneofSizer(msg proto.Message) (n int) {
m := msg.(*Storage)
// value
switch x := m.Value.(type) {
case *Storage_ContentStorage:
s := proto.Size(x.ContentStorage)
n += proto.SizeVarint(1<<3 | proto.WireBytes)
n += proto.SizeVarint(uint64(s))
n += s
case *Storage_HashStorage:
s := proto.Size(x.HashStorage)
n += proto.SizeVarint(2<<3 | proto.WireBytes)
n += proto.SizeVarint(uint64(s))
n += s
case *Storage_LinkStorage:
s := proto.Size(x.LinkStorage)
n += proto.SizeVarint(3<<3 | proto.WireBytes)
n += proto.SizeVarint(uint64(s))
n += s
case *Storage_EncryptStorage:
s := proto.Size(x.EncryptStorage)
n += proto.SizeVarint(4<<3 | proto.WireBytes)
n += proto.SizeVarint(uint64(s))
n += s
case *Storage_EncryptShareStorage:
s := proto.Size(x.EncryptShareStorage)
n += proto.SizeVarint(5<<3 | proto.WireBytes)
n += proto.SizeVarint(uint64(s))
n += s
case nil:
default:
panic(fmt.Sprintf("proto: unexpected type %T in oneof", x))
}
return n
}
type StorageAction struct {
// Types that are valid to be assigned to Value:
// *StorageAction_ContentStorage
// *StorageAction_HashStorage
// *StorageAction_LinkStorage
// *StorageAction_EncryptStorage
// *StorageAction_EncryptShareStorage
Value isStorageAction_Value `protobuf_oneof:"value"`
Ty int32 `protobuf:"varint,6,opt,name=ty" json:"ty,omitempty"`
}
func (m *StorageAction) Reset() { *m = StorageAction{} }
func (m *StorageAction) String() string { return proto.CompactTextString(m) }
func (*StorageAction) ProtoMessage() {}
func (*StorageAction) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} }
type isStorageAction_Value interface {
isStorageAction_Value()
}
type StorageAction_ContentStorage struct {
ContentStorage *ContentOnlyNotaryStorage `protobuf:"bytes,1,opt,name=contentStorage,oneof"`
}
type StorageAction_HashStorage struct {
HashStorage *HashOnlyNotaryStorage `protobuf:"bytes,2,opt,name=hashStorage,oneof"`
}
type StorageAction_LinkStorage struct {
LinkStorage *LinkNotaryStorage `protobuf:"bytes,3,opt,name=linkStorage,oneof"`
}
type StorageAction_EncryptStorage struct {
EncryptStorage *EncryptNotaryStorage `protobuf:"bytes,4,opt,name=encryptStorage,oneof"`
}
type StorageAction_EncryptShareStorage struct {
EncryptShareStorage *EncryptShareNotaryStorage `protobuf:"bytes,5,opt,name=encryptShareStorage,oneof"`
}
func (*StorageAction_ContentStorage) isStorageAction_Value() {}
func (*StorageAction_HashStorage) isStorageAction_Value() {}
func (*StorageAction_LinkStorage) isStorageAction_Value() {}
func (*StorageAction_EncryptStorage) isStorageAction_Value() {}
func (*StorageAction_EncryptShareStorage) isStorageAction_Value() {}
func (m *StorageAction) GetValue() isStorageAction_Value {
if m != nil {
return m.Value
}
return nil
}
func (m *StorageAction) GetContentStorage() *ContentOnlyNotaryStorage {
if x, ok := m.GetValue().(*StorageAction_ContentStorage); ok {
return x.ContentStorage
}
return nil
}
func (m *StorageAction) GetHashStorage() *HashOnlyNotaryStorage {
if x, ok := m.GetValue().(*StorageAction_HashStorage); ok {
return x.HashStorage
}
return nil
}
func (m *StorageAction) GetLinkStorage() *LinkNotaryStorage {
if x, ok := m.GetValue().(*StorageAction_LinkStorage); ok {
return x.LinkStorage
}
return nil
}
func (m *StorageAction) GetEncryptStorage() *EncryptNotaryStorage {
if x, ok := m.GetValue().(*StorageAction_EncryptStorage); ok {
return x.EncryptStorage
}
return nil
}
func (m *StorageAction) GetEncryptShareStorage() *EncryptShareNotaryStorage {
if x, ok := m.GetValue().(*StorageAction_EncryptShareStorage); ok {
return x.EncryptShareStorage
}
return nil
}
func (m *StorageAction) GetTy() int32 {
if m != nil {
return m.Ty
}
return 0
}
// XXX_OneofFuncs is for the internal use of the proto package.
func (*StorageAction) 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 _StorageAction_OneofMarshaler, _StorageAction_OneofUnmarshaler, _StorageAction_OneofSizer, []interface{}{
(*StorageAction_ContentStorage)(nil),
(*StorageAction_HashStorage)(nil),
(*StorageAction_LinkStorage)(nil),
(*StorageAction_EncryptStorage)(nil),
(*StorageAction_EncryptShareStorage)(nil),
}
}
func _StorageAction_OneofMarshaler(msg proto.Message, b *proto.Buffer) error {
m := msg.(*StorageAction)
// value
switch x := m.Value.(type) {
case *StorageAction_ContentStorage:
b.EncodeVarint(1<<3 | proto.WireBytes)
if err := b.EncodeMessage(x.ContentStorage); err != nil {
return err
}
case *StorageAction_HashStorage:
b.EncodeVarint(2<<3 | proto.WireBytes)
if err := b.EncodeMessage(x.HashStorage); err != nil {
return err
}
case *StorageAction_LinkStorage:
b.EncodeVarint(3<<3 | proto.WireBytes)
if err := b.EncodeMessage(x.LinkStorage); err != nil {
return err
}
case *StorageAction_EncryptStorage:
b.EncodeVarint(4<<3 | proto.WireBytes)
if err := b.EncodeMessage(x.EncryptStorage); err != nil {
return err
}
case *StorageAction_EncryptShareStorage:
b.EncodeVarint(5<<3 | proto.WireBytes)
if err := b.EncodeMessage(x.EncryptShareStorage); err != nil {
return err
}
case nil:
default:
return fmt.Errorf("StorageAction.Value has unexpected type %T", x)
}
return nil
}
func _StorageAction_OneofUnmarshaler(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error) {
m := msg.(*StorageAction)
switch tag {
case 1: // value.contentStorage
if wire != proto.WireBytes {
return true, proto.ErrInternalBadWireType
}
msg := new(ContentOnlyNotaryStorage)
err := b.DecodeMessage(msg)
m.Value = &StorageAction_ContentStorage{msg}
return true, err
case 2: // value.hashStorage
if wire != proto.WireBytes {
return true, proto.ErrInternalBadWireType
}
msg := new(HashOnlyNotaryStorage)
err := b.DecodeMessage(msg)
m.Value = &StorageAction_HashStorage{msg}
return true, err
case 3: // value.linkStorage
if wire != proto.WireBytes {
return true, proto.ErrInternalBadWireType
}
msg := new(LinkNotaryStorage)
err := b.DecodeMessage(msg)
m.Value = &StorageAction_LinkStorage{msg}
return true, err
case 4: // value.encryptStorage
if wire != proto.WireBytes {
return true, proto.ErrInternalBadWireType
}
msg := new(EncryptNotaryStorage)
err := b.DecodeMessage(msg)
m.Value = &StorageAction_EncryptStorage{msg}
return true, err
case 5: // value.encryptShareStorage
if wire != proto.WireBytes {
return true, proto.ErrInternalBadWireType
}
msg := new(EncryptShareNotaryStorage)
err := b.DecodeMessage(msg)
m.Value = &StorageAction_EncryptShareStorage{msg}
return true, err
default:
return false, nil
}
}
func _StorageAction_OneofSizer(msg proto.Message) (n int) {
m := msg.(*StorageAction)
// value
switch x := m.Value.(type) {
case *StorageAction_ContentStorage:
s := proto.Size(x.ContentStorage)
n += proto.SizeVarint(1<<3 | proto.WireBytes)
n += proto.SizeVarint(uint64(s))
n += s
case *StorageAction_HashStorage:
s := proto.Size(x.HashStorage)
n += proto.SizeVarint(2<<3 | proto.WireBytes)
n += proto.SizeVarint(uint64(s))
n += s
case *StorageAction_LinkStorage:
s := proto.Size(x.LinkStorage)
n += proto.SizeVarint(3<<3 | proto.WireBytes)
n += proto.SizeVarint(uint64(s))
n += s
case *StorageAction_EncryptStorage:
s := proto.Size(x.EncryptStorage)
n += proto.SizeVarint(4<<3 | proto.WireBytes)
n += proto.SizeVarint(uint64(s))
n += s
case *StorageAction_EncryptShareStorage:
s := proto.Size(x.EncryptShareStorage)
n += proto.SizeVarint(5<<3 | proto.WireBytes)
n += proto.SizeVarint(uint64(s))
n += s
case nil:
default:
panic(fmt.Sprintf("proto: unexpected type %T in oneof", x))
}
return n
}
// 内容存证模型
type ContentOnlyNotaryStorage struct {
// 长度需要小于512k
Content []byte `protobuf:"bytes,1,opt,name=content,proto3" json:"content,omitempty"`
}
func (m *ContentOnlyNotaryStorage) Reset() { *m = ContentOnlyNotaryStorage{} }
func (m *ContentOnlyNotaryStorage) String() string { return proto.CompactTextString(m) }
func (*ContentOnlyNotaryStorage) ProtoMessage() {}
func (*ContentOnlyNotaryStorage) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2} }
func (m *ContentOnlyNotaryStorage) GetContent() []byte {
if m != nil {
return m.Content
}
return nil
}
// 哈希存证模型,推荐使用sha256哈希,限制256位得摘要值
type HashOnlyNotaryStorage struct {
// 长度固定为32字节
Hash []byte `protobuf:"bytes,1,opt,name=hash,proto3" json:"hash,omitempty"`
}
func (m *HashOnlyNotaryStorage) Reset() { *m = HashOnlyNotaryStorage{} }
func (m *HashOnlyNotaryStorage) String() string { return proto.CompactTextString(m) }
func (*HashOnlyNotaryStorage) ProtoMessage() {}
func (*HashOnlyNotaryStorage) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{3} }
func (m *HashOnlyNotaryStorage) GetHash() []byte {
if m != nil {
return m.Hash
}
return nil
}
// 链接存证模型
type LinkNotaryStorage struct {
// 存证内容的链接,可以写入URL,或者其他可用于定位源文件得线索.
Link []byte `protobuf:"bytes,1,opt,name=link,proto3" json:"link,omitempty"`
// 源文件得hash值,推荐使用sha256哈希,限制256位得摘要值
Hash []byte `protobuf:"bytes,2,opt,name=hash,proto3" json:"hash,omitempty"`
}
func (m *LinkNotaryStorage) Reset() { *m = LinkNotaryStorage{} }
func (m *LinkNotaryStorage) String() string { return proto.CompactTextString(m) }
func (*LinkNotaryStorage) ProtoMessage() {}
func (*LinkNotaryStorage) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{4} }
func (m *LinkNotaryStorage) GetLink() []byte {
if m != nil {
return m.Link
}
return nil
}
func (m *LinkNotaryStorage) GetHash() []byte {
if m != nil {
return m.Hash
}
return nil
}
// 隐私存证模型,如果一个文件需要存证,且不公开内容,可以选择将源文件通过对称加密算法加密后上链
type EncryptNotaryStorage struct {
// 存证明文内容的hash值,推荐使用sha256哈希,限制256位得摘要值
ContentHash []byte `protobuf:"bytes,1,opt,name=contentHash,proto3" json:"contentHash,omitempty"`
// 源文件得密文,由加密key及nonce对明文加密得到该值。
EncryptContent []byte `protobuf:"bytes,2,opt,name=encryptContent,proto3" json:"encryptContent,omitempty"`
// 加密iv,通过AES进行加密时制定随机生成的iv,解密时需要使用该值
Nonce []byte `protobuf:"bytes,3,opt,name=nonce,proto3" json:"nonce,omitempty"`
}
func (m *EncryptNotaryStorage) Reset() { *m = EncryptNotaryStorage{} }
func (m *EncryptNotaryStorage) String() string { return proto.CompactTextString(m) }
func (*EncryptNotaryStorage) ProtoMessage() {}
func (*EncryptNotaryStorage) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{5} }
func (m *EncryptNotaryStorage) GetContentHash() []byte {
if m != nil {
return m.ContentHash
}
return nil
}
func (m *EncryptNotaryStorage) GetEncryptContent() []byte {
if m != nil {
return m.EncryptContent
}
return nil
}
func (m *EncryptNotaryStorage) GetNonce() []byte {
if m != nil {
return m.Nonce
}
return nil
}
// 隐私存证模型
type EncryptContentOnlyNotaryStorage struct {
// 存证内容的hash值,推荐使用sha256哈希,限制256位得摘要值
// bytes contentHash = 1;
// 源文件得密文。
EncryptContent []byte `protobuf:"bytes,1,opt,name=encryptContent,proto3" json:"encryptContent,omitempty"`
// 加密iv,通过AES进行加密时制定随机生成的iv,解密时需要使用该值
Nonce []byte `protobuf:"bytes,2,opt,name=nonce,proto3" json:"nonce,omitempty"`
}
func (m *EncryptContentOnlyNotaryStorage) Reset() { *m = EncryptContentOnlyNotaryStorage{} }
func (m *EncryptContentOnlyNotaryStorage) String() string { return proto.CompactTextString(m) }
func (*EncryptContentOnlyNotaryStorage) ProtoMessage() {}
func (*EncryptContentOnlyNotaryStorage) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{6} }
func (m *EncryptContentOnlyNotaryStorage) GetEncryptContent() []byte {
if m != nil {
return m.EncryptContent
}
return nil
}
func (m *EncryptContentOnlyNotaryStorage) GetNonce() []byte {
if m != nil {
return m.Nonce
}
return nil
}
// 分享隐私存证模型
type EncryptShareNotaryStorage struct {
// 存证明文内容的hash值,推荐使用sha256哈希,限制256位得摘要值
ContentHash []byte `protobuf:"bytes,1,opt,name=contentHash,proto3" json:"contentHash,omitempty"`
// 源文件得密文。
EncryptContent []byte `protobuf:"bytes,2,opt,name=encryptContent,proto3" json:"encryptContent,omitempty"`
// 密钥的kdf推导路径。密钥tree父节点根据该路径可以推导出私钥key
KeyName []byte `protobuf:"bytes,3,opt,name=keyName,proto3" json:"keyName,omitempty"`
// 加密key的wrap key。加密key随机生成,对明文进行加密,该key有私密key进行key wrap后公开。
// 使用时,通过私密key对wrap key解密得到加密key对密文进行解密。
KeyWrap []byte `protobuf:"bytes,4,opt,name=keyWrap,proto3" json:"keyWrap,omitempty"`
// 加密iv,通过AES进行加密时制定随机生成的iv,解密时需要使用该值
Nonce []byte `protobuf:"bytes,5,opt,name=nonce,proto3" json:"nonce,omitempty"`
}
func (m *EncryptShareNotaryStorage) Reset() { *m = EncryptShareNotaryStorage{} }
func (m *EncryptShareNotaryStorage) String() string { return proto.CompactTextString(m) }
func (*EncryptShareNotaryStorage) ProtoMessage() {}
func (*EncryptShareNotaryStorage) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{7} }
func (m *EncryptShareNotaryStorage) GetContentHash() []byte {
if m != nil {
return m.ContentHash
}
return nil
}
func (m *EncryptShareNotaryStorage) GetEncryptContent() []byte {
if m != nil {
return m.EncryptContent
}
return nil
}
func (m *EncryptShareNotaryStorage) GetKeyName() []byte {
if m != nil {
return m.KeyName
}
return nil
}
func (m *EncryptShareNotaryStorage) GetKeyWrap() []byte {
if m != nil {
return m.KeyWrap
}
return nil
}
func (m *EncryptShareNotaryStorage) GetNonce() []byte {
if m != nil {
return m.Nonce
}
return nil
}
// 根据txhash去状态数据中查询存储内容
type QueryStorage struct {
TxHash string `protobuf:"bytes,1,opt,name=txHash" json:"txHash,omitempty"`
}
func (m *QueryStorage) Reset() { *m = QueryStorage{} }
func (m *QueryStorage) String() string { return proto.CompactTextString(m) }
func (*QueryStorage) ProtoMessage() {}
func (*QueryStorage) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{8} }
func (m *QueryStorage) GetTxHash() string {
if m != nil {
return m.TxHash
}
return ""
}
// 批量查询有可能导致数据库崩溃
type BatchQueryStorage struct {
TxHashs []string `protobuf:"bytes,1,rep,name=txHashs" json:"txHashs,omitempty"`
}
func (m *BatchQueryStorage) Reset() { *m = BatchQueryStorage{} }
func (m *BatchQueryStorage) String() string { return proto.CompactTextString(m) }
func (*BatchQueryStorage) ProtoMessage() {}
func (*BatchQueryStorage) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{9} }
func (m *BatchQueryStorage) GetTxHashs() []string {
if m != nil {
return m.TxHashs
}
return nil
}
type BatchReplyStorage struct {
Storages []*Storage `protobuf:"bytes,1,rep,name=storages" json:"storages,omitempty"`
}
func (m *BatchReplyStorage) Reset() { *m = BatchReplyStorage{} }
func (m *BatchReplyStorage) String() string { return proto.CompactTextString(m) }
func (*BatchReplyStorage) ProtoMessage() {}
func (*BatchReplyStorage) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{10} }
func (m *BatchReplyStorage) GetStorages() []*Storage {
if m != nil {
return m.Storages
}
return nil
}
func init() {
proto.RegisterType((*Storage)(nil), "types.Storage")
proto.RegisterType((*StorageAction)(nil), "types.StorageAction")
proto.RegisterType((*ContentOnlyNotaryStorage)(nil), "types.ContentOnlyNotaryStorage")
proto.RegisterType((*HashOnlyNotaryStorage)(nil), "types.HashOnlyNotaryStorage")
proto.RegisterType((*LinkNotaryStorage)(nil), "types.LinkNotaryStorage")
proto.RegisterType((*EncryptNotaryStorage)(nil), "types.EncryptNotaryStorage")
proto.RegisterType((*EncryptContentOnlyNotaryStorage)(nil), "types.EncryptContentOnlyNotaryStorage")
proto.RegisterType((*EncryptShareNotaryStorage)(nil), "types.EncryptShareNotaryStorage")
proto.RegisterType((*QueryStorage)(nil), "types.QueryStorage")
proto.RegisterType((*BatchQueryStorage)(nil), "types.BatchQueryStorage")
proto.RegisterType((*BatchReplyStorage)(nil), "types.BatchReplyStorage")
}
// Reference imports to suppress errors if they are not otherwise used.
var _ context.Context
var _ grpc.ClientConn
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
const _ = grpc.SupportPackageIsVersion4
// Client API for Storage service
type StorageClient interface {
}
type storageClient struct {
cc *grpc.ClientConn
}
func NewStorageClient(cc *grpc.ClientConn) StorageClient {
return &storageClient{cc}
}
// Server API for Storage service
type StorageServer interface {
}
func RegisterStorageServer(s *grpc.Server, srv StorageServer) {
s.RegisterService(&_Storage_serviceDesc, srv)
}
var _Storage_serviceDesc = grpc.ServiceDesc{
ServiceName: "types.storage",
HandlerType: (*StorageServer)(nil),
Methods: []grpc.MethodDesc{},
Streams: []grpc.StreamDesc{},
Metadata: "storage.proto",
}
func init() { proto.RegisterFile("storage.proto", fileDescriptor0) }
var fileDescriptor0 = []byte{
// 462 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x94, 0xcf, 0x8b, 0xd3, 0x40,
0x14, 0xc7, 0x4d, 0xba, 0x69, 0xec, 0x4b, 0xb7, 0xb0, 0xe3, 0x2a, 0x23, 0x0a, 0x1b, 0x72, 0x58,
0x8a, 0x62, 0x0f, 0xd5, 0x9b, 0x82, 0xba, 0x52, 0xa8, 0x20, 0x2b, 0x8e, 0x82, 0x47, 0x19, 0xc3,
0x60, 0x4a, 0xeb, 0x24, 0x24, 0xb3, 0x8b, 0xf9, 0x2f, 0xfc, 0x4f, 0xfc, 0xff, 0x3c, 0x49, 0x66,
0xde, 0xe4, 0x47, 0x93, 0x7a, 0x12, 0x4f, 0x7b, 0x9b, 0xf7, 0xde, 0xf7, 0x7d, 0xde, 0xaf, 0x10,
0x38, 0x2e, 0x54, 0x9a, 0xf3, 0x6f, 0x62, 0x91, 0xe5, 0xa9, 0x4a, 0x89, 0xa7, 0xca, 0x4c, 0x14,
0xd1, 0x6f, 0x17, 0xfc, 0x8f, 0x26, 0x40, 0xde, 0xc2, 0x2c, 0x4e, 0xa5, 0x12, 0x52, 0xa1, 0x87,
0x3a, 0xa1, 0x33, 0x0f, 0x96, 0x67, 0x0b, 0xad, 0x5d, 0xbc, 0x31, 0xc1, 0xf7, 0x72, 0x57, 0x5e,
0xa6, 0x8a, 0xe7, 0x25, 0xca, 0xd6, 0xb7, 0xd8, 0x5e, 0x22, 0x79, 0x05, 0x41, 0xc2, 0x8b, 0xc4,
0x72, 0x5c, 0xcd, 0x79, 0x88, 0x9c, 0x35, 0x2f, 0x92, 0x21, 0x48, 0x3b, 0x85, 0xbc, 0x80, 0x60,
0xb7, 0x91, 0x5b, 0x4b, 0x18, 0x69, 0x02, 0x45, 0xc2, 0xbb, 0x8d, 0xdc, 0xf6, 0xb2, 0x5b, 0x72,
0xb2, 0x82, 0x99, 0x90, 0x71, 0x5e, 0x66, 0xf5, 0x28, 0x47, 0x1a, 0xf0, 0x00, 0x01, 0x2b, 0x13,
0xec, 0x8d, 0xd1, 0x4d, 0x22, 0x9f, 0xe0, 0x8e, 0xf5, 0x24, 0x3c, 0x17, 0x96, 0xe5, 0x69, 0x56,
0xd8, 0x65, 0x69, 0xc5, 0x3e, 0x70, 0x28, 0xfd, 0xc2, 0x07, 0xef, 0x9a, 0xef, 0xae, 0x44, 0xf4,
0x73, 0x04, 0xc7, 0xe8, 0x7c, 0x1d, 0xab, 0x4d, 0x2a, 0x6f, 0x4e, 0xf0, 0x7f, 0x4e, 0x40, 0x66,
0xe0, 0xaa, 0x92, 0x8e, 0x43, 0x67, 0xee, 0x31, 0x57, 0x95, 0xcd, 0x49, 0x9e, 0x01, 0x3d, 0xb4,
0x63, 0x42, 0xc1, 0xc7, 0x1d, 0xeb, 0xab, 0x4c, 0x99, 0x35, 0xa3, 0xc7, 0x70, 0x77, 0x70, 0xa3,
0x84, 0xc0, 0x51, 0xb5, 0x51, 0xd4, 0xeb, 0x77, 0xf4, 0x1c, 0x4e, 0x7a, 0xcb, 0xab, 0x84, 0xd5,
0xf2, 0xac, 0xb0, 0x7a, 0xd7, 0xc9, 0x6e, 0x2b, 0xf9, 0x1a, 0x4e, 0x87, 0x16, 0x47, 0x42, 0x08,
0xb0, 0x99, 0x75, 0x53, 0xaf, 0xed, 0x22, 0xe7, 0xf5, 0x3d, 0x70, 0x40, 0xe4, 0xee, 0x79, 0xc9,
0x29, 0x78, 0x32, 0x95, 0xb1, 0xb9, 0xf7, 0x94, 0x19, 0x23, 0xfa, 0x02, 0x67, 0xab, 0x8e, 0xae,
0x3f, 0x6b, 0xbf, 0x80, 0xf3, 0xf7, 0x02, 0x6e, 0xbb, 0xc0, 0x2f, 0x07, 0xee, 0x1f, 0x3c, 0xe3,
0x3f, 0x1c, 0x8f, 0x82, 0xbf, 0x15, 0xe5, 0x25, 0xff, 0x6e, 0x07, 0xb4, 0x26, 0x46, 0x3e, 0xe7,
0x3c, 0xd3, 0x5f, 0xaa, 0x89, 0x54, 0x66, 0xd3, 0xb1, 0xd7, 0xee, 0xf8, 0x1c, 0xa6, 0x1f, 0xae,
0x44, 0xd3, 0xe3, 0x3d, 0x18, 0xab, 0x1f, 0x75, 0x7b, 0x13, 0x86, 0x56, 0xf4, 0x04, 0x4e, 0x2e,
0xb8, 0x8a, 0x93, 0x8e, 0x98, 0x82, 0x6f, 0xc2, 0x05, 0x75, 0xc2, 0xd1, 0x7c, 0xc2, 0xac, 0x19,
0xbd, 0x44, 0x39, 0x13, 0xd9, 0xae, 0x96, 0x3f, 0x82, 0xdb, 0xf8, 0xfb, 0x36, 0xfa, 0x60, 0x39,
0xc3, 0x4f, 0x1f, 0x15, 0xac, 0x8e, 0x2f, 0x27, 0xe0, 0xe3, 0xfb, 0xeb, 0x58, 0xff, 0xeb, 0x9f,
0xfe, 0x09, 0x00, 0x00, 0xff, 0xff, 0x93, 0x02, 0x76, 0xfb, 0xfc, 0x05, 0x00, 0x00,
}
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