Commit 1a1f36c2 authored by liuyuhang's avatar liuyuhang

Merge branch 'master' into kvmvccmavl_exec

parents 143311fe 8bf90244
......@@ -155,7 +155,7 @@ out:
case rsp := <-consensusCh:
consensHeight := rsp.Height
plog.Info("para consensus rcv", "notify", notification, "sending", len(sendingMsgs),
"consensHeigt", rsp.Height, "consensBlockHash", common.ToHex(rsp.BlockHash), "sync", isSync)
"consensHeigt", rsp.Height, "finished", finishHeight, "sync", isSync, "consensBlockHash", common.ToHex(rsp.BlockHash))
if notification == nil || isRollback {
continue
......@@ -166,6 +166,11 @@ out:
isSync = true
}
// 共识高度追赶上完成高度之后再发,不然分叉节点继续发浪费手续费
if finishHeight > consensHeight {
isSync = false
}
//未共识过的小于当前共识高度的区块,可以不参与共识, 如果是新节点,一直等到同步的区块达到了共识高度,才设置同步参与共识
//在某些特殊场景下,比如平行链连接的主链节点分叉后又恢复,主链的共识高度低于分叉高度时候,主链上形成共识空洞,需要从共识高度重新发送而不是分叉高度
//共识高度和分叉高度不一致其中一个原因是共识交易组里面某个高度分叉了,分叉的主链节点执行成功,而其他主链节点执行失败,共识高度停留在交易组最小高度-1
......@@ -186,6 +191,7 @@ out:
finishHeight = consensHeight
sendingMsgs = nil
client.currentTx = nil
isSync = true
}
case key, ok := <-priKeyCh:
......
......@@ -272,7 +272,4 @@ func TestGetConsensusStatus(t *testing.T) {
assert.Nil(t, err)
assert.Equal(t, int64(1), ret.Height)
mainParaSelfConsensusForkHeight = 1
}
......@@ -89,7 +89,7 @@ targetTimespan = 2304
targetTimePerBlock = 16
[consensus.sub.para]
#主链节点的grpc服务器ip,当前可以支持多ip负载均衡,如“101.37.227.226:8802,39.97.20.242:8802,47.107.15.126:8802,jiedian2.33.cn
#主链节点的grpc服务器ip,当前可以支持多ip负载均衡,如“101.37.227.226:8802,39.97.20.242:8802,47.107.15.126:8802,jiedian2.bityuan.com,cloud.bityuan.com
ParaRemoteGrpcClient="localhost:8802"
#主链指定高度的区块开始同步
startHeight=345850
......
......@@ -108,6 +108,11 @@ function para_transfer() {
echo "txhash=$txhash"
query_tx "${PARA_CLI}" "${txhash}"
echo "=========== # para chain takeover node group ============="
txhash=$(${PARA_CLI} send para node -o takeover -k 0x6da92a632ab7deb67d38c0f6560bcfed28167998f6496db64c258d5e8393a81b)
echo "tx=$txhash"
query_tx "${PARA_CLI}" "${txhash}"
}
function para_transfer2account() {
......@@ -344,8 +349,78 @@ function para_cross_transfer_withdraw_for_token() {
done
}
function para_nodemanage_test() {
echo "=========== # para chain new node join ============="
hash=$(${PARA_CLI} send para node -o join -a 14KEKbYtKKQm4wMthSK9J4La4nAiidGozt -k CC38546E9E659D15E6B4893F0AB32A06D103931A8230B0BDE71459D2B27D6944)
echo "${hash}"
query_tx "${PARA_CLI}" "${hash}"
status=$(${PARA_CLI} para node_list -t user.p.para. -s 1 | jq -r ".addrs[0].applyAddr")
if [ "${status}" != "14KEKbYtKKQm4wMthSK9J4La4nAiidGozt" ]; then
echo "wrong join status"
${PARA_CLI} para node_list -t user.p.para. -s 1
exit 1
fi
echo "=========== # para chain node vote ============="
${PARA_CLI} send para node -o vote -a 14KEKbYtKKQm4wMthSK9J4La4nAiidGozt -v yes -k 0x6da92a632ab7deb67d38c0f6560bcfed28167998f6496db64c258d5e8393a81b
${PARA_CLI} send para node -o vote -a 14KEKbYtKKQm4wMthSK9J4La4nAiidGozt -v yes -k 0x19c069234f9d3e61135fefbeb7791b149cdf6af536f26bebb310d4cd22c3fee4
hash=$(${PARA_CLI} send para node -o vote -a 14KEKbYtKKQm4wMthSK9J4La4nAiidGozt -v yes -k 0x7a80a1f75d7360c6123c32a78ecf978c1ac55636f87892df38d8b85a9aeff115)
echo "${hash}"
query_tx "${PARA_CLI}" "${hash}"
status=$(${PARA_CLI} para node_status -t user.p.para. -a 14KEKbYtKKQm4wMthSK9J4La4nAiidGozt | jq -r ".status")
if [ "${status}" != "2" ]; then
echo "wrong vote status"
${PARA_CLI} para node_status -t user.p.para. -a 14KEKbYtKKQm4wMthSK9J4La4nAiidGozt
exit 1
fi
node=$(${PARA_CLI} para node_group -t user.p.para. | jq -r '.value|contains("14K")')
if [ "${node}" != "true" ]; then
echo "wrong node group addr"
${PARA_CLI} para node_group -t user.p.para.
exit 1
fi
echo "=========== # para chain node quit ============="
hash=$(${PARA_CLI} send para node -o quit -a 14KEKbYtKKQm4wMthSK9J4La4nAiidGozt -k CC38546E9E659D15E6B4893F0AB32A06D103931A8230B0BDE71459D2B27D6944)
echo "${hash}"
query_tx "${PARA_CLI}" "${hash}"
status=$(${PARA_CLI} para node_list -t user.p.para. -s 3 | jq -r ".addrs[0].applyAddr")
if [ "${status}" != "14KEKbYtKKQm4wMthSK9J4La4nAiidGozt" ]; then
echo "wrong join status"
${PARA_CLI} para node_list -t user.p.para. -s 3
exit 1
fi
echo "=========== # para chain node vote quit ============="
${PARA_CLI} send para node -o vote -a 14KEKbYtKKQm4wMthSK9J4La4nAiidGozt -v yes -k 0x6da92a632ab7deb67d38c0f6560bcfed28167998f6496db64c258d5e8393a81b
${PARA_CLI} send para node -o vote -a 14KEKbYtKKQm4wMthSK9J4La4nAiidGozt -v yes -k 0x19c069234f9d3e61135fefbeb7791b149cdf6af536f26bebb310d4cd22c3fee4
hash=$(${PARA_CLI} send para node -o vote -a 14KEKbYtKKQm4wMthSK9J4La4nAiidGozt -v yes -k 0x7a80a1f75d7360c6123c32a78ecf978c1ac55636f87892df38d8b85a9aeff115)
echo "${hash}"
query_tx "${PARA_CLI}" "${hash}"
status=$(${PARA_CLI} para node_status -t user.p.para. -a 14KEKbYtKKQm4wMthSK9J4La4nAiidGozt | jq -r ".status")
if [ "${status}" != "4" ]; then
echo "wrong vote status"
${PARA_CLI} para node_status -t user.p.para. -a 14KEKbYtKKQm4wMthSK9J4La4nAiidGozt
exit 1
fi
node=$(${PARA_CLI} para node_group -t user.p.para. | jq -r '.value|contains("14K")')
if [ "${node}" == "true" ]; then
echo "wrong node group addr"
${PARA_CLI} para node_group -t user.p.para.
exit 1
fi
}
function para_test() {
echo "=========== # para chain test ============="
para_nodemanage_test
token_create "${PARA_CLI}"
token_transfer "${PARA_CLI}"
para_cross_transfer_withdraw
......
......@@ -12,6 +12,7 @@ import (
"strings"
"github.com/33cn/chain33/rpc/jsonclient"
rpctypes "github.com/33cn/chain33/rpc/types"
"github.com/33cn/chain33/system/dapp/commands"
"github.com/33cn/chain33/types"
pt "github.com/33cn/plugin/plugin/dapp/paracross/types"
......@@ -31,6 +32,12 @@ func ParcCmd() *cobra.Command {
CreateRawTransferCmd(),
CreateRawWithdrawCmd(),
CreateRawTransferToExecCmd(),
CreateRawNodeManageCmd(),
GetParaInfoCmd(),
GetParaListCmd(),
GetNodeGroupCmd(),
GetNodeInfoCmd(),
GetNodeListCmd(),
IsSyncCmd(),
GetHeightCmd(),
GetBlockInfoCmd(),
......@@ -229,6 +236,55 @@ func createWithdraw(cmd *cobra.Command, args []string) {
commands.CreateAssetWithdraw(cmd, args, pt.ParaX)
}
//CreateRawNodeManageCmd create super node mange tx
func CreateRawNodeManageCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "node",
Short: "Create a super node manage cmd",
Run: createNodeTx,
}
addNodeManageFlags(cmd)
return cmd
}
func addNodeManageFlags(cmd *cobra.Command) {
cmd.Flags().StringP("operation", "o", "", "operation:join,quit,vote,takeover")
cmd.MarkFlagRequired("operation")
cmd.Flags().StringP("addr", "a", "", "operating target addr")
cmd.Flags().StringP("value", "v", "", "vote value: yes,no")
}
func createNodeTx(cmd *cobra.Command, args []string) {
op, _ := cmd.Flags().GetString("operation")
opAddr, _ := cmd.Flags().GetString("addr")
val, _ := cmd.Flags().GetString("value")
if op != "vote" && op != "quit" && op != "join" && op != "takeover" {
fmt.Println("operation should be one of join,quit,vote,takeover")
return
}
if (op == "vote" || op == "join" || op == "quit") && opAddr == "" {
fmt.Println("addr parameter should not be null")
return
}
if op == "vote" && (val != "yes" && val != "no") {
fmt.Println("vote operation value parameter require yes or no value")
return
}
payload := &pt.ParaNodeAddrConfig{Op: op, Value: val, Addr: opAddr}
params := &rpctypes.CreateTxIn{
Execer: types.ExecName(pt.ParaX),
ActionName: "NodeConfig",
Payload: types.MustPBToJSON(payload),
}
rpcLaddr, _ := cmd.Flags().GetString("rpc_laddr")
ctx := jsonclient.NewRPCCtx(rpcLaddr, "Chain33.CreateTransaction", params, nil)
ctx.RunWithoutMarshal()
}
// IsSyncCmd query parachain is sync
func IsSyncCmd() *cobra.Command {
cmd := &cobra.Command{
......@@ -303,3 +359,149 @@ func blockInfo(cmd *cobra.Command, args []string) {
ctx.Run()
}
// GetParaInfoCmd get para chain status by height
func GetParaInfoCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "para_status",
Short: "Get para chain current status",
Run: paraInfo,
}
addParaBodyCmdFlags(cmd)
return cmd
}
func addParaBodyCmdFlags(cmd *cobra.Command) {
cmd.Flags().StringP("title", "t", "", "parallel chain's title")
cmd.MarkFlagRequired("title")
cmd.Flags().Int64P("height", "g", 0, "height to para chain")
cmd.MarkFlagRequired("height")
}
func paraInfo(cmd *cobra.Command, args []string) {
rpcLaddr, _ := cmd.Flags().GetString("rpc_laddr")
title, _ := cmd.Flags().GetString("title")
height, _ := cmd.Flags().GetInt64("height")
params := pt.ReqParacrossTitleHeight{
Title: title,
Height: height,
}
var res pt.RespParacrossDone
ctx := jsonclient.NewRPCCtx(rpcLaddr, "paracross.GetTitleHeight", params, &res)
ctx.Run()
}
// GetParaListCmd get para chain info list
func GetParaListCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "para_list",
Short: "Get para chain info list by titles",
Run: paraList,
}
return cmd
}
func paraList(cmd *cobra.Command, args []string) {
rpcLaddr, _ := cmd.Flags().GetString("rpc_laddr")
var res pt.RespParacrossTitles
ctx := jsonclient.NewRPCCtx(rpcLaddr, "paracross.ListTitles", types.ReqNil{}, &res)
ctx.Run()
}
// GetNodeInfoCmd get node current status
func GetNodeInfoCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "node_status",
Short: "Get node current vote status",
Run: nodeInfo,
}
addNodeBodyCmdFlags(cmd)
return cmd
}
func addNodeBodyCmdFlags(cmd *cobra.Command) {
cmd.Flags().StringP("title", "t", "", "parallel chain's title")
cmd.MarkFlagRequired("title")
cmd.Flags().StringP("addr", "a", "", "addr apply for super user")
cmd.MarkFlagRequired("addr")
}
func nodeInfo(cmd *cobra.Command, args []string) {
rpcLaddr, _ := cmd.Flags().GetString("rpc_laddr")
title, _ := cmd.Flags().GetString("title")
addr, _ := cmd.Flags().GetString("addr")
params := pt.ReqParacrossNodeInfo{
Title: title,
Addr: addr,
}
var res pt.ParaNodeAddrStatus
ctx := jsonclient.NewRPCCtx(rpcLaddr, "paracross.GetNodeStatus", params, &res)
ctx.Run()
}
// GetNodeListCmd get node list by status
func GetNodeListCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "node_list",
Short: "Get node info list by status",
Run: nodeList,
}
addNodeListCmdFlags(cmd)
return cmd
}
func addNodeListCmdFlags(cmd *cobra.Command) {
cmd.Flags().StringP("title", "t", "", "parallel chain's title")
cmd.MarkFlagRequired("title")
cmd.Flags().Int32P("status", "s", 0, "status:1:adding,2:added,3:quiting,4:quited")
cmd.MarkFlagRequired("status")
}
func nodeList(cmd *cobra.Command, args []string) {
rpcLaddr, _ := cmd.Flags().GetString("rpc_laddr")
title, _ := cmd.Flags().GetString("title")
status, _ := cmd.Flags().GetInt32("status")
params := pt.ReqParacrossNodeInfo{
Title: title,
Status: status,
}
var res pt.RespParacrossNodeAddrs
ctx := jsonclient.NewRPCCtx(rpcLaddr, "paracross.ListNodeStatus", params, &res)
ctx.Run()
}
// GetNodeGroupCmd get node group addr
func GetNodeGroupCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "node_group",
Short: "Get super node group by title",
Run: nodeGroup,
}
addNodeGroupCmdFlags(cmd)
return cmd
}
func addNodeGroupCmdFlags(cmd *cobra.Command) {
cmd.Flags().StringP("title", "t", "", "parallel chain's title")
cmd.MarkFlagRequired("title")
}
func nodeGroup(cmd *cobra.Command, args []string) {
rpcLaddr, _ := cmd.Flags().GetString("rpc_laddr")
title, _ := cmd.Flags().GetString("title")
var res types.ReplyConfig
ctx := jsonclient.NewRPCCtx(rpcLaddr, "paracross.GetNodeGroup", types.ReqString{Data: title}, &res)
ctx.Run()
}
......@@ -39,33 +39,36 @@ func newAction(t *Paracross, tx *types.Transaction) *action {
t.GetBlockTime(), t.GetHeight(), dapp.ExecAddress(string(tx.Execer)), t.GetAPI(), tx, t}
}
func getNodes(db dbm.KV, title string) (map[string]struct{}, error) {
key := calcConfigNodesKey(title)
func getNodes(db dbm.KV, key []byte) (map[string]struct{}, []string, error) {
item, err := db.Get(key)
if err != nil {
clog.Info("getNodes", "get db key", string(key), "failed", err)
if isNotFound(err) {
err = pt.ErrTitleNotExist
}
return nil, errors.Wrapf(err, "db get key:%s", string(key))
return nil, nil, errors.Wrapf(err, "db get key:%s", string(key))
}
var config types.ConfigItem
err = types.Decode(item, &config)
if err != nil {
return nil, errors.Wrap(err, "decode config")
return nil, nil, errors.Wrap(err, "decode config")
}
value := config.GetArr()
if value == nil {
// 在配置地址后,发现配置错了, 删除会出现这种情况
return map[string]struct{}{}, nil
return map[string]struct{}{}, nil, nil
}
uniqNode := make(map[string]struct{})
var nodesArray []string
nodesMap := make(map[string]struct{})
for _, v := range value.Value {
uniqNode[v] = struct{}{}
if _, exist := nodesMap[v]; !exist {
nodesMap[v] = struct{}{}
nodesArray = append(nodesArray, v)
}
}
return uniqNode, nil
return nodesMap, nodesArray, nil
}
func validTitle(title string) bool {
......@@ -211,6 +214,32 @@ func hasCommited(addrs []string, addr string) (bool, int) {
return false, 0
}
func (a *action) getNodesGroup(title string) (map[string]struct{}, error) {
if !types.IsDappFork(a.exec.GetMainHeight(), pt.ParaX, pt.ForkCommitTx) {
key := calcManageConfigNodesKey(title)
nodes, _, err := getNodes(a.db, key)
if err != nil {
return nil, errors.Wrapf(err, "getNodes for title:%s", title)
}
return nodes, nil
}
key := calcParaNodeGroupKey(title)
nodes, _, err := getNodes(a.db, key)
if err != nil {
if errors.Cause(err) != pt.ErrTitleNotExist {
return nil, errors.Wrapf(err, "getNodes para for title:%s", title)
}
key = calcManageConfigNodesKey(title)
nodes, _, err = getNodes(a.db, key)
if err != nil {
return nil, errors.Wrapf(err, "getNodes manager for title:%s", title)
}
}
return nodes, nil
}
func (a *action) Commit(commit *pt.ParacrossCommitAction) (*types.Receipt, error) {
err := checkCommitInfo(commit)
if err != nil {
......@@ -221,9 +250,9 @@ func (a *action) Commit(commit *pt.ParacrossCommitAction) (*types.Receipt, error
return nil, pt.ErrInvalidTitle
}
nodes, err := getNodes(a.db, commit.Status.Title)
nodes, err := a.getNodesGroup(commit.Status.Title)
if err != nil {
return nil, errors.Wrapf(err, "getNodes for title:%s", commit.Status.Title)
return nil, err
}
if !validNode(a.fromaddr, nodes) {
......@@ -295,7 +324,12 @@ func (a *action) Commit(commit *pt.ParacrossCommitAction) (*types.Receipt, error
}
receipt = makeCommitReceipt(a.fromaddr, commit, nil, stat)
} else {
copyStat := *stat
var copyStat pt.ParacrossHeightStatus
err = deepCopy(&copyStat, stat)
if err != nil {
clog.Error("paracross.Commit deep copy fail", "copy", copyStat, "stat", stat)
return nil, err
}
// 如有分叉, 同一个节点可能再次提交commit交易
found, index := hasCommited(stat.Details.Addrs, a.fromaddr)
if found {
......@@ -327,25 +361,6 @@ func (a *action) Commit(commit *pt.ParacrossCommitAction) (*types.Receipt, error
}
clog.Info("paracross.Commit commit ----pass", "most", most, "mostHash", hex.EncodeToString([]byte(mostHash)))
// parallel chain get self blockhash and compare with commit done result, if not match, just log and return
if types.IsPara() {
saveTitleHeight(a.db, calcTitleHeightKey(commit.Status.Title, commit.Status.Height), stat)
blockHash, err := getBlockHash(a.api, stat.Height)
if err != nil {
clog.Error("paracross.Commit para getBlockHash local", "err", err.Error(), "commitheight", commit.Status.Height,
"commitHash", hex.EncodeToString(commit.Status.BlockHash), "mainHash", hex.EncodeToString(commit.Status.MainBlockHash),
"mainHeight", commit.Status.MainBlockHeight)
return receipt, nil
}
if !bytes.Equal(blockHash.Hash, []byte(mostHash)) {
clog.Error("paracross.Commit para blockHash not match", "selfBlockHash", hex.EncodeToString(blockHash.Hash),
"mostHash", hex.EncodeToString([]byte(mostHash)), "commitHeight", commit.Status.Height,
"commitMainHash", hex.EncodeToString(commit.Status.MainBlockHash), "commitMainHeight", commit.Status.MainBlockHeight)
return receipt, nil
}
}
stat.Status = pt.ParacrossStatusCommitDone
receiptDone := makeDoneReceipt(a.fromaddr, commit, stat, int32(most), int32(commitCount), int32(len(nodes)))
receipt.KV = append(receipt.KV, receiptDone.KV...)
......@@ -357,12 +372,6 @@ func (a *action) Commit(commit *pt.ParacrossCommitAction) (*types.Receipt, error
titleStatus.BlockHash = commit.Status.BlockHash
saveTitle(a.db, calcTitleKey(commit.Status.Title), titleStatus)
if types.IsDappFork(a.exec.GetMainHeight(), pt.ParaX, pt.ForkCommitTx) {
key := calcTitleHashKey(commit.Status.Title, hex.EncodeToString(commit.Status.MainBlockHash))
saveTitle(a.db, key, titleStatus)
receipt.KV = append(receipt.KV, &types.KeyValue{Key: key, Value: types.Encode(titleStatus)})
}
clog.Info("paracross.Commit commit done", "height", commit.Status.Height,
"cross tx count", len(commit.Status.CrossTxHashs), "statusBlockHash", hex.EncodeToString(titleStatus.BlockHash))
......
......@@ -65,7 +65,7 @@ func (suite *AssetTransferTestSuite) SetupTest() {
MainBlockHash10 = blockDetail.Block.Hash()
// setup title nodes : len = 1
nodeConfigKey := calcConfigNodesKey(Title)
nodeConfigKey := calcManageConfigNodesKey(Title)
nodeValue := makeNodeInfo(Title, Title, 1)
suite.stateDB.Set(nodeConfigKey, types.Encode(nodeValue))
value, err := suite.stateDB.Get(nodeConfigKey)
......
......@@ -60,7 +60,7 @@ func (suite *AssetWithdrawTestSuite) SetupTest() {
MainBlockHash10 = blockDetail.Block.Hash()
// setup title nodes : len = 1
nodeConfigKey := calcConfigNodesKey(Title)
nodeConfigKey := calcManageConfigNodesKey(Title)
nodeValue := makeNodeInfo(Title, Title, 1)
suite.stateDB.Set(nodeConfigKey, types.Encode(nodeValue))
value, err := suite.stateDB.Get(nodeConfigKey)
......
......@@ -86,3 +86,9 @@ func (e *Paracross) Exec_TransferToExec(payload *types.AssetsTransferToExec, tx
a := newAction(e, tx)
return a.TransferToExec(payload, tx, index)
}
//Exec_NodeConfig exec super node config
func (e *Paracross) Exec_NodeConfig(payload *pt.ParaNodeAddrConfig, tx *types.Transaction, index int) (*types.Receipt, error) {
a := newAction(e, tx)
return a.NodeConfig(payload)
}
......@@ -49,6 +49,36 @@ func (e *Paracross) ExecDelLocal_Commit(payload *pt.ParacrossCommitAction, tx *t
return &set, nil
}
// ExecDelLocal_NodeConfig node config tx delete process
func (e *Paracross) ExecDelLocal_NodeConfig(payload *pt.ParaNodeAddrConfig, tx *types.Transaction, receiptData *types.ReceiptData, index int) (*types.LocalDBSet, error) {
var set types.LocalDBSet
for _, log := range receiptData.Logs {
if log.Ty == pt.TyLogParaNodeConfig {
var g pt.ReceiptParaNodeConfig
err := types.Decode(log.Log, &g)
if err != nil {
return nil, err
}
if g.Prev != nil {
set.KV = append(set.KV, &types.KeyValue{
Key: calcLocalNodeTitleStatus(g.Current.Title, g.Current.ApplyAddr, g.Prev.Status), Value: types.Encode(g.Prev)})
}
set.KV = append(set.KV, &types.KeyValue{
Key: calcLocalNodeTitleStatus(g.Current.Title, g.Current.ApplyAddr, g.Current.Status), Value: nil})
} else if log.Ty == pt.TyLogParaNodeVoteDone {
var g pt.ReceiptParaNodeVoteDone
err := types.Decode(log.Log, &g)
if err != nil {
return nil, err
}
key := calcLocalNodeTitleDone(g.Title, g.TargetAddr)
set.KV = append(set.KV, &types.KeyValue{Key: key, Value: nil})
}
}
return &set, nil
}
//ExecDelLocal_AssetTransfer asset transfer del local db process
func (e *Paracross) ExecDelLocal_AssetTransfer(payload *types.AssetsTransfer, tx *types.Transaction, receiptData *types.ReceiptData, index int) (*types.LocalDBSet, error) {
var set types.LocalDBSet
......
......@@ -51,6 +51,37 @@ func (e *Paracross) ExecLocal_Commit(payload *pt.ParacrossCommitAction, tx *type
return &set, nil
}
//ExecLocal_NodeConfig node config add process
func (e *Paracross) ExecLocal_NodeConfig(payload *pt.ParaNodeAddrConfig, tx *types.Transaction, receiptData *types.ReceiptData, index int) (*types.LocalDBSet, error) {
var set types.LocalDBSet
for _, log := range receiptData.Logs {
if log.Ty == pt.TyLogParaNodeConfig {
var g pt.ReceiptParaNodeConfig
err := types.Decode(log.Log, &g)
if err != nil {
return nil, err
}
if g.Prev != nil {
set.KV = append(set.KV, &types.KeyValue{
Key: calcLocalNodeTitleStatus(g.Current.Title, g.Current.ApplyAddr, g.Prev.Status), Value: nil})
}
set.KV = append(set.KV, &types.KeyValue{
Key: calcLocalNodeTitleStatus(g.Current.Title, g.Current.ApplyAddr, g.Current.Status),
Value: types.Encode(g.Current)})
} else if log.Ty == pt.TyLogParaNodeVoteDone {
var g pt.ReceiptParaNodeVoteDone
err := types.Decode(log.Log, &g)
if err != nil {
return nil, err
}
key := calcLocalNodeTitleDone(g.Title, g.TargetAddr)
set.KV = append(set.KV, &types.KeyValue{Key: key, Value: types.Encode(&g)})
}
}
return &set, nil
}
//ExecLocal_AssetTransfer asset transfer local proc
func (e *Paracross) ExecLocal_AssetTransfer(payload *types.AssetsTransfer, tx *types.Transaction, receiptData *types.ReceiptData, index int) (*types.LocalDBSet, error) {
var set types.LocalDBSet
......
......@@ -11,25 +11,33 @@ import (
)
var (
title string
titleHeight string
titleHash string
configNodes string
localTx string
localTitle string
localTitleHeight string
localAssetKey string
title string
titleHeight string
managerConfigNodes string //manager 合约配置的nodes
paraConfigNodes string //平行链自组织配置的nodes,最初是从manager同步过来
paraConfigNodeAddr string //平行链配置节点账户
localTx string
localTitle string
localTitleHeight string
localAssetKey string
localNodeTitleStatus string
localNodeTitleDone string
)
func setPrefix() {
title = "mavl-paracross-title-"
titleHeight = "mavl-paracross-titleHeight-"
titleHash = "mavl-paracross-titleHash-"
configNodes = "paracross-nodes-"
managerConfigNodes = "paracross-nodes-"
paraConfigNodes = "mavl-paracross-nodes-title-"
paraConfigNodeAddr = "mavl-paracross-nodes-titleAddr-"
localTx = "LODB-paracross-titleHeightAddr-"
localTitle = "LODB-paracross-title-"
localTitleHeight = "LODB-paracross-titleHeight-"
localAssetKey = "LODB-paracross-asset-"
localNodeTitleStatus = "LODB-paracross-nodesTitleStatus-"
localNodeTitleDone = "LODB-paracross-nodesTitleDone-"
}
func calcTitleKey(t string) []byte {
......@@ -40,19 +48,23 @@ func calcTitleHeightKey(title string, height int64) []byte {
return []byte(fmt.Sprintf(titleHeight+"%s-%d", title, height))
}
func calcTitleHashKey(title string, blockHash string) []byte {
return []byte(fmt.Sprintf(titleHash+"%s-%s", title, blockHash))
}
func calcLocalHeightKey(title string, height int64) []byte {
return []byte(fmt.Sprintf(localTitleHeight+"%s-%d", title, height))
}
func calcConfigNodesKey(title string) []byte {
key := configNodes + title
func calcManageConfigNodesKey(title string) []byte {
key := managerConfigNodes + title
return []byte(types.ManageKey(key))
}
func calcParaNodeGroupKey(title string) []byte {
return []byte(fmt.Sprintf(paraConfigNodes+"%s", title))
}
func calcParaNodeAddrKey(title string, addr string) []byte {
return []byte(fmt.Sprintf(paraConfigNodeAddr+"%s-%s", title, addr))
}
func calcLocalTxKey(title string, height int64, addr string) []byte {
return []byte(fmt.Sprintf(localTx+"%s-%012-%s", title, height, addr))
}
......@@ -61,10 +73,6 @@ func calcLocalTitleKey(title string) []byte {
return []byte(fmt.Sprintf(localTitle+"%s", title))
}
func calcLocalTitleHeightKey(title string, height int64) []byte {
return []byte(fmt.Sprintf(localTitle+"%s-%012d", title, height))
}
func calcLocalTitlePrefix() []byte {
return []byte(localTitle)
}
......@@ -72,3 +80,15 @@ func calcLocalTitlePrefix() []byte {
func calcLocalAssetKey(hash []byte) []byte {
return []byte(fmt.Sprintf(localAssetKey+"%s", hash))
}
func calcLocalNodeTitleStatus(title, addr string, status int32) []byte {
return []byte(fmt.Sprintf(localNodeTitleStatus+"%s-%02d-%s", title, status, addr))
}
func calcLocalNodeStatusPrefix(title string, status int32) []byte {
return []byte(fmt.Sprintf(localNodeTitleStatus+"%s-%02d", title, status))
}
func calcLocalNodeTitleDone(title, addr string) []byte {
return []byte(fmt.Sprintf(localNodeTitleDone+"%s-%s", title, addr))
}
......@@ -322,7 +322,7 @@ func (c *Paracross) allow(tx *types.Transaction, index int) error {
return nil
}
if types.IsDappFork(c.GetHeight(), pt.ParaX, pt.ForkCommitTx) {
if payload.Ty == pt.ParacrossActionCommit {
if payload.Ty == pt.ParacrossActionCommit || payload.Ty == pt.ParacrossActionNodeConfig {
return nil
}
}
......
......@@ -111,7 +111,7 @@ func (suite *CommitTestSuite) SetupSuite() {
MainBlockHash10 = blockDetail.Block.Hash()
// setup title nodes : len = 4
nodeConfigKey := calcConfigNodesKey(Title)
nodeConfigKey := calcManageConfigNodesKey(Title)
nodeValue := makeNodeInfo(Title, Title, 4)
suite.stateDB.Set(nodeConfigKey, types.Encode(nodeValue))
value, err := suite.stateDB.Get(nodeConfigKey)
......@@ -139,7 +139,7 @@ func (suite *CommitTestSuite) SetupSuite() {
}
func (suite *CommitTestSuite) TestSetup() {
nodeConfigKey := calcConfigNodesKey(Title)
nodeConfigKey := calcManageConfigNodesKey(Title)
suite.T().Log(string(nodeConfigKey))
_, err := suite.stateDB.Get(nodeConfigKey)
if err != nil {
......@@ -257,7 +257,7 @@ func checkCommitReceipt(suite *CommitTestSuite, receipt *types.Receipt, commitCn
func checkDoneReceipt(suite suite.Suite, receipt *types.Receipt, commitCnt int) {
assert.Equal(suite.T(), receipt.Ty, int32(types.ExecOk))
assert.Len(suite.T(), receipt.KV, 3)
assert.Len(suite.T(), receipt.KV, 2)
assert.Len(suite.T(), receipt.Logs, 2)
key := calcTitleHeightKey(Title, TitleHeight)
......
......@@ -6,6 +6,10 @@ package executor
import (
"encoding/hex"
"fmt"
"math/big"
"strconv"
dbm "github.com/33cn/chain33/common/db"
"github.com/33cn/chain33/types"
......@@ -27,16 +31,52 @@ func (p *Paracross) Query_GetTitleByHash(in *pt.ReqParacrossTitleHash) (types.Me
return nil, types.ErrInvalidParam
}
if !types.IsDappFork(p.GetMainHeight(), pt.ParaX, pt.ForkCommitTx) {
block, err := p.GetAPI().GetBlockOverview(&types.ReqHash{Hash: in.BlockHash})
if err != nil || block == nil {
return nil, types.ErrHashNotExist
}
return p.paracrossGetHeight(in.GetTitle())
block, err := p.GetAPI().GetBlockOverview(&types.ReqHash{Hash: in.BlockHash})
if err != nil || block == nil {
return nil, types.ErrHashNotExist
}
return p.paracrossGetHeight(in.GetTitle())
}
return p.paracrossGetHeightByHash(in)
//Query_GetNodeGroup get node group addrs
func (p *Paracross) Query_GetNodeGroup(in *types.ReqString) (types.Message, error) {
if in == nil {
return nil, types.ErrInvalidParam
}
key := calcParaNodeGroupKey(in.GetData())
ret, _, err := getNodes(p.GetStateDB(), key)
if err != nil {
return nil, errors.Cause(err)
}
var nodes []string
for k := range ret {
nodes = append(nodes, k)
}
var reply types.ReplyConfig
reply.Key = string(key)
reply.Value = fmt.Sprint(nodes)
return &reply, nil
}
//Query_GetNodeAddrInfo get specific node addr info
func (p *Paracross) Query_GetNodeAddrInfo(in *pt.ReqParacrossNodeInfo) (types.Message, error) {
if in == nil || in.Title == "" || in.Addr == "" {
return nil, types.ErrInvalidParam
}
key := calcParaNodeAddrKey(in.Title, in.Addr)
stat, err := getNodeAddr(p.GetStateDB(), key)
if err != nil {
return nil, err
}
return stat, nil
}
//Query_ListNodeStatusInfo list node info by status
func (p *Paracross) Query_ListNodeStatusInfo(in *pt.ReqParacrossNodeInfo) (types.Message, error) {
if in == nil || in.Title == "" {
return nil, types.ErrInvalidParam
}
return listLocalNodeStatus(p.GetLocalDB(), in.Title, in.Status)
}
//Query_ListTitles query paracross titles list
......@@ -100,14 +140,6 @@ func (p *Paracross) paracrossGetHeight(title string) (types.Message, error) {
return ret, nil
}
func (p *Paracross) paracrossGetHeightByHash(in *pt.ReqParacrossTitleHash) (types.Message, error) {
ret, err := getTitle(p.GetStateDB(), calcTitleHashKey(in.GetTitle(), hex.EncodeToString(in.GetBlockHash())))
if err != nil {
return nil, errors.Cause(err)
}
return ret, nil
}
func (p *Paracross) paracrossListTitles() (types.Message, error) {
return listLocalTitles(p.GetLocalDB())
}
......@@ -125,23 +157,65 @@ func listLocalTitles(db dbm.KVDB) (types.Message, error) {
if err != nil {
panic(err)
}
resp.Titles = append(resp.Titles, &st)
rst := &pt.RespParacrossDone{
TotalNodes: st.TotalNodes,
TotalCommit: st.TotalCommit,
MostSameCommit: st.MostSameCommit,
Title: st.Title,
Height: st.Height,
StateHash: hex.EncodeToString(st.StateHash),
TxCounts: st.TxCounts,
TxResult: strconv.FormatUint(big.NewInt(0).SetBytes(st.TxResult).Uint64(), 2),
}
resp.Titles = append(resp.Titles, rst)
}
return &resp, nil
}
//按状态遍历
func listLocalNodeStatus(db dbm.KVDB, title string, status int32) (types.Message, error) {
prefix := calcLocalNodeStatusPrefix(title, status)
res, err := db.List(prefix, []byte(""), 0, 1)
if err != nil {
return nil, err
}
var resp pt.RespParacrossNodeAddrs
for _, r := range res {
var st pt.ParaNodeAddrStatus
err = types.Decode(r, &st)
if err != nil {
panic(err)
}
resp.Addrs = append(resp.Addrs, &st)
}
return &resp, nil
}
func loadLocalTitle(db dbm.KV, title string, height int64) (types.Message, error) {
key := calcLocalTitleHeightKey(title, height)
key := calcLocalHeightKey(title, height)
res, err := db.Get(key)
if err != nil {
return nil, err
}
var resp pt.ReceiptParacrossDone
err = types.Decode(res, &resp)
var st pt.ReceiptParacrossDone
err = types.Decode(res, &st)
if err != nil {
panic(err)
}
return &resp, nil
return &pt.RespParacrossDone{
TotalNodes: st.TotalNodes,
TotalCommit: st.TotalCommit,
MostSameCommit: st.MostSameCommit,
Title: st.Title,
Height: st.Height,
StateHash: hex.EncodeToString(st.StateHash),
TxCounts: st.TxCounts,
TxResult: strconv.FormatUint(big.NewInt(0).SetBytes(st.TxResult).Uint64(), 2),
}, nil
}
func (p *Paracross) paracrossGetTitleHeight(title string, height int64) (types.Message, error) {
......
This diff is collapsed.
# paracross 执行器 授权账户管理
## 场景
1. 平行链申请开链之前申请几个授权账户,没有授权账户无法做跨链交易,目前没有押金机制
1. 主链超级用户会分别向主链和平行链的manager合约发送账户添加tx,作为平行链的初始授权账户
1. 平行链开链后在做跨链tx之前需要任何一个初始授权账户在平行链上发送takeover tx把初始授权账户接管到平行链,
由平行链自己管理,如果不发送接管tx,平行链跨链无法完成
1. 平行链接管初始授权账户后,初始授权账户审核后续新授权账户的添加和退出申请工作,必须除自己外,超过2/3数同意
才可加入和退出,如果只剩最后一个账户,则不允许退出,如果随意退出有只留下僵尸授权账户风险,平行链失控
1. 当前授权账户有投票删除某一个授权账户的权利,2/3数同意的规则
1. 新申请账户在当前任一账户同意条件下,超级账户投票有直接通过权利,尤其是在当前授权账户不足2/3达不成共识时候,需要超级账户干预
1. 特殊或异常场景:
1. 新申请节点还没投票就退出,不允许,必须都投完票之后再申请
1. 申请节点退出后重新申请,允许重新加入,但需要重新投票
1. 新申请节点投票超过2/3否决,后来又投票超过2/3同意,可以加入或退出
## 四个状态
```
+-----------------------------------
| |
adding --+ added --+ quiting --+ quited
| |
-----------------------+
```
1. adding: 新授权账户申请状态,若投票超过2/3否决停留在此状态,后续可以继续投赞成票
1. added: 授权账户被当前授权账户组超过2/3票通过状态
1. quiting: 当前授权账户申请退出账户组状态,投票超过2/3否决停留在此状态,后续可以继续投赞成票
1. quited: 授权账户quiting被账户组除自己外账户投票超过2/3通过状态,或added的账户被账户组除自己外投票超过2/3否决除名状态
## 测试场景:
1. 新节点发tx申请加入,超2/3同意,新节点加入成功处于added状态
1. 已加入节点申请退出,超2/3同意,已加入节点退出管理组处于quited状态
1. 新节点重新申请加入,超2/3否决,新节点仍停留在adding状态,后来投票节点又2/3同意,新节点加入
1. 投票节点一起投某一个账户组里面的账户否决票,超2/3数后,此账户退出账户组,又超过2/3同意后,仍处于退出状态(需自己申请加入)
1. 账户组里面账户申请退出,当是最后一个时候退出失败
1. 配4个节点,只有2个可以投票发共识消息,共识停止,2个新节点申请加入,其中一节点vote通过后,超级账户vote后通过,加入管理组参与共识
\ No newline at end of file
// Copyright Fuzamei Corp. 2018 All Rights Reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package executor
import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/suite"
//"github.com/stretchr/testify/mock"
"testing"
apimock "github.com/33cn/chain33/client/mocks"
dbm "github.com/33cn/chain33/common/db"
dbmock "github.com/33cn/chain33/common/db/mocks"
"github.com/33cn/chain33/types"
pt "github.com/33cn/plugin/plugin/dapp/paracross/types"
)
var (
PrivKey14K = "CC38546E9E659D15E6B4893F0AB32A06D103931A8230B0BDE71459D2B27D6944" // 14KEKbYtKKQm4wMthSK9J4La4nAiidGozt
Account14K = "14KEKbYtKKQm4wMthSK9J4La4nAiidGozt"
Account1MC = "1MCftFynyvG2F4ED5mdHYgziDxx6vDrScs"
)
type NodeManageTestSuite struct {
suite.Suite
stateDB dbm.KV
localDB *dbmock.KVDB
api *apimock.QueueProtocolAPI
exec *Paracross
}
func (suite *NodeManageTestSuite) SetupSuite() {
suite.stateDB, _ = dbm.NewGoMemDB("state", "state", 1024)
// memdb 不支持KVDB接口, 等测试完Exec , 再扩展 memdb
//suite.localDB, _ = dbm.NewGoMemDB("local", "local", 1024)
suite.localDB = new(dbmock.KVDB)
suite.api = new(apimock.QueueProtocolAPI)
suite.exec = newParacross().(*Paracross)
suite.exec.SetLocalDB(suite.localDB)
suite.exec.SetStateDB(suite.stateDB)
suite.exec.SetEnv(0, 0, 0)
suite.exec.SetAPI(suite.api)
enableParacrossTransfer = false
forkHeight := types.GetDappFork(pt.ParaX, pt.ForkCommitTx)
if forkHeight == types.MaxHeight {
types.SetDappFork(Title, pt.ParaX, pt.ForkCommitTx, 0)
}
// TODO, more fields
// setup block
blockDetail := &types.BlockDetail{
Block: &types.Block{},
}
MainBlockHash10 = blockDetail.Block.Hash()
// setup title nodes : len = 4
nodeConfigKey := calcManageConfigNodesKey(Title)
nodeValue := makeNodeInfo(Title, Title, 4)
suite.stateDB.Set(nodeConfigKey, types.Encode(nodeValue))
value, err := suite.stateDB.Get(nodeConfigKey)
if err != nil {
suite.T().Error("get setup title failed", err)
return
}
assert.Equal(suite.T(), value, types.Encode(nodeValue))
}
func (suite *NodeManageTestSuite) TestSetup() {
nodeConfigKey := calcParaNodeGroupKey(Title)
suite.T().Log(string(nodeConfigKey))
_, err := suite.stateDB.Get(nodeConfigKey)
if err != nil {
suite.T().Error("get setup title failed", err)
return
}
}
func nodeCommit(suite *NodeManageTestSuite, privkeyStr string, tx *types.Transaction) (receipt *types.Receipt) {
return nodeCommitImpl(suite.Suite, suite.exec, privkeyStr, tx)
}
func nodeCommitImpl(suite suite.Suite, exec *Paracross, privkeyStr string, tx *types.Transaction) (receipt *types.Receipt) {
tx, _ = signTx(suite, tx, privkeyStr)
suite.T().Log(tx.From())
receipt, err := exec.Exec(tx, 0)
suite.T().Log(receipt)
assert.NotNil(suite.T(), receipt)
assert.Nil(suite.T(), err)
return
}
func checkJoinReceipt(suite *NodeManageTestSuite, receipt *types.Receipt) {
assert.Equal(suite.T(), receipt.Ty, int32(types.ExecOk))
assert.Len(suite.T(), receipt.KV, 1)
assert.Len(suite.T(), receipt.Logs, 1)
var stat pt.ParaNodeAddrStatus
err := types.Decode(receipt.KV[0].Value, &stat)
assert.Nil(suite.T(), err, "decode ParaNodeAddrStatus failed")
//suite.T().Log("titleHeight", titleHeight)
assert.Equal(suite.T(), int32(pt.TyLogParaNodeConfig), receipt.Logs[0].Ty)
assert.Equal(suite.T(), int32(pt.ParacrossNodeAdding), stat.Status)
assert.NotNil(suite.T(), stat.Votes)
}
func checkQuitReceipt(suite *NodeManageTestSuite, receipt *types.Receipt) {
assert.Equal(suite.T(), receipt.Ty, int32(types.ExecOk))
assert.Len(suite.T(), receipt.KV, 1)
assert.Len(suite.T(), receipt.Logs, 1)
var stat pt.ParaNodeAddrStatus
err := types.Decode(receipt.KV[0].Value, &stat)
assert.Nil(suite.T(), err, "decode ParaNodeAddrStatus failed")
//suite.T().Log("titleHeight", titleHeight)
assert.Equal(suite.T(), int32(pt.TyLogParaNodeConfig), receipt.Logs[0].Ty)
assert.Equal(suite.T(), int32(pt.ParacrossNodeQuiting), stat.Status)
assert.NotNil(suite.T(), stat.Votes)
}
func checkVoteReceipt(suite *NodeManageTestSuite, receipt *types.Receipt, count int) {
assert.Equal(suite.T(), receipt.Ty, int32(types.ExecOk))
assert.Len(suite.T(), receipt.KV, 1)
assert.Len(suite.T(), receipt.Logs, 1)
var stat pt.ParaNodeAddrStatus
err := types.Decode(receipt.KV[0].Value, &stat)
assert.Nil(suite.T(), err, "decode ParaNodeAddrStatus failed")
assert.Len(suite.T(), stat.Votes.Votes, count)
////suite.T().Log("titleHeight", titleHeight)
//assert.Equal(suite.T(), int32(pt.TyLogParaNodeConfig), receipt.Logs[0].Ty)
//assert.Equal(suite.T(), int32(pt.ParacrossNodeAdding), stat.Status)
//assert.NotNil(suite.T(), stat.Votes)
}
func checkVoteDoneReceipt(suite *NodeManageTestSuite, receipt *types.Receipt, count int, join bool) {
assert.Equal(suite.T(), receipt.Ty, int32(types.ExecOk))
assert.Len(suite.T(), receipt.KV, 2)
assert.Len(suite.T(), receipt.Logs, 3)
var stat pt.ParaNodeAddrStatus
err := types.Decode(receipt.KV[0].Value, &stat)
assert.Nil(suite.T(), err, "decode ParaNodeAddrStatus failed")
assert.Len(suite.T(), stat.Votes.Votes, count)
var item types.ConfigItem
err = types.Decode(receipt.KV[1].Value, &item)
assert.Nil(suite.T(), err, "decode ParaNodeAddrStatus failed")
if join {
suite.Contains(item.GetArr().Value, Account14K)
} else {
suite.NotContains(item.GetArr().Value, Account14K)
}
}
func voteTest(suite *NodeManageTestSuite, addr string, join bool) {
config := &pt.ParaNodeAddrConfig{
Op: pt.ParaNodeVote,
Addr: addr,
Value: pt.ParaNodeVoteYes,
}
tx, err := pt.CreateRawNodeConfigTx(config)
suite.Nil(err)
receipt := nodeCommit(suite, PrivKeyA, tx)
checkVoteReceipt(suite, receipt, 1)
receipt = nodeCommit(suite, PrivKeyB, tx)
checkVoteReceipt(suite, receipt, 2)
receipt = nodeCommit(suite, PrivKeyC, tx)
checkVoteDoneReceipt(suite, receipt, 3, join)
}
func (suite *NodeManageTestSuite) TestExec() {
//takeover
config := &pt.ParaNodeAddrConfig{
Op: pt.ParaNodeTakeover,
Addr: Account14K,
}
tx, err := pt.CreateRawNodeConfigTx(config)
suite.Nil(err)
nodeCommit(suite, PrivKey14K, tx)
//checkJoinReceipt(suite, receipt)
//Join test
config = &pt.ParaNodeAddrConfig{
Op: pt.ParaNodeJoin,
Addr: Account14K,
}
tx, err = pt.CreateRawNodeConfigTx(config)
suite.Nil(err)
receipt := nodeCommit(suite, PrivKey14K, tx)
checkJoinReceipt(suite, receipt)
//vote test
voteTest(suite, Account14K, true)
//Quit test
config = &pt.ParaNodeAddrConfig{
Op: pt.ParaNodeQuit,
Addr: Account1MC,
}
tx, err = pt.CreateRawNodeConfigTx(config)
suite.Nil(err)
receipt = nodeCommit(suite, PrivKeyD, tx)
checkQuitReceipt(suite, receipt)
//vote test
voteTest(suite, Account1MC, false)
}
func TestNodeManageSuite(t *testing.T) {
tempTitle = types.GetTitle()
types.SetTitleOnlyForTest(Title)
suite.Run(t, new(NodeManageTestSuite))
types.SetTitleOnlyForTest(tempTitle)
}
......@@ -3,6 +3,7 @@ syntax = "proto3";
import "transaction.proto";
import "common.proto";
import "blockchain.proto";
import "executor.proto";
package types;
......@@ -33,6 +34,62 @@ message ParacrossConsensusStatus {
string consensBlockHash = 4;
}
message ParaNodeAddrConfig{
string title = 1;
string op = 2;
string addr = 3;
string value = 4;
}
message ParaNodeVoteDetail{
repeated string addrs = 1;
repeated string votes = 2;
}
message ParaNodeAddrStatus{
int32 status = 1;
string title = 2;
string applyAddr = 3;
ParaNodeVoteDetail votes = 4;
}
message ReceiptParaNodeConfig {
string addr = 1;
ParaNodeAddrConfig config = 2;
ParaNodeAddrStatus prev = 3;
ParaNodeAddrStatus current = 4;
}
message ReceiptParaNodeVoteRecord {
string fromAddr = 1;
string voteAddr = 2;
int32 value = 3;
}
message ReceiptParaNodeVoteDone {
string title = 1;
string targetAddr = 2;
int32 totalNodes = 3;
int32 totalVote = 4;
int32 mostVote = 5;
string voteRst = 6;
int32 doneStatus = 7;
}
// node query
message ReqParacrossNodeInfo {
string title = 1;
string addr = 2;
int32 status = 3;
}
message RespParacrossNodeAddrs {
repeated ParaNodeAddrStatus addrs = 1;
}
message ParaBlock2MainMap {
int64 height = 1;
string blockHash = 2;
......@@ -78,6 +135,8 @@ message ParacrossAction {
AssetsTransfer transfer = 6;
AssetsWithdraw withdraw = 7;
AssetsTransferToExec transferToExec = 8;
ParaNodeAddrConfig nodeConfig = 9;
}
int32 ty = 2;
}
......@@ -122,8 +181,19 @@ message ReqParacrossTitleHeight {
int64 height = 2;
}
message RespParacrossDone {
int32 totalNodes = 1;
int32 totalCommit = 2;
int32 mostSameCommit = 3;
string title = 4;
int64 height = 5;
string stateHash = 6;
uint32 txCounts = 7;
string txResult = 8;
}
message RespParacrossTitles {
repeated ReceiptParacrossDone titles = 1;
repeated RespParacrossDone titles = 1;
}
message ReqParacrossTitleHash {
......@@ -149,10 +219,12 @@ message ParacrossAsset {
bool success = 23;
}
service paracross {
rpc GetTitle(ReqString) returns (ParacrossConsensusStatus) {}
rpc ListTitles(ReqNil) returns (RespParacrossTitles) {}
rpc GetTitleHeight(ReqParacrossTitleHeight) returns (ReceiptParacrossDone) {}
rpc GetTitleHeight(ReqParacrossTitleHeight) returns (RespParacrossDone) {}
rpc GetAssetTxResult(ReqHash) returns (ParacrossAsset) {}
rpc IsSync(ReqNil) returns (IsCaughtUp) {}
}
\ No newline at end of file
......@@ -72,12 +72,12 @@ func (c *Jrpc) ListTitles(req *types.ReqNil, result *interface{}) error {
return err
}
func (c *channelClient) GetTitleHeight(ctx context.Context, req *pt.ReqParacrossTitleHeight) (*pt.ReceiptParacrossDone, error) {
func (c *channelClient) GetTitleHeight(ctx context.Context, req *pt.ReqParacrossTitleHeight) (*pt.RespParacrossDone, error) {
data, err := c.Query(pt.GetExecName(), "GetTitleHeight", req)
if err != nil {
return nil, err
}
if resp, ok := data.(*pt.ReceiptParacrossDone); ok {
if resp, ok := data.(*pt.RespParacrossDone); ok {
return resp, nil
}
return nil, types.ErrDecode
......@@ -167,3 +167,63 @@ func (c *Jrpc) GetBlock2MainInfo(req *types.ReqBlocks, result *interface{}) erro
*result = *ret
return err
}
// GetNodeGroup get super node group
func (c *channelClient) GetNodeGroup(ctx context.Context, req *types.ReqString) (*types.ReplyConfig, error) {
r := *req
data, err := c.Query(pt.GetExecName(), "GetNodeGroup", &r)
if err != nil {
return nil, err
}
if resp, ok := data.(*types.ReplyConfig); ok {
return resp, nil
}
return nil, types.ErrDecode
}
// GetNodeGroup get super node group
func (c *Jrpc) GetNodeGroup(req *types.ReqString, result *interface{}) error {
data, err := c.cli.GetNodeGroup(context.Background(), req)
*result = data
return err
}
// GetNodeStatus get super node status
func (c *channelClient) GetNodeStatus(ctx context.Context, req *pt.ReqParacrossNodeInfo) (*pt.ParaNodeAddrStatus, error) {
r := *req
data, err := c.Query(pt.GetExecName(), "GetNodeAddrInfo", &r)
if err != nil {
return nil, err
}
if resp, ok := data.(*pt.ParaNodeAddrStatus); ok {
return resp, nil
}
return nil, types.ErrDecode
}
// GetNodeStatus get super node status
func (c *Jrpc) GetNodeStatus(req *pt.ReqParacrossNodeInfo, result *interface{}) error {
data, err := c.cli.GetNodeStatus(context.Background(), req)
*result = data
return err
}
//ListNodeStatus list super node by status
func (c *channelClient) ListNodeStatus(ctx context.Context, req *pt.ReqParacrossNodeInfo) (*pt.RespParacrossNodeAddrs, error) {
r := *req
data, err := c.Query(pt.GetExecName(), "ListNodeStatusInfo", &r)
if err != nil {
return nil, err
}
if resp, ok := data.(*pt.RespParacrossNodeAddrs); ok {
return resp, nil
}
return nil, types.ErrDecode
}
//ListNodeStatus list super node by status
func (c *Jrpc) ListNodeStatus(req *pt.ReqParacrossNodeInfo, result *interface{}) error {
data, err := c.cli.ListNodeStatus(context.Background(), req)
*result = data
return err
}
......@@ -77,7 +77,7 @@ func TestChannelClient_GetTitleHeight(t *testing.T) {
client := newGrpc(api)
client.Init("paracross", nil, nil, nil)
req := &pt.ReqParacrossTitleHeight{}
api.On("Query", pt.GetExecName(), "GetTitleHeight", req).Return(&pt.ReceiptParacrossDone{}, nil)
api.On("Query", pt.GetExecName(), "GetTitleHeight", req).Return(&pt.RespParacrossDone{}, nil)
_, err := client.GetTitleHeight(context.Background(), req)
assert.Nil(t, err)
}
......@@ -87,7 +87,7 @@ func TestJrpc_GetTitleHeight(t *testing.T) {
j := newJrpc(api)
req := &pt.ReqParacrossTitleHeight{}
var result interface{}
api.On("Query", pt.GetExecName(), "GetTitleHeight", req).Return(&pt.ReceiptParacrossDone{}, nil)
api.On("Query", pt.GetExecName(), "GetTitleHeight", req).Return(&pt.RespParacrossDone{}, nil)
err := j.GetTitleHeight(req, &result)
assert.Nil(t, err)
}
......
......@@ -27,4 +27,20 @@ var (
ErrParaWaitingNewSeq = errors.New("ErrParaWaitingNewSeq")
// ErrParaCurHashNotMatch para curr main hash not match with pre, main node may switched
ErrParaCurHashNotMatch = errors.New("ErrParaCurHashNotMatch")
// ErrParaUnSupportNodeOper unsupport node operation
ErrParaUnSupportNodeOper = errors.New("ErrParaUnSupportNodeOper")
//ErrParaNodeAddrExisted node addr exist in group
ErrParaNodeAddrExisted = errors.New("ErrParaNodeAddrExisted")
//ErrParaNodeAddrNotExisted node addr not exist in group
ErrParaNodeAddrNotExisted = errors.New("ErrParaNodeAddrNotExisted")
//ErrParaManageNodesNotSet config manage node not set
ErrParaManageNodesNotSet = errors.New("ErrParaManageNodesNotSet")
//ErrParaNodeGroupNotSet para config node group not set by take over
ErrParaNodeGroupNotSet = errors.New("ErrParaManageNodesNotSet")
//ErrParaNodeGroupExisted para config group taked over alreay
ErrParaNodeGroupExisted = errors.New("ErrParaNodesExisted")
//ErrParaNodeGroupLastAddr last super node not be allow to quite
ErrParaNodeGroupLastAddr = errors.New("ErrParaNodeGroupLastAddr")
//ErrParaNodeVoteSelf vote self not allow
ErrParaNodeVoteSelf = errors.New("ErrParaNodeVoteSelf")
)
......@@ -35,6 +35,10 @@ const (
TyLogParacrossMiner = 655
// TyLogParaAssetDeposit asset deposit log key
TyLogParaAssetDeposit = 656
// TyLogParaNodeConfig config super node log key
TyLogParaNodeConfig = 657
TyLogParaNodeVoteDone = 658
TyLogParaNodeGroupUpdate = 659
)
type paracrossCommitTx struct {
......@@ -66,6 +70,8 @@ const (
ParacrossActionAssetTransfer = iota + paraCrossTransferActionTypeStart
// ParacrossActionAssetWithdraw paracross asset withdraw key
ParacrossActionAssetWithdraw
//ParacrossActionNodeConfig para super node config
ParacrossActionNodeConfig
)
// status
......@@ -76,6 +82,28 @@ const (
ParacrossStatusCommitDone
)
// node config op
const (
ParaNodeJoin = "join"
ParaNodeQuit = "quit"
ParaNodeVote = "vote"
ParaNodeTakeover = "takeover"
ParaNodeVoteYes = "yes"
ParaNodeVoteNo = "no"
)
const (
// ParacrossNodeAdding apply for adding group
ParacrossNodeAdding = iota + 1
// ParacrossNodeAdded pass to add by votes
ParacrossNodeAdded
// ParacrossNodeQuiting apply for quiting
ParacrossNodeQuiting
// ParacrossNodeQuited pass to quite by votes
ParacrossNodeQuited
)
var (
// ParacrossActionCommitStr Commit string
ParacrossActionCommitStr = string("Commit")
......@@ -132,6 +160,21 @@ func createRawCommitTx(status *ParacrossNodeStatus, name string, fee int64) (*ty
return tx, nil
}
// CreateRawNodeConfigTx create raw tx for node config
func CreateRawNodeConfigTx(config *ParaNodeAddrConfig) (*types.Transaction, error) {
config.Title = types.GetTitle()
action := &ParacrossAction{
Ty: ParacrossActionNodeConfig,
Value: &ParacrossAction_NodeConfig{config},
}
tx := &types.Transaction{
Payload: types.Encode(action),
}
return tx, nil
}
// CreateRawAssetTransferTx create asset transfer tx
func CreateRawAssetTransferTx(param *types.CreateTx) (*types.Transaction, error) {
// 跨链交易需要在主链和平行链上执行, 所以应该可以在主链和平行链上构建
......
This diff is collapsed.
......@@ -61,6 +61,9 @@ func (p *ParacrossType) GetLogMap() map[int64]*types.LogInfo {
TyLogParaAssetTransfer: {Ty: reflect.TypeOf(types.ReceiptAccountTransfer{}), Name: "LogParaAssetTransfer"},
TyLogParaAssetDeposit: {Ty: reflect.TypeOf(types.ReceiptAccountTransfer{}), Name: "LogParaAssetDeposit"},
TyLogParacrossMiner: {Ty: reflect.TypeOf(ReceiptParacrossMiner{}), Name: "LogParacrossMiner"},
TyLogParaNodeConfig: {Ty: reflect.TypeOf(ReceiptParaNodeConfig{}), Name: "LogParaNodeConfig"},
TyLogParaNodeGroupUpdate: {Ty: reflect.TypeOf(types.ReceiptConfig{}), Name: "LogParaNodeGroupUpdate"},
TyLogParaNodeVoteDone: {Ty: reflect.TypeOf(ReceiptParaNodeVoteDone{}), Name: "LogParaNodeVoteDone"},
}
}
......@@ -74,6 +77,7 @@ func (p *ParacrossType) GetTypeMap() map[string]int32 {
"Transfer": ParacrossActionTransfer,
"Withdraw": ParacrossActionWithdraw,
"TransferToExec": ParacrossActionTransferToExec,
"NodeConfig": ParacrossActionNodeConfig,
}
}
......@@ -107,6 +111,17 @@ func (p ParacrossType) CreateTx(action string, message json.RawMessage) (*types.
action == "ParacrossTransferToExec" || action == "TransferToExec" {
return p.CreateRawTransferTx(action, message)
} else if action == "NodeConfig" {
if !types.IsPara() {
return nil, types.ErrNotSupport
}
var param ParaNodeAddrConfig
err := json.Unmarshal(message, &param)
if err != nil {
glog.Error("CreateTx.NodeConfig", "Error", err)
return nil, types.ErrInvalidParam
}
return CreateRawNodeConfigTx(&param)
}
return nil, types.ErrNotSupport
......
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