Commit 0b56fd16 authored by liuyuhang's avatar liuyuhang Committed by 33cn

add test and modify bug

parent 43b37845
...@@ -9,11 +9,15 @@ import ( ...@@ -9,11 +9,15 @@ import (
drivers "github.com/33cn/chain33/system/dapp" drivers "github.com/33cn/chain33/system/dapp"
"github.com/33cn/chain33/types" "github.com/33cn/chain33/types"
auty "github.com/33cn/plugin/plugin/dapp/autonomy/types" auty "github.com/33cn/plugin/plugin/dapp/autonomy/types"
"github.com/33cn/chain33/common/address"
) )
var alog = log.New("module", "execs.autonomy") var (
alog = log.New("module", "execs.autonomy")
driverName = auty.AutonomyX
autonomyAddr = address.ExecAddress(auty.AutonomyX)
)
var driverName = auty.AutonomyX
func init() { func init() {
ety := types.LoadExecutorType(driverName) ety := types.LoadExecutorType(driverName)
......
...@@ -229,16 +229,16 @@ func (a *action) votePropBoard(voteProb *auty.VoteProposalBoard) (*types.Receipt ...@@ -229,16 +229,16 @@ func (a *action) votePropBoard(voteProb *auty.VoteProposalBoard) (*types.Receipt
cur.Res.Pass = true cur.Res.Pass = true
cur.PropBoard.RealEndBlockHeight = a.height cur.PropBoard.RealEndBlockHeight = a.height
receipt, err := a.coinsAccount.ExecTransferFrozen(cur.Address, auty.AutonomyX, a.execaddr, lockAmount) receipt, err := a.coinsAccount.ExecTransferFrozen(cur.Address, autonomyAddr, a.execaddr, lockAmount)
if err != nil { if err != nil {
alog.Error("votePropBoard ", "addr", a.fromaddr, "execaddr", a.execaddr, "ExecTransferFrozen amount fail", err) alog.Error("votePropBoard ", "addr", cur.Address, "execaddr", a.execaddr, "ExecTransferFrozen amount fail", err)
return nil, err return nil, err
} }
logs = append(logs, receipt.Logs...) logs = append(logs, receipt.Logs...)
kv = append(kv, receipt.KV...) kv = append(kv, receipt.KV...)
} }
key := propBoardID(common.ToHex(a.txhash)) key := propBoardID(voteProb.ProposalID)
cur.Status = auty.AutonomyStatusVotePropBoard cur.Status = auty.AutonomyStatusVotePropBoard
if cur.Res.Pass { if cur.Res.Pass {
cur.Status = auty.AutonomyStatusTmintPropBoard cur.Status = auty.AutonomyStatusTmintPropBoard
...@@ -263,32 +263,32 @@ func (a *action) tmintPropBoard(tmintProb *auty.TerminateProposalBoard) (*types. ...@@ -263,32 +263,32 @@ func (a *action) tmintPropBoard(tmintProb *auty.TerminateProposalBoard) (*types.
// 获取GameID // 获取GameID
value, err := a.db.Get(propBoardID(tmintProb.ProposalID)) value, err := a.db.Get(propBoardID(tmintProb.ProposalID))
if err != nil { if err != nil {
alog.Error("tmintPropBoard ", "addr", a.fromaddr, "execaddr", a.execaddr, "get round failed", alog.Error("tmintPropBoard ", "addr", a.fromaddr, "execaddr", a.execaddr, "get propBoardID failed",
tmintProb.ProposalID, "err", err) tmintProb.ProposalID, "err", err)
return nil, err return nil, err
} }
var cur auty.AutonomyProposalBoard var cur auty.AutonomyProposalBoard
err = types.Decode(value, &cur) err = types.Decode(value, &cur)
if err != nil { if err != nil {
alog.Error("tmintPropBoard ", "addr", a.fromaddr, "execaddr", a.execaddr, "decode round failed", alog.Error("tmintPropBoard ", "addr", a.fromaddr, "execaddr", a.execaddr, "decode AutonomyProposalBoard failed",
tmintProb.ProposalID, "err", err) tmintProb.ProposalID, "err", err)
return nil, err return nil, err
} }
pre := copyAutonomyProposalBoard(&cur) pre := copyAutonomyProposalBoard(&cur)
// 检查当前状态 start := cur.GetPropBoard().StartBlockHeight
if cur.Status != auty.AutonomyStatusVotePropBoard { end := cur.GetPropBoard().EndBlockHeight
err := auty.ErrProposalStatus if a.height < end && cur.Status != auty.AutonomyStatusVotePropBoard {
alog.Error("tmintPropBoard ", "addr", a.fromaddr, "status", cur.Status, "status is not match", err := auty.ErrTerminatePeriod
alog.Error("tmintPropBoard ", "addr", a.fromaddr, "status", cur.Status, "height", a.height, "ProposalID",
tmintProb.ProposalID, "err", err) tmintProb.ProposalID, "err", err)
return nil, err return nil, err
} }
start := cur.GetPropBoard().StartBlockHeight // 检查当前状态
end := cur.GetPropBoard().EndBlockHeight if cur.Status == auty.AutonomyStatusTmintPropBoard {
if a.height > end { err := auty.ErrProposalStatus
err := auty.ErrRevokeProposalPeriod alog.Error("tmintPropBoard ", "addr", a.fromaddr, "status", cur.Status, "status is not match",
alog.Error("tmintPropBoard ", "addr", a.fromaddr, "execaddr", a.execaddr, "ProposalID",
tmintProb.ProposalID, "err", err) tmintProb.ProposalID, "err", err)
return nil, err return nil, err
} }
...@@ -312,7 +312,7 @@ func (a *action) tmintPropBoard(tmintProb *auty.TerminateProposalBoard) (*types. ...@@ -312,7 +312,7 @@ func (a *action) tmintPropBoard(tmintProb *auty.TerminateProposalBoard) (*types.
var logs []*types.ReceiptLog var logs []*types.ReceiptLog
var kv []*types.KeyValue var kv []*types.KeyValue
receipt, err := a.coinsAccount.ExecTransferFrozen(cur.Address, auty.AutonomyX, a.execaddr, lockAmount) receipt, err := a.coinsAccount.ExecTransferFrozen(cur.Address, autonomyAddr, a.execaddr, lockAmount)
if err != nil { if err != nil {
alog.Error("votePropBoard ", "addr", a.fromaddr, "execaddr", a.execaddr, "ExecTransferFrozen amount fail", err) alog.Error("votePropBoard ", "addr", a.fromaddr, "execaddr", a.execaddr, "ExecTransferFrozen amount fail", err)
return nil, err return nil, err
......
...@@ -20,6 +20,7 @@ import ( ...@@ -20,6 +20,7 @@ import (
_ "github.com/33cn/chain33/system" _ "github.com/33cn/chain33/system"
"github.com/stretchr/testify/mock" "github.com/stretchr/testify/mock"
"github.com/33cn/chain33/common/address" "github.com/33cn/chain33/common/address"
drivers "github.com/33cn/chain33/system/dapp"
"github.com/33cn/chain33/util" "github.com/33cn/chain33/util"
) )
...@@ -29,6 +30,8 @@ type execEnv struct { ...@@ -29,6 +30,8 @@ type execEnv struct {
index int index int
difficulty uint64 difficulty uint64
txHash string txHash string
startHeight int64
endHeight int64
} }
var ( var (
...@@ -57,14 +60,14 @@ var ( ...@@ -57,14 +60,14 @@ var (
OutAmount int64 = 5 OutAmount int64 = 5
boards = []string{"1KSBd17H7ZK8iT37aJztFB22XGwsPTdwE4", "1JRNjdEqp4LJ5fqycUBm9ayCKSeeskgMKR", "1NLHPEcbTWWxxU3dGUZBhayjrCHD3psX7k"} boards = []string{"1KSBd17H7ZK8iT37aJztFB22XGwsPTdwE4", "1JRNjdEqp4LJ5fqycUBm9ayCKSeeskgMKR", "1NLHPEcbTWWxxU3dGUZBhayjrCHD3psX7k"}
total = types.Coin * 30000
) )
func init() { func init() {
commonlog.SetLogLevel("error") commonlog.SetLogLevel("error")
} }
func TestProposalBoard(t *testing.T) { func InitEnv() (*execEnv, drivers.Driver, dbm.KV, dbm.KVDB) {
total := types.Coin * 30000
accountA := types.Account{ accountA := types.Account{
Balance: total, Balance: total,
Frozen: 0, Frozen: 0,
...@@ -89,17 +92,17 @@ func TestProposalBoard(t *testing.T) { ...@@ -89,17 +92,17 @@ func TestProposalBoard(t *testing.T) {
Addr: AddrD, Addr: AddrD,
} }
env := execEnv{ env := &execEnv{
1539918074, blockTime: 1539918074,
10, blockHeight: 10,
2, index: 2,
1539918074, difficulty: 1539918074,
"hash", txHash: "",
} }
stateDB, _ := dbm.NewGoMemDB("state", "state", 100) stateDB, _ := dbm.NewGoMemDB("state", "state", 100)
_, _, kvdb := util.CreateTestDB() _, _, kvdb := util.CreateTestDB()
api := new(apimock.QueueProtocolAPI)
accCoin := account.NewCoinsAccount() accCoin := account.NewCoinsAccount()
accCoin.SetDB(stateDB) accCoin.SetDB(stateDB)
...@@ -108,14 +111,43 @@ func TestProposalBoard(t *testing.T) { ...@@ -108,14 +111,43 @@ func TestProposalBoard(t *testing.T) {
accCoin.SaveAccount(&accountB) accCoin.SaveAccount(&accountB)
accCoin.SaveAccount(&accountC) accCoin.SaveAccount(&accountC)
accCoin.SaveAccount(&accountD) accCoin.SaveAccount(&accountD)
//total ticket balance
accCoin.SaveAccount(&types.Account{Balance: total*4,
Frozen: 0,
Addr: "16htvcBNSEA7fZhAdLJphDwQRQJaHpyHTp"})
exec := newAutonomy() exec := newAutonomy()
exec.SetStateDB(stateDB) exec.SetStateDB(stateDB)
exec.SetLocalDB(kvdb) exec.SetLocalDB(kvdb)
exec.SetEnv(env.blockHeight, env.blockTime, env.difficulty) exec.SetEnv(env.blockHeight, env.blockTime, env.difficulty)
exec.SetAPI(api) return env, exec, stateDB, kvdb
}
func TestRevokeProposalBoard(t *testing.T) {
env, exec, stateDB, kvdb := InitEnv()
// PropBoard
testPropBoard(t, env, exec, stateDB, kvdb, true)
//RevokeProposalBoard
revokeProposalBoard(t, env, exec, stateDB, kvdb, false)
}
func TestVoteProposalBoard(t *testing.T) {
env, exec, stateDB, kvdb := InitEnv()
// PropBoard
testPropBoard(t, env, exec, stateDB, kvdb, true)
//voteProposalBoard
voteProposalBoard(t, env, exec, stateDB, kvdb, true)
}
func TestTerminateProposalBoard(t *testing.T) {
env, exec, stateDB, kvdb := InitEnv()
// PropBoard // PropBoard
testPropBoard(t, env, exec, stateDB, kvdb, true)
//terminateProposalBoard
terminateProposalBoard(t, env, exec, stateDB, kvdb, true)
}
func testPropBoard(t *testing.T, env *execEnv, exec drivers.Driver, stateDB dbm.KV, kvdb dbm.KVDB, save bool) {
opt1 := &auty.ProposalBoard{ opt1 := &auty.ProposalBoard{
Year: 2019, Year: 2019,
Month: 7, Month: 7,
...@@ -134,21 +166,46 @@ func TestProposalBoard(t *testing.T) { ...@@ -134,21 +166,46 @@ func TestProposalBoard(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
require.NotNil(t, receipt) require.NotNil(t, receipt)
for _, kv := range receipt.KV { if save {
stateDB.Set(kv.Key, kv.Value) for _, kv := range receipt.KV {
stateDB.Set(kv.Key, kv.Value)
}
} }
receiptDate := &types.ReceiptData{Ty: receipt.Ty, Logs: receipt.Logs} receiptData := &types.ReceiptData{Ty: receipt.Ty, Logs: receipt.Logs}
set, err := exec.ExecLocal(pbtx, receiptDate, int(1)) set, err := exec.ExecLocal(pbtx, receiptData, int(1))
require.NoError(t, err) require.NoError(t, err)
require.NotNil(t, set) require.NotNil(t, set)
if save {
for _, kv := range set.KV {
kvdb.Set(kv.Key, kv.Value)
}
}
// 更新tahash
env.txHash = common.ToHex(pbtx.Hash())
env.startHeight = opt1.StartBlockHeight
env.endHeight = opt1.EndBlockHeight
for _, kv := range set.KV { // check
kvdb.Set(kv.Key, kv.Value) accCoin := account.NewCoinsAccount()
accCoin.SetDB(stateDB)
account := accCoin.LoadExecAccount(AddrA, address.ExecAddress(auty.AutonomyX))
require.Equal(t, lockAmount, account.Frozen)
}
func propBoardTx(parm *auty.ProposalBoard) (*types.Transaction, error) {
if parm == nil {
return nil, types.ErrInvalidParam
} }
val := &auty.AutonomyAction{
Ty: auty.AutonomyActionPropBoard,
Value: &auty.AutonomyAction_PropBoard{PropBoard: parm},
}
return types.CreateFormatTx(types.ExecName(auty.AutonomyX), types.Encode(val))
}
//RevokeProposalBoard func revokeProposalBoard(t *testing.T, env *execEnv, exec drivers.Driver, stateDB dbm.KV, kvdb dbm.KVDB, save bool) {
proposalID := common.ToHex(pbtx.Hash()) proposalID := env.txHash
opt2 := &auty.RevokeProposalBoard{ opt2 := &auty.RevokeProposalBoard{
ProposalID:proposalID, ProposalID:proposalID,
} }
...@@ -157,20 +214,29 @@ func TestProposalBoard(t *testing.T) { ...@@ -157,20 +214,29 @@ func TestProposalBoard(t *testing.T) {
rtx, err = signTx(rtx, PrivKeyA) rtx, err = signTx(rtx, PrivKeyA)
require.NoError(t, err) require.NoError(t, err)
exec.SetEnv(env.blockHeight, env.blockTime, env.difficulty) exec.SetEnv(env.blockHeight, env.blockTime, env.difficulty)
receipt, err = exec.Exec(rtx, int(1)) receipt, err := exec.Exec(rtx, int(1))
require.NoError(t, err) require.NoError(t, err)
require.NotNil(t, receipt) require.NotNil(t, receipt)
} if save {
for _, kv := range receipt.KV {
func propBoardTx(parm *auty.ProposalBoard) (*types.Transaction, error) { stateDB.Set(kv.Key, kv.Value)
if parm == nil { }
return nil, types.ErrInvalidParam
} }
val := &auty.AutonomyAction{
Ty: auty.AutonomyActionPropBoard, receiptData := &types.ReceiptData{Ty: receipt.Ty, Logs: receipt.Logs}
Value: &auty.AutonomyAction_PropBoard{PropBoard: parm}, set, err := exec.ExecLocal(rtx, receiptData, int(1))
require.NoError(t, err)
require.NotNil(t, set)
if save {
for _, kv := range set.KV {
kvdb.Set(kv.Key, kv.Value)
}
} }
return types.CreateFormatTx(types.ExecName(auty.AutonomyX), types.Encode(val)) // check
accCoin := account.NewCoinsAccount()
accCoin.SetDB(stateDB)
account := accCoin.LoadExecAccount(AddrA, address.ExecAddress(auty.AutonomyX))
require.Equal(t, int64(0), account.Frozen)
} }
func revokeProposalBoardTx(parm *auty.RevokeProposalBoard) (*types.Transaction, error) { func revokeProposalBoardTx(parm *auty.RevokeProposalBoard) (*types.Transaction, error) {
...@@ -184,6 +250,103 @@ func revokeProposalBoardTx(parm *auty.RevokeProposalBoard) (*types.Transaction, ...@@ -184,6 +250,103 @@ func revokeProposalBoardTx(parm *auty.RevokeProposalBoard) (*types.Transaction,
return types.CreateFormatTx(types.ExecName(auty.AutonomyX), types.Encode(val)) return types.CreateFormatTx(types.ExecName(auty.AutonomyX), types.Encode(val))
} }
func voteProposalBoard(t *testing.T, env *execEnv, exec drivers.Driver, stateDB dbm.KV, kvdb dbm.KVDB, save bool) {
api := new(apimock.QueueProtocolAPI)
api.On("StoreList", mock.Anything).Return(&types.StoreListReply{}, nil)
api.On("GetLastHeader", mock.Anything).Return(&types.Header{StateHash: []byte("")}, nil)
hear := &types.Header{StateHash: []byte("")}
api.On("GetHeaders", mock.Anything).
Return(&types.Headers{
Items:[]*types.Header{hear}}, nil)
acc := &types.Account{
Currency: 0,
Balance: total*4,
}
val := types.Encode(acc)
values := [][]byte{val}
api.On("StoreGet", mock.Anything).Return(&types.StoreReplyValue{Values:values}, nil).Once()
acc = &types.Account{
Currency: 0,
Balance: total,
}
val1 := types.Encode(acc)
values1 := [][]byte{val1}
api.On("StoreGet", mock.Anything).Return(&types.StoreReplyValue{Values:values1}, nil).Once()
exec.SetAPI(api)
proposalID := env.txHash
// 4人参与投票,3人赞成票,1人反对票
type record struct {
priv string
appr bool
}
records := []record{
{PrivKeyA, true},
{PrivKeyB, false},
{PrivKeyC, true},
//{PrivKeyD, true},
}
for _, record := range records {
opt := &auty.VoteProposalBoard{
ProposalID:proposalID,
Approve: record.appr,
}
tx, err := voteProposalBoardTx(opt)
require.NoError(t, err)
tx, err = signTx(tx, record.priv)
require.NoError(t, err)
// 设定当前高度为投票高度
exec.SetEnv(env.startHeight, env.blockTime, env.difficulty)
receipt, err := exec.Exec(tx, int(1))
require.NoError(t, err)
require.NotNil(t, receipt)
if save {
for _, kv := range receipt.KV {
stateDB.Set(kv.Key, kv.Value)
}
}
receiptData := &types.ReceiptData{Ty: receipt.Ty, Logs: receipt.Logs}
set, err := exec.ExecLocal(tx, receiptData, int(1))
require.NoError(t, err)
require.NotNil(t, set)
if save {
for _, kv := range set.KV {
kvdb.Set(kv.Key, kv.Value)
}
}
// 每次需要重新设置
acc := &types.Account{
Currency: 0,
Balance: total,
}
val := types.Encode(acc)
values := [][]byte{val}
api.On("StoreGet", mock.Anything).Return(&types.StoreReplyValue{Values:values}, nil).Once()
exec.SetAPI(api)
}
// check
// balance
accCoin := account.NewCoinsAccount()
accCoin.SetDB(stateDB)
account := accCoin.LoadExecAccount(AddrA, address.ExecAddress(auty.AutonomyX))
require.Equal(t, int64(0), account.Frozen)
account = accCoin.LoadExecAccount(autonomyAddr, address.ExecAddress(auty.AutonomyX))
require.Equal(t, int64(lockAmount), account.Balance)
// status
value, err := stateDB.Get(propBoardID(proposalID))
require.NoError(t, err)
cur := &auty.AutonomyProposalBoard{}
err = types.Decode(value, cur)
require.NoError(t, err)
require.Equal(t, int32(auty.AutonomyStatusTmintPropBoard), cur.Status)
require.Equal(t, AddrA, cur.Address)
require.Equal(t, true, cur.Res.Pass)
}
func voteProposalBoardTx(parm *auty.VoteProposalBoard) (*types.Transaction, error) { func voteProposalBoardTx(parm *auty.VoteProposalBoard) (*types.Transaction, error) {
if parm == nil { if parm == nil {
return nil, types.ErrInvalidParam return nil, types.ErrInvalidParam
...@@ -195,6 +358,57 @@ func voteProposalBoardTx(parm *auty.VoteProposalBoard) (*types.Transaction, erro ...@@ -195,6 +358,57 @@ func voteProposalBoardTx(parm *auty.VoteProposalBoard) (*types.Transaction, erro
return types.CreateFormatTx(types.ExecName(auty.AutonomyX), types.Encode(val)) return types.CreateFormatTx(types.ExecName(auty.AutonomyX), types.Encode(val))
} }
func terminateProposalBoard(t *testing.T, env *execEnv, exec drivers.Driver, stateDB dbm.KV, kvdb dbm.KVDB, save bool) {
api := new(apimock.QueueProtocolAPI)
api.On("StoreList", mock.Anything).Return(&types.StoreListReply{}, nil)
api.On("GetLastHeader", mock.Anything).Return(&types.Header{StateHash: []byte("")}, nil)
hear := &types.Header{StateHash: []byte("")}
api.On("GetHeaders", mock.Anything).
Return(&types.Headers{
Items:[]*types.Header{hear}}, nil)
acc := &types.Account{
Currency: 0,
Balance: total*4,
}
val := types.Encode(acc)
values := [][]byte{val}
api.On("StoreGet", mock.Anything).Return(&types.StoreReplyValue{Values:values}, nil).Once()
exec.SetAPI(api)
proposalID := env.txHash
opt := &auty.TerminateProposalBoard{
ProposalID:proposalID,
}
tx, err := terminateProposalBoardTx(opt)
require.NoError(t, err)
tx, err = signTx(tx, PrivKeyA)
require.NoError(t, err)
exec.SetEnv(env.endHeight+1, env.blockTime, env.difficulty)
receipt, err := exec.Exec(tx, int(1))
require.NoError(t, err)
require.NotNil(t, receipt)
if save {
for _, kv := range receipt.KV {
stateDB.Set(kv.Key, kv.Value)
}
}
receiptData := &types.ReceiptData{Ty: receipt.Ty, Logs: receipt.Logs}
set, err := exec.ExecLocal(tx, receiptData, int(1))
require.NoError(t, err)
require.NotNil(t, set)
if save {
for _, kv := range set.KV {
kvdb.Set(kv.Key, kv.Value)
}
}
// check
accCoin := account.NewCoinsAccount()
accCoin.SetDB(stateDB)
account := accCoin.LoadExecAccount(AddrA, address.ExecAddress(auty.AutonomyX))
require.Equal(t, int64(0), account.Frozen)
}
func terminateProposalBoardTx(parm *auty.TerminateProposalBoard) (*types.Transaction, error) { func terminateProposalBoardTx(parm *auty.TerminateProposalBoard) (*types.Transaction, error) {
if parm == nil { if parm == nil {
return nil, types.ErrInvalidParam return nil, types.ErrInvalidParam
...@@ -217,14 +431,22 @@ func TestGetStartHeightVoteAccount(t *testing.T) { ...@@ -217,14 +431,22 @@ func TestGetStartHeightVoteAccount(t *testing.T) {
addr := "1JmFaA6unrCFYEWPGRi7uuXY1KthTJxJEP" addr := "1JmFaA6unrCFYEWPGRi7uuXY1KthTJxJEP"
api.On("StoreList", mock.Anything).Return(&types.StoreListReply{}, nil) api.On("StoreList", mock.Anything).Return(&types.StoreListReply{}, nil)
api.On("GetLastHeader", mock.Anything).Return(&types.Header{StateHash: []byte("111111111111111111111")}, nil) api.On("GetLastHeader", mock.Anything).Return(&types.Header{StateHash: []byte("")}, nil)
api.On("StoreGet", mock.Anything).Return(&types.StoreReplyValue{Values: make([][]byte, 1)}, nil) acc := &types.Account{
hear := &types.Header{StateHash: []byte("111111111111111111111")} Currency: 0,
Balance: types.Coin,
}
val := types.Encode(acc)
values := [][]byte{val}
api.On("StoreGet", mock.Anything).Return(&types.StoreReplyValue{Values:values}, nil)
hear := &types.Header{StateHash: []byte("")}
api.On("GetHeaders", mock.Anything). api.On("GetHeaders", mock.Anything).
Return(&types.Headers{ Return(&types.Headers{
Items:[]*types.Header{hear}}, nil) Items:[]*types.Header{hear}}, nil)
_, err := action.getStartHeightVoteAccount(addr, 0) account, err := action.getStartHeightVoteAccount(addr, 0)
require.NoError(t, err) require.NoError(t, err)
require.NotNil(t, account)
require.Equal(t, types.Coin, account.Balance)
} }
func TestGetReceiptLog(t *testing.T) { func TestGetReceiptLog(t *testing.T) {
......
...@@ -17,6 +17,6 @@ var ( ...@@ -17,6 +17,6 @@ var (
ErrRevokeProposalPeriod = errors.New("ErrRevokeProposalPeriod") ErrRevokeProposalPeriod = errors.New("ErrRevokeProposalPeriod")
// ErrRevokeProposalPower 不能取消 // ErrRevokeProposalPower 不能取消
ErrRevokeProposalPower = errors.New("ErrRevokeProposalPower") ErrRevokeProposalPower = errors.New("ErrRevokeProposalPower")
// ErrRevokeProposal 不能取消 // ErrTerminatePeriod 不能终止
//ErrRevokeProposal = errors.New("ErrRevokeProposal") ErrTerminatePeriod = errors.New("ErrTerminatePeriod")
) )
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