Commit aa8a0c88 authored by mdj33's avatar mdj33 Committed by vipwzw

added addr cancel operation

parent cfa64635
......@@ -251,12 +251,12 @@ func CreateRawNodeManageCmd() *cobra.Command {
}
func addNodeManageFlags(cmd *cobra.Command) {
cmd.Flags().Uint32P("operation", "o", 0, "operation:1:join,2:vote,3:quit")
cmd.Flags().Uint32P("operation", "o", 0, "operation:1:join,2:vote,3:quit,4:cancel")
cmd.MarkFlagRequired("operation")
cmd.Flags().StringP("addr", "a", "", "operating target addr")
cmd.Flags().StringP("addr", "a", "", "operating target addr[optional]")
cmd.Flags().StringP("id", "i", "", "operating target id")
cmd.Flags().StringP("id", "i", "", "operating target id[optional]")
cmd.Flags().Uint32P("value", "v", 1, "vote value: 1:yes,2:no")
cmd.Flags().Float64P("coins_frozen", "c", 0, "frozen coins amount, should not less nodegroup's")
......
......@@ -261,10 +261,10 @@ func (a *action) getNodesGroup(title string) (map[string]struct{}, error) {
}
//根据nodes过滤掉可能退出了的addrs
func updateCommitAddrs(stat *pt.ParacrossHeightStatus,nodes map[string]struct{}){
func updateCommitAddrs(stat *pt.ParacrossHeightStatus, nodes map[string]struct{}) {
details := &pt.ParacrossStatusDetails{}
for i,addr := range stat.Details.Addrs{
if _,ok :=nodes[addr]; ok{
for i, addr := range stat.Details.Addrs {
if _, ok := nodes[addr]; ok {
details.Addrs = append(details.Addrs, addr)
details.BlockHash = append(details.BlockHash, stat.Details.BlockHash[i])
}
......@@ -378,8 +378,8 @@ func (a *action) Commit(commit *pt.ParacrossCommitAction) (*types.Receipt, error
receipt = makeCommitReceipt(a.fromaddr, commit, &copyStat, stat)
}
if types.IsDappFork(commit.Status.MainBlockHeight, pt.ParaX, pt.ForkCommitTx){
updateCommitAddrs(stat,nodes)
if types.IsDappFork(commit.Status.MainBlockHeight, pt.ParaX, pt.ForkCommitTx) {
updateCommitAddrs(stat, nodes)
}
clog.Info("paracross.Commit commit", "stat.title", stat.Title, "stat.height", stat.Height, "notes", len(nodes))
......
......@@ -111,9 +111,28 @@ func makeVoteDoneReceipt(config *pt.ParaNodeIdStatus, totalCount, commitCount, m
}
}
func makeParaNodeStatusReceipt(fromAddr string, prev, current *pt.ParaNodeAddrIdStatus) *types.Receipt {
key := calcParaNodeAddrKey(current.Title, current.Addr)
log := &pt.ReceiptParaNodeAddrStatUpdate{
FromAddr: fromAddr,
Prev: prev,
Current: current,
}
return &types.Receipt{
Ty: types.ExecOk,
KV: []*types.KeyValue{
{Key: key, Value: types.Encode(current)},
},
Logs: []*types.ReceiptLog{
{
Ty: pt.TyLogParaNodeStatusUpdate,
Log: types.Encode(log),
},
},
}
}
func makeNodeConfigReceipt(fromAddr string, config *pt.ParaNodeAddrConfig, prev, current *pt.ParaNodeIdStatus) *types.Receipt {
key := calcParaNodeAddrKey(current.Title, current.TargetAddr)
val := &pt.ParaNodeAddrIdStatus{ProposalId: current.Id}
log := &pt.ReceiptParaNodeConfig{
Addr: fromAddr,
Config: config,
......@@ -124,7 +143,6 @@ func makeNodeConfigReceipt(fromAddr string, config *pt.ParaNodeAddrConfig, prev,
Ty: types.ExecOk,
KV: []*types.KeyValue{
{Key: []byte(current.Id), Value: types.Encode(current)},
{Key: key, Value: types.Encode(val)},
},
Logs: []*types.ReceiptLog{
{
......@@ -193,13 +211,24 @@ func makeParaNodeGroupReceipt(title string, prev, current *types.ConfigItem) *ty
}
}
func (a *action) nodeJoin(config *pt.ParaNodeAddrConfig) (*types.Receipt, error) {
func (a *action) checkValidNode(config *pt.ParaNodeAddrConfig) (bool, error) {
nodes, _, err := getParacrossNodes(a.db, config.Title)
if err != nil {
return nil, errors.Wrapf(err, "getNodes for title:%s", config.Title)
return false, errors.Wrapf(err, "getNodes for title:%s", config.Title)
}
//有可能申请地址和配置地址不是同一个
if validNode(config.Addr, nodes) {
return true, nil
}
return false, nil
}
func (a *action) nodeJoin(config *pt.ParaNodeAddrConfig) (*types.Receipt, error) {
addrExist, err := a.checkValidNode(config)
if err != nil {
return nil, err
}
if addrExist {
return nil, errors.Wrapf(pt.ErrParaNodeAddrExisted, "nodeAddr existed:%s", config.Addr)
}
......@@ -244,19 +273,9 @@ func (a *action) nodeJoin(config *pt.ParaNodeAddrConfig) (*types.Receipt, error)
return receipt, nil
}
stat, err := getNodeID(a.db, addrStat.ProposalId)
if err != nil {
clog.Error("nodeaccount.getNodeID fail", "err", err.Error())
return nil, err
}
var copyStat pt.ParaNodeIdStatus
err = deepCopy(&copyStat, stat)
if err != nil {
clog.Error("nodeaccount.nodeJoin deep copy fail", "copy", copyStat, "stat", stat)
return nil, err
}
if stat.Status == pt.ParacrossNodeQuited {
stat = &pt.ParaNodeIdStatus{
if addrStat.Status == pt.ParacrossNodeQuited {
stat := &pt.ParaNodeIdStatus{
Id: calcParaNodeIDKey(config.Title, common.ToHex(a.txhash)),
Status: pt.ParacrossNodeJoining,
Title: config.Title,
......@@ -265,17 +284,46 @@ func (a *action) nodeJoin(config *pt.ParaNodeAddrConfig) (*types.Receipt, error)
Votes: &pt.ParaNodeVoteDetail{},
CoinsFrozen: config.CoinsFrozen,
Height: a.height}
r := makeNodeConfigReceipt(a.fromaddr, config, &copyStat, stat)
r := makeNodeConfigReceipt(a.fromaddr, config, nil, stat)
receipt.KV = append(receipt.KV, r.KV...)
receipt.Logs = append(receipt.Logs, r.Logs...)
return receipt, nil
}
return nil, errors.Wrapf(pt.ErrParaNodeAddrExisted, "nodeAddr existed:%s,status:%d", config.Addr, stat.Status)
return nil, errors.Wrapf(pt.ErrParaNodeAddrExisted, "nodeAddr existed:%s,status:%d", config.Addr, addrStat.Status)
}
func (a *action) nodeQuit(config *pt.ParaNodeAddrConfig) (*types.Receipt, error) {
addrExist, err := a.checkValidNode(config)
if err != nil {
return nil, err
}
if !addrExist {
return nil, errors.Wrapf(pt.ErrParaNodeAddrNotExisted, "nodeAddr not existed:%s", config.Addr)
}
addrStat, err := getNodeAddr(a.db, config.Title, config.Addr)
if err != nil {
return nil, errors.Wrapf(err, "nodeAddr:%s get error", config.Addr)
}
if addrStat.Status != pt.ParacrossNodeJoined {
return nil, errors.Wrapf(pt.ErrParaNodeAddrNotExisted, "nodeAddr:%s status:%d", config.Addr, addrStat.Status)
}
stat := &pt.ParaNodeIdStatus{
Id: calcParaNodeIDKey(config.Title, common.ToHex(a.txhash)),
Status: pt.ParacrossNodeQuiting,
Title: config.Title,
TargetAddr: config.Addr,
FromAddr: a.fromaddr,
Votes: &pt.ParaNodeVoteDetail{},
Height: a.height}
return makeNodeConfigReceipt(a.fromaddr, config, nil, stat), nil
}
func (a *action) nodeCancel(config *pt.ParaNodeAddrConfig) (*types.Receipt, error) {
stat, err := getNodeID(a.db, config.Id)
if err != nil {
return nil, err
......@@ -285,53 +333,38 @@ func (a *action) nodeQuit(config *pt.ParaNodeAddrConfig) (*types.Receipt, error)
return nil, errors.Wrapf(pt.ErrNodeNotForTheTitle, "config title:%s,id title:%s", config.Title, stat.Title)
}
if stat.Status != pt.ParacrossNodeJoining && stat.Status != pt.ParacrossNodeQuiting {
return nil, errors.Wrapf(pt.ErrParaNodeOpStatusWrong, "config id:%s,status:%d", config.Id, stat.Status)
}
var copyStat pt.ParaNodeIdStatus
err = deepCopy(&copyStat, stat)
if err != nil {
clog.Error("nodeaccount.nodeQuit deep copy fail", "copy", copyStat, "stat", stat)
return nil, err
}
if stat.Status == pt.ParacrossNodeJoined {
nodes, _, err := getParacrossNodes(a.db, config.Title)
if err != nil {
return nil, errors.Wrapf(err, "getNodes for title:%s", config.Title)
}
if !validNode(stat.TargetAddr, nodes) {
return nil, errors.Wrapf(pt.ErrParaNodeAddrNotExisted, "nodeAddr not existed:%s", stat.TargetAddr)
}
//不允许最后一个账户退出
if len(nodes) == 1 {
return nil, errors.Wrapf(pt.ErrParaNodeGroupLastAddr, "nodeAddr last one:%s", stat.TargetAddr)
}
stat.Status = pt.ParacrossNodeQuiting
stat.Height = a.height
stat.Votes = &pt.ParaNodeVoteDetail{}
return makeNodeConfigReceipt(a.fromaddr, config, &copyStat, stat), nil
}
if stat.Status == pt.ParacrossNodeJoining {
//still adding status, quit directly
receipt := &types.Receipt{Ty: types.ExecOk}
if !types.IsPara() {
r, err := a.nodeGroupCoinsActive(stat.FromAddr, stat.CoinsFrozen, 1)
if err != nil {
return nil, err
}
receipt.KV = append(receipt.KV, r.KV...)
receipt.Logs = append(receipt.Logs, r.Logs...)
receipt = mergeReceipt(receipt, r)
}
stat.Status = pt.ParacrossNodeQuited
stat.Status = pt.ParacrossNodeCanceled
stat.Height = a.height
stat.Votes = &pt.ParaNodeVoteDetail{}
r := makeNodeConfigReceipt(a.fromaddr, config, &copyStat, stat)
receipt.KV = append(receipt.KV, r.KV...)
receipt.Logs = append(receipt.Logs, r.Logs...)
receipt = mergeReceipt(receipt, r)
return receipt, nil
}
if stat.Status == pt.ParacrossNodeQuiting {
stat.Status = pt.ParacrossNodeCanceled
stat.Height = a.height
return makeNodeConfigReceipt(a.fromaddr, config, &copyStat, stat), nil
}
return nil, errors.Wrapf(pt.ErrParaUnSupportNodeOper, "nodeid %s was quit status:%d", config.Id, stat.Status)
}
......@@ -401,10 +434,10 @@ func (a *action) superManagerVoteProc(title string) error {
return nil
}
func updateVotes(stat *pt.ParaNodeIdStatus,nodes map[string]struct{}){
func updateVotes(stat *pt.ParaNodeIdStatus, nodes map[string]struct{}) {
votes := &pt.ParaNodeVoteDetail{}
for i,addr := range stat.Votes.Addrs{
if _,ok :=nodes[addr]; ok{
for i, addr := range stat.Votes.Addrs {
if _, ok := nodes[addr]; ok {
votes.Addrs = append(votes.Addrs, addr)
votes.Votes = append(votes.Votes, stat.Votes.Votes[i])
}
......@@ -412,6 +445,55 @@ func updateVotes(stat *pt.ParaNodeIdStatus,nodes map[string]struct{}){
stat.Votes = votes
}
func (a *action) updateNodeAddrStatus(stat *pt.ParaNodeIdStatus) (*types.Receipt, error) {
addrStat, err := getNodeAddr(a.db, stat.Title, stat.TargetAddr)
if err != nil {
if !isNotFound(err) {
return nil, errors.Wrapf(err, "nodeAddr:%s get error", stat.TargetAddr)
}
if stat.Status != pt.ParacrossNodeJoined {
return nil, errors.Wrapf(pt.ErrParaNodeOpStatusWrong, "nodeAddr:%s int get wrong status", stat.TargetAddr, stat.Status)
}
addrStat = &pt.ParaNodeAddrIdStatus{}
addrStat.Title = stat.Title
addrStat.Addr = stat.TargetAddr
addrStat.Status = pt.ParacrossNodeJoined
addrStat.ProposalId = stat.Id
addrStat.QuitId = ""
return makeParaNodeStatusReceipt(a.fromaddr, nil, addrStat), nil
}
preStat := *addrStat
if stat.Status == pt.ParacrossNodeJoined {
addrStat.Status = pt.ParacrossNodeJoined
addrStat.ProposalId = stat.Id
addrStat.QuitId = ""
return makeParaNodeStatusReceipt(a.fromaddr, &preStat, addrStat), nil
}
if stat.Status == pt.ParacrossNodeQuited {
proposalStat, err := getNodeID(a.db, addrStat.ProposalId)
if err != nil {
return nil, errors.Wrapf(err, "nodeAddr:%s quiting wrong proposeid:%s", stat.TargetAddr, addrStat.ProposalId)
}
addrStat.Status = pt.ParacrossNodeQuited
addrStat.QuitId = stat.Id
receipt := makeParaNodeStatusReceipt(a.fromaddr, &preStat, addrStat)
if !types.IsPara() {
r, err := a.nodeGroupCoinsActive(proposalStat.FromAddr, proposalStat.CoinsFrozen, 1)
if err != nil {
return nil, err
}
receipt = mergeReceipt(receipt, r)
}
return receipt, nil
}
return nil, errors.Wrapf(pt.ErrParaNodeOpStatusWrong, "nodeAddr:%s get wrong status", stat.TargetAddr, stat.Status)
}
func (a *action) nodeVote(config *pt.ParaNodeAddrConfig) (*types.Receipt, error) {
nodes, _, err := getParacrossNodes(a.db, config.Title)
if err != nil {
......@@ -430,6 +512,9 @@ func (a *action) nodeVote(config *pt.ParaNodeAddrConfig) (*types.Receipt, error)
return nil, errors.Wrapf(pt.ErrNodeNotForTheTitle, "config title:%s,id title:%s", config.Title, stat.Title)
}
if stat.Status != pt.ParacrossNodeJoining && stat.Status != pt.ParacrossNodeQuiting {
return nil, errors.Wrapf(pt.ErrParaNodeOpStatusWrong, "config id:%s,status:%d", config.Id, stat.Status)
}
var copyStat pt.ParaNodeIdStatus
err = deepCopy(&copyStat, stat)
if err != nil {
......@@ -474,15 +559,10 @@ func (a *action) nodeVote(config *pt.ParaNodeAddrConfig) (*types.Receipt, error)
receipt := &types.Receipt{Ty: types.ExecOk}
if vote == pt.ParaNodeVoteNo {
// 对已经在group里面的node,直接投票remove,对正在申请中的adding or quiting状态保持不变,对quited的保持不变
if stat.Status == pt.ParacrossNodeJoined {
r, err := unpdateNodeGroup(a.db, config.Title, stat.TargetAddr, false)
if err != nil {
return nil, err
}
receipt = mergeReceipt(receipt, r)
stat.Status = pt.ParacrossNodeQuited
if stat.Status == pt.ParacrossNodeJoining {
stat.Status = pt.ParacrossNodeCanceled
stat.Height = a.height
//active coins
if !types.IsPara() {
r, err := a.nodeGroupCoinsActive(stat.FromAddr, stat.CoinsFrozen, 1)
if err != nil {
......@@ -490,7 +570,11 @@ func (a *action) nodeVote(config *pt.ParaNodeAddrConfig) (*types.Receipt, error)
}
receipt = mergeReceipt(receipt, r)
}
} else if stat.Status == pt.ParacrossNodeQuiting {
stat.Status = pt.ParacrossNodeCanceled
stat.Height = a.height
}
} else {
if stat.Status == pt.ParacrossNodeJoining {
r, err := unpdateNodeGroup(a.db, config.Title, stat.TargetAddr, true)
......@@ -500,6 +584,12 @@ func (a *action) nodeVote(config *pt.ParaNodeAddrConfig) (*types.Receipt, error)
stat.Status = pt.ParacrossNodeJoined
stat.Height = a.height
receipt = mergeReceipt(receipt, r)
r, err = a.updateNodeAddrStatus(stat)
if err != nil {
return nil, err
}
receipt = mergeReceipt(receipt, r)
} else if stat.Status == pt.ParacrossNodeQuiting {
r, err := unpdateNodeGroup(a.db, config.Title, stat.TargetAddr, false)
if err != nil {
......@@ -509,13 +599,12 @@ func (a *action) nodeVote(config *pt.ParaNodeAddrConfig) (*types.Receipt, error)
stat.Height = a.height
receipt = mergeReceipt(receipt, r)
if !types.IsPara() {
r, err := a.nodeGroupCoinsActive(stat.FromAddr, stat.CoinsFrozen, 1)
r, err = a.updateNodeAddrStatus(stat)
if err != nil {
return nil, err
}
receipt = mergeReceipt(receipt, r)
}
}
}
r := makeNodeConfigReceipt(a.fromaddr, config, &copyStat, stat)
......@@ -723,7 +812,7 @@ func (a *action) nodeGroupQuit(config *pt.ParaNodeGroupConfig) (*types.Receipt,
//approved or quited
if status.Status != pt.ParacrossNodeGroupApply {
return nil, errors.Wrapf(pt.ErrParaNodeGroupStatusWrong, "node group apply not apply:%d", status.Status)
return nil, errors.Wrapf(pt.ErrParaNodeOpStatusWrong, "node group apply not apply:%d", status.Status)
}
applyAddrs := strings.Split(status.TargetAddrs, ",")
......@@ -843,7 +932,7 @@ func (a *action) nodeGroupApprove(config *pt.ParaNodeGroupConfig) (*types.Receip
return a.nodeGroupApproveApply(config, id)
}
return nil, errors.Wrapf(pt.ErrParaNodeGroupStatusWrong, "nodeGroupApprove id wrong status:%d,id:%s", id.Status, config.Id)
return nil, errors.Wrapf(pt.ErrParaNodeOpStatusWrong, "nodeGroupApprove id wrong status:%d,id:%s", id.Status, config.Id)
}
......@@ -927,10 +1016,13 @@ func (a *action) NodeConfig(config *pt.ParaNodeAddrConfig) (*types.Receipt, erro
return a.nodeJoin(config)
} else if config.Op == pt.ParaNodeQuit {
return a.nodeQuit(config)
} else if config.Op == pt.ParaNodeCancel {
if config.Id == "" {
return nil, types.ErrInvalidParam
}
return a.nodeQuit(config)
return a.nodeCancel(config)
} else if config.Op == pt.ParaNodeVote {
if config.Id == "" || config.Value >= pt.ParaNodeVoteEnd {
......
......@@ -353,17 +353,17 @@ func TestGetAddrGroup(t *testing.T) {
}
func TestUpdateVotes(t *testing.T){
func TestUpdateVotes(t *testing.T) {
stat := &pt.ParaNodeIdStatus{}
votes := &pt.ParaNodeVoteDetail{
Addrs:[]string{"AA","BB","CC"},
Votes:[]string{"yes","no","no"}}
Addrs: []string{"AA", "BB", "CC"},
Votes: []string{"yes", "no", "no"}}
stat.Votes = votes
nodes := make(map[string]struct{})
nodes["BB"]= struct{}{}
nodes["BB"] = struct{}{}
nodes["CC"] = struct{}{}
updateVotes(stat,nodes)
assert.Equal(t,[]string{"BB","CC"},stat.Votes.Addrs)
assert.Equal(t,[]string{"no","no"},stat.Votes.Votes)
updateVotes(stat, nodes)
assert.Equal(t, []string{"BB", "CC"}, stat.Votes.Addrs)
assert.Equal(t, []string{"no", "no"}, stat.Votes.Votes)
}
......@@ -63,7 +63,11 @@ message ParaNodeVoteDetail {
}
message ParaNodeAddrIdStatus {
string proposalId = 1;
string addr = 1;
string proposalId = 2;
string quitId = 3;
int32 status = 4;
string title = 5;
}
message ParaNodeIdStatus {
......@@ -85,6 +89,11 @@ message ReceiptParaNodeConfig {
ParaNodeIdStatus current = 4;
}
message ReceiptParaNodeAddrStatUpdate {
string fromAddr = 1;
ParaNodeAddrIdStatus prev = 2;
ParaNodeAddrIdStatus current = 3;
}
message ReceiptParaNodeVoteDone {
string id = 1;
......
......@@ -45,8 +45,8 @@ var (
ErrParaNodeVoteSelf = errors.New("ErrParaNodeVoteSelf")
//ErrParaNodeGroupFrozenCoinsNotEnough node group coins in tx less than conf's minimum coins
ErrParaNodeGroupFrozenCoinsNotEnough = errors.New("ErrParaNodeGroupFrozenCoinsNotEnough")
//ErrParaNodeGroupStatusWrong node group process wrong status
ErrParaNodeGroupStatusWrong = errors.New("ErrParaNodeGroupStatusWrong")
//ErrParaNodeOpStatusWrong node process wrong status
ErrParaNodeOpStatusWrong = errors.New("ErrParaNodeOpStatusWrong")
//ErrParaConsensStopBlocksNotReach consensus stop blocks not reach
ErrParaConsensStopBlocksNotReach = errors.New("ErrParaConsensStopBlocksNotReach")
)
......@@ -41,6 +41,7 @@ const (
TyLogParaNodeVoteDone = 658
TyLogParaNodeGroupAddrsUpdate = 659
TyLogParaNodeGroupConfig = 660
TyLogParaNodeStatusUpdate = 661
TyLogParaNodeGroupStatusUpdate = 664
)
......@@ -92,6 +93,7 @@ const (
ParaNodeJoin = iota + 1
ParaNodeVote
ParaNodeQuit
ParaNodeCancel
)
// node vote op
......@@ -114,6 +116,8 @@ const (
ParacrossNodeQuiting
// ParacrossNodeQuited pass to quite by votes
ParacrossNodeQuited
// ParacrossNodeCanceled to cancel apply of joining or quiting
ParacrossNodeCanceled
)
const (
......
......@@ -62,6 +62,7 @@ func (p *ParacrossType) GetLogMap() map[int64]*types.LogInfo {
TyLogParaAssetDeposit: {Ty: reflect.TypeOf(types.ReceiptAccountTransfer{}), Name: "LogParaAssetDeposit"},
TyLogParacrossMiner: {Ty: reflect.TypeOf(ReceiptParacrossMiner{}), Name: "LogParacrossMiner"},
TyLogParaNodeConfig: {Ty: reflect.TypeOf(ReceiptParaNodeConfig{}), Name: "LogParaNodeConfig"},
TyLogParaNodeStatusUpdate: {Ty: reflect.TypeOf(ReceiptParaNodeAddrStatUpdate{}), Name: "LogParaNodeAddrStatUpdate"},
TyLogParaNodeGroupAddrsUpdate: {Ty: reflect.TypeOf(types.ReceiptConfig{}), Name: "LogParaNodeGroupAddrsUpdate"},
TyLogParaNodeVoteDone: {Ty: reflect.TypeOf(ReceiptParaNodeVoteDone{}), Name: "LogParaNodeVoteDone"},
TyLogParaNodeGroupConfig: {Ty: reflect.TypeOf(ReceiptParaNodeGroupConfig{}), Name: "LogParaNodeGroupConfig"},
......
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