Unverified Commit 36fdfd31 authored by vipwzw's avatar vipwzw Committed by GitHub

Merge pull request #597 from lyh169/autonomyV2

Autonomy v2
parents 03f50573 fb8defde
......@@ -31,6 +31,7 @@ func AutonomyCmd() *cobra.Command {
VoteProposalBoardCmd(),
TerminateProposalBoardCmd(),
ShowProposalBoardCmd(),
ShowActiveBoardCmd(),
)
// project
......@@ -50,6 +51,7 @@ func AutonomyCmd() *cobra.Command {
VoteProposalRuleCmd(),
TerminateProposalRuleCmd(),
ShowProposalRuleCmd(),
ShowActiveRuleCmd(),
)
cmd.AddCommand(
......@@ -58,6 +60,15 @@ func AutonomyCmd() *cobra.Command {
ShowProposalCommentCmd(),
)
// change
cmd.AddCommand(
ProposalChangeCmd(),
RevokeProposalChangeCmd(),
VoteProposalChangeCmd(),
TerminateProposalChangeCmd(),
ShowProposalChangeCmd(),
)
return cmd
}
......@@ -81,7 +92,7 @@ func addProposalBoardFlags(cmd *cobra.Command) {
cmd.Flags().Int64P("endBlock", "e", 0, "end block height")
cmd.MarkFlagRequired("endBlock")
cmd.Flags().StringP("boards", "b", "", "addr1-addr2......addrN (3<=N<=30)")
cmd.Flags().StringP("boards", "b", "", "addr1-addr2......addrN (20<=N<=40)")
cmd.MarkFlagRequired("boards")
}
......@@ -173,22 +184,30 @@ func addVoteProposalBoardFlags(cmd *cobra.Command) {
cmd.Flags().StringP("proposalID", "p", "", "proposal ID")
cmd.MarkFlagRequired("proposalID")
cmd.Flags().Int32P("approve", "r", 1, "is approve, default true")
cmd.Flags().StringP("originAddr", "o", "", "origin address: addr1-addr2......addrN")
}
func voteProposalBoard(cmd *cobra.Command, args []string) {
rpcLaddr, _ := cmd.Flags().GetString("rpc_laddr")
ID, _ := cmd.Flags().GetString("proposalID")
approve, _ := cmd.Flags().GetInt32("approve")
originAddr, _ := cmd.Flags().GetString("originAddr")
var isapp bool
if approve == 0 {
isapp = false
} else {
isapp = true
}
var originAddrs []string
if len(originAddr) > 0 {
originAddrs = strings.Split(originAddr, "-")
}
params := &auty.VoteProposalBoard{
ProposalID: ID,
Approve: isapp,
OriginAddr: originAddrs,
}
payLoad, err := json.Marshal(params)
if err != nil {
......@@ -246,7 +265,7 @@ func terminateProposalBoard(cmd *cobra.Command, args []string) {
// ShowProposalBoardCmd 显示提案查询信息
func ShowProposalBoardCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "showBoardInfo",
Use: "showBoard",
Short: "show proposal board info",
Run: showProposalBoard,
}
......@@ -305,3 +324,26 @@ func showProposalBoard(cmd *cobra.Command, args []string) {
ctx := jsonrpc.NewRPCCtx(rpcLaddr, "Chain33.Query", params, rep)
ctx.Run()
}
// ShowActiveBoardCmd 显示提案查询信息
func ShowActiveBoardCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "showActiveBoard",
Short: "show active board",
Run: showActiveBoard,
}
return cmd
}
func showActiveBoard(cmd *cobra.Command, args []string) {
rpcLaddr, _ := cmd.Flags().GetString("rpc_laddr")
params := rpctypes.Query4Jrpc{}
params.Execer = auty.AutonomyX
params.FuncName = auty.GetActiveBoard
params.Payload = types.MustPBToJSON(&types.ReqString{})
rep := &auty.ActiveBoard{}
ctx := jsonrpc.NewRPCCtx(rpcLaddr, "Chain33.Query", params, rep)
ctx.Run()
}
// 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 commands
import (
"strings"
"encoding/json"
jsonrpc "github.com/33cn/chain33/rpc/jsonclient"
rpctypes "github.com/33cn/chain33/rpc/types"
"github.com/33cn/chain33/types"
auty "github.com/33cn/plugin/plugin/dapp/autonomy/types"
"github.com/spf13/cobra"
)
// ProposalChangeCmd 创建提案命令
func ProposalChangeCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "proposalchange",
Short: "create proposal change",
Run: proposalChange,
}
addProposalChangeFlags(cmd)
return cmd
}
func addProposalChangeFlags(cmd *cobra.Command) {
cmd.Flags().Int32P("year", "y", 0, "year")
cmd.Flags().Int32P("month", "m", 0, "month")
cmd.Flags().Int32P("day", "d", 0, "day")
cmd.Flags().Int64P("startBlock", "s", 0, "start block height")
cmd.MarkFlagRequired("startBlock")
cmd.Flags().Int64P("endBlock", "e", 0, "end block height")
cmd.MarkFlagRequired("endBlock")
cmd.Flags().StringP("changes", "c", "", "addr1-true*addr2-false*addr3-true*......*addrN-false (1<=N<20)")
cmd.MarkFlagRequired("changes")
}
func proposalChange(cmd *cobra.Command, args []string) {
rpcLaddr, _ := cmd.Flags().GetString("rpc_laddr")
year, _ := cmd.Flags().GetInt32("year")
month, _ := cmd.Flags().GetInt32("month")
day, _ := cmd.Flags().GetInt32("day")
startBlock, _ := cmd.Flags().GetInt64("startBlock")
endBlock, _ := cmd.Flags().GetInt64("endBlock")
changestr, _ := cmd.Flags().GetString("changes")
changeStr := strings.Split(changestr, "*")
var changes []*auty.Change
for _, chStr := range changeStr {
per := strings.Split(chStr, "-")
if len(per) == 2 {
if per[1] == "true" {
change := &auty.Change{
Cancel: true,
Addr: per[0],
}
changes = append(changes, change)
} else if per[1] == "false" {
change := &auty.Change{
Cancel: false,
Addr: per[0],
}
changes = append(changes, change)
}
}
}
params := &auty.ProposalChange{
Year: year,
Month: month,
Day: day,
Changes: changes,
StartBlockHeight: startBlock,
EndBlockHeight: endBlock,
}
payLoad, err := json.Marshal(params)
if err != nil {
return
}
pm := &rpctypes.CreateTxIn{
Execer: types.ExecName(auty.AutonomyX),
ActionName: "PropChange",
Payload: payLoad,
}
var res string
ctx := jsonrpc.NewRPCCtx(rpcLaddr, "Chain33.CreateTransaction", pm, &res)
ctx.RunWithoutMarshal()
}
// RevokeProposalChangeCmd 撤销提案
func RevokeProposalChangeCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "revokeChange",
Short: "revoke proposal change",
Run: revokeProposalChange,
}
addRevokeProposalChangeFlags(cmd)
return cmd
}
func addRevokeProposalChangeFlags(cmd *cobra.Command) {
cmd.Flags().StringP("proposalID", "p", "", "proposal ID")
cmd.MarkFlagRequired("proposalID")
}
func revokeProposalChange(cmd *cobra.Command, args []string) {
rpcLaddr, _ := cmd.Flags().GetString("rpc_laddr")
ID, _ := cmd.Flags().GetString("proposalID")
params := &auty.RevokeProposalChange{
ProposalID: ID,
}
payLoad, err := json.Marshal(params)
if err != nil {
return
}
pm := &rpctypes.CreateTxIn{
Execer: types.ExecName(auty.AutonomyX),
ActionName: "RvkPropChange",
Payload: payLoad,
}
var res string
ctx := jsonrpc.NewRPCCtx(rpcLaddr, "Chain33.CreateTransaction", pm, &res)
ctx.RunWithoutMarshal()
}
// VoteProposalChangeCmd 投票提案
func VoteProposalChangeCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "voteChange",
Short: "vote proposal change",
Run: voteProposalChange,
}
addVoteProposalChangeFlags(cmd)
return cmd
}
func addVoteProposalChangeFlags(cmd *cobra.Command) {
cmd.Flags().StringP("proposalID", "p", "", "proposal ID")
cmd.MarkFlagRequired("proposalID")
cmd.Flags().Int32P("approve", "r", 1, "is approve, default true")
}
func voteProposalChange(cmd *cobra.Command, args []string) {
rpcLaddr, _ := cmd.Flags().GetString("rpc_laddr")
ID, _ := cmd.Flags().GetString("proposalID")
approve, _ := cmd.Flags().GetInt32("approve")
var isapp bool
if approve == 0 {
isapp = false
} else {
isapp = true
}
params := &auty.VoteProposalChange{
ProposalID: ID,
Approve: isapp,
}
payLoad, err := json.Marshal(params)
if err != nil {
return
}
pm := &rpctypes.CreateTxIn{
Execer: types.ExecName(auty.AutonomyX),
ActionName: "VotePropChange",
Payload: payLoad,
}
var res string
ctx := jsonrpc.NewRPCCtx(rpcLaddr, "Chain33.CreateTransaction", pm, &res)
ctx.RunWithoutMarshal()
}
// TerminateProposalChangeCmd 终止提案
func TerminateProposalChangeCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "terminateChange",
Short: "terminate proposal change",
Run: terminateProposalChange,
}
addTerminateProposalChangeFlags(cmd)
return cmd
}
func addTerminateProposalChangeFlags(cmd *cobra.Command) {
cmd.Flags().StringP("proposalID", "p", "", "proposal ID")
cmd.MarkFlagRequired("proposalID")
}
func terminateProposalChange(cmd *cobra.Command, args []string) {
rpcLaddr, _ := cmd.Flags().GetString("rpc_laddr")
ID, _ := cmd.Flags().GetString("proposalID")
params := &auty.RevokeProposalChange{
ProposalID: ID,
}
payLoad, err := json.Marshal(params)
if err != nil {
return
}
pm := &rpctypes.CreateTxIn{
Execer: types.ExecName(auty.AutonomyX),
ActionName: "TmintPropChange",
Payload: payLoad,
}
var res string
ctx := jsonrpc.NewRPCCtx(rpcLaddr, "Chain33.CreateTransaction", pm, &res)
ctx.RunWithoutMarshal()
}
// ShowProposalChangeCmd 显示提案查询信息
func ShowProposalChangeCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "showChange",
Short: "show proposal change info",
Run: showProposalChange,
}
addShowProposalChangeflags(cmd)
return cmd
}
func addShowProposalChangeflags(cmd *cobra.Command) {
cmd.Flags().Uint32P("type", "y", 0, "type(0:query by hash; 1:list)")
cmd.MarkFlagRequired("type")
cmd.Flags().StringP("proposalID", "p", "", "proposal ID")
cmd.Flags().Uint32P("status", "s", 0, "status")
cmd.Flags().StringP("addr", "a", "", "address")
cmd.Flags().Int32P("count", "c", 1, "count, default is 1")
cmd.Flags().Int32P("direction", "d", -1, "direction, default is reserve")
cmd.Flags().Int64P("height", "t", -1, "height, default is -1")
cmd.Flags().Int32P("index", "i", -1, "index, default is -1")
}
func showProposalChange(cmd *cobra.Command, args []string) {
rpcLaddr, _ := cmd.Flags().GetString("rpc_laddr")
typ, _ := cmd.Flags().GetUint32("type")
propID, _ := cmd.Flags().GetString("proposalID")
status, _ := cmd.Flags().GetUint32("status")
addr, _ := cmd.Flags().GetString("addr")
count, _ := cmd.Flags().GetInt32("count")
direction, _ := cmd.Flags().GetInt32("direction")
height, _ := cmd.Flags().GetInt64("height")
index, _ := cmd.Flags().GetInt32("index")
var params rpctypes.Query4Jrpc
var rep interface{}
params.Execer = auty.AutonomyX
if 0 == typ {
req := types.ReqString{
Data: propID,
}
params.FuncName = auty.GetProposalChange
params.Payload = types.MustPBToJSON(&req)
} else if 1 == typ {
req := auty.ReqQueryProposalChange{
Status: int32(status),
Addr: addr,
Count: count,
Direction: direction,
Height: height,
Index: index,
}
params.FuncName = auty.ListProposalChange
params.Payload = types.MustPBToJSON(&req)
}
rep = &auty.ReplyQueryProposalChange{}
ctx := jsonrpc.NewRPCCtx(rpcLaddr, "Chain33.Query", params, rep)
ctx.Run()
}
......@@ -7,6 +7,8 @@ package commands
import (
"encoding/json"
"strings"
jsonrpc "github.com/33cn/chain33/rpc/jsonclient"
rpctypes "github.com/33cn/chain33/rpc/types"
"github.com/33cn/chain33/types"
......@@ -200,13 +202,15 @@ func PubVoteProposalProjectCmd() *cobra.Command {
func addPubVoteProposalProjectFlags(cmd *cobra.Command) {
cmd.Flags().StringP("proposalID", "p", "", "proposal ID")
cmd.MarkFlagRequired("proposalID")
cmd.Flags().Int32P("oppose", "o", 1, "is oppose, default true")
cmd.Flags().Int32P("oppose", "s", 1, "is oppose, default true")
cmd.Flags().StringP("originAddr", "o", "", "origin address: addr1-addr2......addrN")
}
func pubVoteProposalProject(cmd *cobra.Command, args []string) {
rpcLaddr, _ := cmd.Flags().GetString("rpc_laddr")
ID, _ := cmd.Flags().GetString("proposalID")
oppose, _ := cmd.Flags().GetInt32("oppose")
originAddr, _ := cmd.Flags().GetString("originAddr")
var isopp bool
if oppose == 0 {
......@@ -215,9 +219,15 @@ func pubVoteProposalProject(cmd *cobra.Command, args []string) {
isopp = true
}
var originAddrs []string
if len(originAddr) > 0 {
originAddrs = strings.Split(originAddr, "-")
}
params := &auty.PubVoteProposalProject{
ProposalID: ID,
Oppose: isopp,
OriginAddr: originAddrs,
}
payLoad, err := json.Marshal(params)
if err != nil {
......@@ -273,7 +283,7 @@ func terminateProposalProject(cmd *cobra.Command, args []string) {
// ShowProposalProjectCmd 显示提案查询信息
func ShowProposalProjectCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "showProjectInfo",
Use: "showProject",
Short: "show proposal project info",
Run: showProposalProject,
}
......
......@@ -7,6 +7,8 @@ package commands
import (
"encoding/json"
"strings"
jsonrpc "github.com/33cn/chain33/rpc/jsonclient"
rpctypes "github.com/33cn/chain33/rpc/types"
"github.com/33cn/chain33/types"
......@@ -52,7 +54,6 @@ func proposalRule(cmd *cobra.Command, args []string) {
startBlock, _ := cmd.Flags().GetInt64("startBlock")
endBlock, _ := cmd.Flags().GetInt64("endBlock")
boardAttendRatio, _ := cmd.Flags().GetInt32("boardAttendRatio")
boardApproveRatio, _ := cmd.Flags().GetInt32("boardApproveRatio")
pubOpposeRatio, _ := cmd.Flags().GetInt32("pubOpposeRatio")
......@@ -65,7 +66,6 @@ func proposalRule(cmd *cobra.Command, args []string) {
Month: month,
Day: day,
RuleCfg: &auty.RuleConfig{
BoardAttendRatio: boardAttendRatio,
BoardApproveRatio: boardApproveRatio,
PubOpposeRatio: pubOpposeRatio,
ProposalAmount: proposalAmount * types.Coin,
......@@ -142,12 +142,14 @@ func addVoteProposalRuleFlags(cmd *cobra.Command) {
cmd.Flags().StringP("proposalID", "p", "", "proposal ID")
cmd.MarkFlagRequired("proposalID")
cmd.Flags().Int32P("approve", "r", 1, "is approve, default true")
cmd.Flags().StringP("originAddr", "o", "", "origin address: addr1-addr2......addrN")
}
func voteProposalRule(cmd *cobra.Command, args []string) {
rpcLaddr, _ := cmd.Flags().GetString("rpc_laddr")
ID, _ := cmd.Flags().GetString("proposalID")
approve, _ := cmd.Flags().GetInt32("approve")
originAddr, _ := cmd.Flags().GetString("originAddr")
var isapp bool
if approve == 0 {
isapp = false
......@@ -155,9 +157,15 @@ func voteProposalRule(cmd *cobra.Command, args []string) {
isapp = true
}
var originAddrs []string
if len(originAddr) > 0 {
originAddrs = strings.Split(originAddr, "-")
}
params := &auty.VoteProposalRule{
ProposalID: ID,
Approve: isapp,
OriginAddr: originAddrs,
}
payLoad, err := json.Marshal(params)
if err != nil {
......@@ -213,7 +221,7 @@ func terminateProposalRule(cmd *cobra.Command, args []string) {
// ShowProposalRuleCmd 显示提案查询信息
func ShowProposalRuleCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "showRuleInfo",
Use: "showRule",
Short: "show proposal rule info",
Run: showProposalRule,
}
......@@ -273,6 +281,29 @@ func showProposalRule(cmd *cobra.Command, args []string) {
ctx.Run()
}
// ShowActiveRuleCmd 显示提案查询信息
func ShowActiveRuleCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "showActiveRule",
Short: "show active rule",
Run: showActiveRule,
}
return cmd
}
func showActiveRule(cmd *cobra.Command, args []string) {
rpcLaddr, _ := cmd.Flags().GetString("rpc_laddr")
params := rpctypes.Query4Jrpc{}
params.Execer = auty.AutonomyX
params.FuncName = auty.GetActiveRule
params.Payload = types.MustPBToJSON(&types.ReqString{})
rep := &auty.RuleConfig{}
ctx := jsonrpc.NewRPCCtx(rpcLaddr, "Chain33.Query", params, rep)
ctx.Run()
}
// TransferFundCmd 资金转入自治系统合约中
func TransferFundCmd() *cobra.Command {
cmd := &cobra.Command{
......
......@@ -134,3 +134,16 @@ func (a *Autonomy) listProposalBoard(req *auty.ReqQueryProposalBoard) (types.Mes
}
return &rep, nil
}
func (a *Autonomy) getActiveBoard() (types.Message, error) {
value, err := a.GetStateDB().Get(activeBoardID())
if err != nil {
return nil, err
}
prop := &auty.ActiveBoard{}
err = types.Decode(value, prop)
if err != nil {
return nil, err
}
return prop, nil
}
......@@ -13,7 +13,6 @@ import (
"github.com/33cn/chain33/util"
auty "github.com/33cn/plugin/plugin/dapp/autonomy/types"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestExecLocalBoard(t *testing.T) {
......@@ -49,14 +48,14 @@ func testexecLocalBoard(t *testing.T, auto bool) {
var err error
if !auto {
set, err = au.execLocalBoard(receipt)
require.NoError(t, err)
require.NotNil(t, set)
assert.NoError(t, err)
assert.NotNil(t, set)
} else {
tx, err := types.CreateFormatTx(types.ExecName(auty.AutonomyX), nil)
assert.NoError(t, err)
set, err = au.execAutoLocalBoard(tx, receipt)
require.NoError(t, err)
require.NotNil(t, set)
assert.NoError(t, err)
assert.NotNil(t, set)
}
//save to database
......@@ -78,8 +77,8 @@ func testexecLocalBoard(t *testing.T, auto bool) {
{Ty: auty.TyLogRvkPropBoard, Log: types.Encode(receiptBoard1)},
},
})
require.NoError(t, err)
require.NotNil(t, set)
assert.NoError(t, err)
assert.NotNil(t, set)
} else {
tx, err := types.CreateFormatTx(types.ExecName(auty.AutonomyX), nil)
assert.NoError(t, err)
......@@ -89,8 +88,8 @@ func testexecLocalBoard(t *testing.T, auto bool) {
{Ty: auty.TyLogRvkPropBoard, Log: types.Encode(receiptBoard1)},
},
})
require.NoError(t, err)
require.NotNil(t, set)
assert.NoError(t, err)
assert.NotNil(t, set)
}
//save to database
......@@ -114,8 +113,8 @@ func testexecLocalBoard(t *testing.T, auto bool) {
{Ty: auty.TyLogVotePropBoard, Log: types.Encode(receiptBoard2)},
},
})
require.NoError(t, err)
require.NotNil(t, set)
assert.NoError(t, err)
assert.NotNil(t, set)
} else {
tx, err := types.CreateFormatTx(types.ExecName(auty.AutonomyX), nil)
assert.NoError(t, err)
......@@ -125,8 +124,8 @@ func testexecLocalBoard(t *testing.T, auto bool) {
{Ty: auty.TyLogVotePropBoard, Log: types.Encode(receiptBoard2)},
},
})
require.NoError(t, err)
require.NotNil(t, set)
assert.NoError(t, err)
assert.NotNil(t, set)
}
//save to database
......@@ -168,13 +167,13 @@ func testexecDelLocalBoard(t *testing.T) {
tx, err := types.CreateFormatTx(types.ExecName(auty.AutonomyX), nil)
assert.NoError(t, err)
set, err := au.execAutoLocalBoard(tx, receipt)
require.NoError(t, err)
require.NotNil(t, set)
assert.NoError(t, err)
assert.NotNil(t, set)
saveKvs(sdb, set.KV)
set, err = au.execAutoDelLocal(tx, receipt)
require.NoError(t, err)
require.NotNil(t, set)
assert.NoError(t, err)
assert.NotNil(t, set)
saveKvs(sdb, set.KV)
// check
......@@ -206,8 +205,8 @@ func testexecDelLocalBoard(t *testing.T) {
tx, err = types.CreateFormatTx(types.ExecName(auty.AutonomyX), nil)
assert.NoError(t, err)
set, err = au.execAutoLocalBoard(tx, receipt)
require.NoError(t, err)
require.NotNil(t, set)
assert.NoError(t, err)
assert.NotNil(t, set)
saveKvs(sdb, set.KV)
// 正常测试退回
......@@ -215,15 +214,15 @@ func testexecDelLocalBoard(t *testing.T) {
assert.NoError(t, err)
set, err = au.execAutoLocalBoard(tx, recpt)
require.NoError(t, err)
require.NotNil(t, set)
assert.NoError(t, err)
assert.NotNil(t, set)
saveKvs(sdb, set.KV)
// check
checkExecLocalBoard(t, kvdb, cur)
set, err = au.execAutoDelLocal(tx, recpt)
require.NoError(t, err)
require.NotNil(t, set)
assert.NoError(t, err)
assert.NotNil(t, set)
saveKvs(sdb, set.KV)
// check
checkExecLocalBoard(t, kvdb, pre1)
......@@ -238,9 +237,9 @@ func TestGetProposalBoard(t *testing.T) {
tx := "1111111111111111111"
storedb.Set(propBoardID(tx), types.Encode(&auty.AutonomyProposalBoard{}))
rsp, err := au.getProposalBoard(&types.ReqString{Data: tx})
require.NoError(t, err)
require.NotNil(t, rsp)
require.Equal(t, len(rsp.(*auty.ReplyQueryProposalBoard).PropBoards), 1)
assert.NoError(t, err)
assert.NotNil(t, rsp)
assert.Equal(t, len(rsp.(*auty.ReplyQueryProposalBoard).PropBoards), 1)
}
func TestListProposalBoard(t *testing.T) {
......@@ -288,9 +287,9 @@ func TestListProposalBoard(t *testing.T) {
cur.Index = int32(tcase.index)
err := table.Replace(cur)
require.NoError(t, err)
assert.NoError(t, err)
kv, err := table.Save()
require.NoError(t, err)
assert.NoError(t, err)
kvs = append(kvs, kv...)
}
......@@ -303,12 +302,12 @@ func TestListProposalBoard(t *testing.T) {
Index: -1,
}
rsp, err := au.listProposalBoard(req)
require.NoError(t, err)
require.Equal(t, len(rsp.(*auty.ReplyQueryProposalBoard).PropBoards), len(testcase2))
assert.NoError(t, err)
assert.Equal(t, len(rsp.(*auty.ReplyQueryProposalBoard).PropBoards), len(testcase2))
k := 2
for _, tcase := range testcase2 {
require.Equal(t, rsp.(*auty.ReplyQueryProposalBoard).PropBoards[k].Height, tcase.height)
require.Equal(t, rsp.(*auty.ReplyQueryProposalBoard).PropBoards[k].Index, int32(tcase.index))
assert.Equal(t, rsp.(*auty.ReplyQueryProposalBoard).PropBoards[k].Height, tcase.height)
assert.Equal(t, rsp.(*auty.ReplyQueryProposalBoard).PropBoards[k].Index, int32(tcase.index))
k--
}
......@@ -320,11 +319,11 @@ func TestListProposalBoard(t *testing.T) {
Index: -1,
}
rsp, err = au.listProposalBoard(req)
require.NoError(t, err)
require.Equal(t, len(rsp.(*auty.ReplyQueryProposalBoard).PropBoards), len(testcase2))
assert.NoError(t, err)
assert.Equal(t, len(rsp.(*auty.ReplyQueryProposalBoard).PropBoards), len(testcase2))
for i, tcase := range testcase2 {
require.Equal(t, rsp.(*auty.ReplyQueryProposalBoard).PropBoards[i].Height, tcase.height)
require.Equal(t, rsp.(*auty.ReplyQueryProposalBoard).PropBoards[i].Index, int32(tcase.index))
assert.Equal(t, rsp.(*auty.ReplyQueryProposalBoard).PropBoards[i].Height, tcase.height)
assert.Equal(t, rsp.(*auty.ReplyQueryProposalBoard).PropBoards[i].Index, int32(tcase.index))
}
// 翻页查找
......@@ -335,12 +334,12 @@ func TestListProposalBoard(t *testing.T) {
Index: -1,
}
rsp, err = au.listProposalBoard(req)
require.NoError(t, err)
require.Equal(t, len(rsp.(*auty.ReplyQueryProposalBoard).PropBoards), 1)
assert.NoError(t, err)
assert.Equal(t, len(rsp.(*auty.ReplyQueryProposalBoard).PropBoards), 1)
height := rsp.(*auty.ReplyQueryProposalBoard).PropBoards[0].Height
index := rsp.(*auty.ReplyQueryProposalBoard).PropBoards[0].Index
require.Equal(t, height, testcase2[2].height)
require.Equal(t, index, int32(testcase2[2].index))
assert.Equal(t, height, testcase2[2].height)
assert.Equal(t, index, int32(testcase2[2].index))
//
req = &auty.ReqQueryProposalBoard{
Status: auty.AutonomyStatusProposalBoard,
......@@ -350,12 +349,25 @@ func TestListProposalBoard(t *testing.T) {
Index: index,
}
rsp, err = au.listProposalBoard(req)
require.NoError(t, err)
require.Equal(t, len(rsp.(*auty.ReplyQueryProposalBoard).PropBoards), 2)
require.Equal(t, rsp.(*auty.ReplyQueryProposalBoard).PropBoards[0].Height, testcase2[1].height)
require.Equal(t, rsp.(*auty.ReplyQueryProposalBoard).PropBoards[0].Index, int32(testcase2[1].index))
require.Equal(t, rsp.(*auty.ReplyQueryProposalBoard).PropBoards[1].Height, testcase2[0].height)
require.Equal(t, rsp.(*auty.ReplyQueryProposalBoard).PropBoards[1].Index, int32(testcase2[0].index))
assert.NoError(t, err)
assert.Equal(t, len(rsp.(*auty.ReplyQueryProposalBoard).PropBoards), 2)
assert.Equal(t, rsp.(*auty.ReplyQueryProposalBoard).PropBoards[0].Height, testcase2[1].height)
assert.Equal(t, rsp.(*auty.ReplyQueryProposalBoard).PropBoards[0].Index, int32(testcase2[1].index))
assert.Equal(t, rsp.(*auty.ReplyQueryProposalBoard).PropBoards[1].Height, testcase2[0].height)
assert.Equal(t, rsp.(*auty.ReplyQueryProposalBoard).PropBoards[1].Index, int32(testcase2[0].index))
}
func TestGetActiveBoard(t *testing.T) {
au := &Autonomy{
dapp.DriverBase{},
}
_, storedb, _ := util.CreateTestDB()
au.SetStateDB(storedb)
storedb.Set(activeBoardID(), types.Encode(&auty.ActiveBoard{Boards: []string{"111"}}))
rsp, err := au.getActiveBoard()
assert.NoError(t, err)
assert.NotNil(t, rsp)
assert.Equal(t, len(rsp.(*auty.ActiveBoard).Boards), 1)
}
func checkExecLocalBoard(t *testing.T, kvdb db.KVDB, cur *auty.AutonomyProposalBoard) {
......
......@@ -14,20 +14,22 @@ import (
auty "github.com/33cn/plugin/plugin/dapp/autonomy/types"
"github.com/33cn/chain33/common/address"
ticket "github.com/33cn/plugin/plugin/dapp/ticket/executor"
ticketTy "github.com/33cn/plugin/plugin/dapp/ticket/types"
)
const (
minBoards = 3
maxBoards = 30
publicPeriod int32 = 120960 // 公示一周时间,以区块高度计算
ticketPrice = types.Coin * 3000 // 单张票价
largeProjectAmount = types.Coin * 100 * 10000 // 重大项目公示金额阈值
proposalAmount = types.Coin * 1000 // 创建者消耗金额
boardAttendRatio int32 = 66 // 董事会成员参与率,以%计,可修改
boardApproveRatio int32 = 66 // 董事会成员赞成率,以%计,可修改
pubAttendRatio int32 = 50 // 全体持票人参与率,以%计
pubApproveRatio int32 = 50 // 全体持票人赞成率,以%计
pubOpposeRatio int32 = 33 // 全体持票人否决率,以%计
minBoards = 20
maxBoards = 40
publicPeriod int32 = 17280 * 7 // 公示一周时间,以区块高度计算
ticketPrice = types.Coin * 3000 // 单张票价
largeProjectAmount = types.Coin * 100 * 10000 // 重大项目公示金额阈值
proposalAmount = types.Coin * 500 // 创建者消耗金额
boardApproveRatio int32 = 66 // 董事会成员赞成率,以%计,可修改
pubAttendRatio int32 = 75 // 全体持票人参与率,以%计
pubApproveRatio int32 = 66 // 全体持票人赞成率,以%计
pubOpposeRatio int32 = 33 // 全体持票人否决率,以%计
startEndBlockPeriod = 720 // 提案开始结束最小周期
)
type action struct {
......@@ -55,17 +57,26 @@ func (a *action) propBoard(prob *auty.ProposalBoard) (*types.Receipt, error) {
return nil, types.ErrInvalidParam
}
if prob.StartBlockHeight < a.height || prob.EndBlockHeight < a.height {
if prob.StartBlockHeight < a.height || prob.EndBlockHeight < a.height ||
prob.StartBlockHeight+startEndBlockPeriod > prob.EndBlockHeight {
alog.Error("propBoard height invaild", "StartBlockHeight", prob.StartBlockHeight, "EndBlockHeight",
prob.EndBlockHeight, "height", a.height)
return nil, types.ErrInvalidParam
}
mpBd := make(map[string]struct{})
for _, board := range prob.Boards {
if err := address.CheckAddress(board); err != nil {
alog.Error("propBoard ", "addr", board, "check toAddr error", err)
return nil, types.ErrInvalidAddress
}
// 提案board重复地址去重复
if _, ok := mpBd[board]; ok {
err := auty.ErrRepeatAddr
alog.Error("propBoard ", "addr", board, "propBoard have repeat addr ", err)
return nil, err
}
mpBd[board] = struct{}{}
}
// 获取当前生效提案规则
......@@ -187,15 +198,39 @@ func (a *action) votePropBoard(voteProb *auty.VoteProposalBoard) (*types.Receipt
return nil, err
}
if len(voteProb.OriginAddr) > 0 {
for _, board := range voteProb.OriginAddr {
if err := address.CheckAddress(board); err != nil {
alog.Error("votePropBoard ", "addr", board, "check toAddr error", err)
return nil, types.ErrInvalidAddress
}
}
// 挖矿地址验证
addr, err := a.verifyMinerAddr(voteProb.OriginAddr, a.fromaddr)
if err != nil {
alog.Error("votePropBoard ", "from addr", a.fromaddr, "error addr", addr, "ProposalID",
voteProb.ProposalID, "err", err)
return nil, err
}
}
// 本次参与投票地址
var addrs []string
if len(voteProb.OriginAddr) == 0 {
addrs = append(addrs, a.fromaddr)
} else {
addrs = append(addrs, voteProb.OriginAddr...)
}
// 检查是否已经参与投票
votes, err := a.checkVotesRecord(votesRecord(voteProb.ProposalID))
votes, err := a.checkVotesRecord(addrs, votesRecord(voteProb.ProposalID))
if err != nil {
alog.Error("votePropBoard ", "addr", a.fromaddr, "execaddr", a.execaddr, "checkVotesRecord failed",
voteProb.ProposalID, "err", err)
return nil, err
}
// 更新投票记录
votes.Address = append(votes.Address, a.fromaddr)
votes.Address = append(votes.Address, addrs...)
if cur.GetVoteResult().TotalVotes == 0 { //需要统计票数
vtCouts, err := a.getTotalVotes(start)
......@@ -205,8 +240,10 @@ func (a *action) votePropBoard(voteProb *auty.VoteProposalBoard) (*types.Receipt
cur.VoteResult.TotalVotes = vtCouts
}
vtCouts, err := a.getAddressVotes(a.fromaddr, start)
vtCouts, err := a.batchGetAddressVotes(addrs, start)
if err != nil {
alog.Error("votePropBoard ", "addr", a.fromaddr, "execaddr", a.execaddr, "batchGetAddressVotes failed",
voteProb.ProposalID, "err", err)
return nil, err
}
if voteProb.Approve {
......@@ -249,7 +286,11 @@ func (a *action) votePropBoard(voteProb *auty.VoteProposalBoard) (*types.Receipt
// 更新当前具有权利的董事会成员
if cur.VoteResult.Pass {
kv = append(kv, &types.KeyValue{Key: activeBoardID(), Value: types.Encode(cur.PropBoard)})
act := &auty.ActiveBoard{
Boards: cur.PropBoard.Boards,
StartHeight: a.height,
}
kv = append(kv, &types.KeyValue{Key: activeBoardID(), Value: types.Encode(act)})
}
ty := auty.TyLogVotePropBoard
......@@ -325,7 +366,11 @@ func (a *action) tmintPropBoard(tmintProb *auty.TerminateProposalBoard) (*types.
// 更新当前具有权利的董事会成员
if cur.VoteResult.Pass {
kv = append(kv, &types.KeyValue{Key: activeBoardID(), Value: types.Encode(cur.PropBoard)})
act := &auty.ActiveBoard{
Boards: cur.PropBoard.Boards,
StartHeight: a.height,
}
kv = append(kv, &types.KeyValue{Key: activeBoardID(), Value: types.Encode(act)})
}
receiptLog := getReceiptLog(pre, cur, auty.TyLogTmintPropBoard)
......@@ -346,6 +391,34 @@ func (a *action) getTotalVotes(height int64) (int32, error) {
return int32(account.Balance / ticketPrice), nil
}
func (a *action) verifyMinerAddr(addrs []string, bindAddr string) (string, error) {
// 验证绑定关系
for _, addr := range addrs {
value, err := a.db.Get(ticket.BindKey(addr))
if err != nil {
return addr, auty.ErrMinerAddr
}
tkBind := &ticketTy.TicketBind{}
err = types.Decode(value, tkBind)
if err != nil || tkBind.MinerAddress != bindAddr {
return addr, auty.ErrBindAddr
}
}
return "", nil
}
func (a *action) batchGetAddressVotes(addrs []string, height int64) (int32, error) {
total := int32(0)
for _, addr := range addrs {
count, err := a.getAddressVotes(addr, height)
if err != nil {
return 0, err
}
total += count
}
return total, nil
}
func (a *action) getAddressVotes(addr string, height int64) (int32, error) {
account, err := a.getStartHeightVoteAccount(addr, auty.TicketX, height)
if err != nil {
......@@ -406,7 +479,6 @@ func (a *action) getActiveRule() (*auty.RuleConfig, error) {
return nil, err
}
} else { // 载入系统默认值
rule.BoardAttendRatio = boardAttendRatio
rule.BoardApproveRatio = boardApproveRatio
rule.PubOpposeRatio = pubOpposeRatio
rule.ProposalAmount = proposalAmount
......@@ -416,7 +488,7 @@ func (a *action) getActiveRule() (*auty.RuleConfig, error) {
return rule, nil
}
func (a *action) checkVotesRecord(key []byte) (*auty.VotesRecord, error) {
func (a *action) checkVotesRecord(addrs []string, key []byte) (*auty.VotesRecord, error) {
var votes auty.VotesRecord
value, err := a.db.Get(key)
if err == nil {
......@@ -425,10 +497,15 @@ func (a *action) checkVotesRecord(key []byte) (*auty.VotesRecord, error) {
return nil, err
}
}
mp := make(map[string]struct{}, len(addrs))
for _, addr := range addrs {
mp[addr] = struct{}{}
}
// 检查是否有重复
for _, addr := range votes.Address {
if addr == a.fromaddr {
if _, ok := mp[addr]; ok {
err := auty.ErrRepeatVoteAddr
alog.Error("autonomy ", "addr", addr, "err", err)
return nil, err
}
}
......
// Copyright Fuzamei Corp. 2018 All Rights Reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package executor
import (
"github.com/33cn/chain33/system/dapp"
"github.com/33cn/chain33/types"
auty "github.com/33cn/plugin/plugin/dapp/autonomy/types"
)
func (a *Autonomy) execAutoLocalChange(tx *types.Transaction, receiptData *types.ReceiptData) (*types.LocalDBSet, error) {
set, err := a.execLocalChange(receiptData)
if err != nil {
return set, err
}
dbSet := &types.LocalDBSet{}
dbSet.KV = a.AddRollbackKV(tx, tx.Execer, set.KV)
return dbSet, nil
}
func (a *Autonomy) execLocalChange(receiptData *types.ReceiptData) (*types.LocalDBSet, error) {
table := NewChangeTable(a.GetLocalDB())
for _, log := range receiptData.Logs {
switch log.Ty {
case auty.TyLogPropChange,
auty.TyLogRvkPropChange,
auty.TyLogVotePropChange,
auty.TyLogTmintPropChange:
{
var receipt auty.ReceiptProposalChange
err := types.Decode(log.Log, &receipt)
if err != nil {
return nil, err
}
err = table.Replace(receipt.Current)
if err != nil {
return nil, err
}
}
default:
break
}
}
kvs, err := table.Save()
if err != nil {
return nil, err
}
dbSet := &types.LocalDBSet{}
dbSet.KV = append(dbSet.KV, kvs...)
return dbSet, nil
}
func (a *Autonomy) getProposalChange(req *types.ReqString) (types.Message, error) {
if req == nil {
return nil, types.ErrInvalidParam
}
value, err := a.GetStateDB().Get(propChangeID(req.Data))
if err != nil {
return nil, err
}
prop := &auty.AutonomyProposalChange{}
err = types.Decode(value, prop)
if err != nil {
return nil, err
}
rep := &auty.ReplyQueryProposalChange{}
rep.PropChanges = append(rep.PropChanges, prop)
return rep, nil
}
func (a *Autonomy) listProposalChange(req *auty.ReqQueryProposalChange) (types.Message, error) {
if req == nil {
return nil, types.ErrInvalidParam
}
localDb := a.GetLocalDB()
query := NewChangeTable(localDb).GetQuery(localDb)
var primary []byte
if req.Height > 0 {
primary = []byte(dapp.HeightIndexStr(req.Height, int64(req.Index)))
}
indexName := ""
if req.Status > 0 && req.Addr != "" {
indexName = "addr_status"
} else if req.Status > 0 {
indexName = "status"
} else if req.Addr != "" {
indexName = "addr"
}
cur := &ChangeRow{
AutonomyProposalChange: &auty.AutonomyProposalChange{},
}
cur.Address = req.Addr
cur.Status = req.Status
cur.Height = req.Height
cur.Index = req.Index
prefix, err := cur.Get(indexName)
if err != nil {
alog.Error("Get", "indexName", indexName, "err", err)
return nil, err
}
rows, err := query.ListIndex(indexName, prefix, primary, req.Count, req.Direction)
if err != nil {
alog.Error("query List failed", "indexName", indexName, "prefix", "prefix", "key", string(primary), "err", err)
return nil, err
}
if len(rows) == 0 {
return nil, types.ErrNotFound
}
var rep auty.ReplyQueryProposalChange
for _, row := range rows {
r, ok := row.Data.(*auty.AutonomyProposalChange)
if !ok {
alog.Error("listProposalChange", "err", "bad row type")
return nil, types.ErrDecode
}
rep.PropChanges = append(rep.PropChanges, r)
}
return &rep, nil
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
package executor
import (
"fmt"
"github.com/33cn/chain33/common/db"
"github.com/33cn/chain33/common/db/table"
"github.com/33cn/chain33/system/dapp"
"github.com/33cn/chain33/types"
auty "github.com/33cn/plugin/plugin/dapp/autonomy/types"
)
/*
table struct
data: autonomy change
index: status, addr
*/
var changeOpt = &table.Option{
Prefix: "LODB-autonomy",
Name: "change",
Primary: "heightindex",
Index: []string{"addr", "status", "addr_status"},
}
//NewChangeTable 新建表
func NewChangeTable(kvdb db.KV) *table.Table {
rowmeta := NewChangeRow()
table, err := table.NewTable(rowmeta, kvdb, changeOpt)
if err != nil {
panic(err)
}
return table
}
//ChangeRow table meta 结构
type ChangeRow struct {
*auty.AutonomyProposalChange
}
//NewChangeRow 新建一个meta 结构
func NewChangeRow() *ChangeRow {
return &ChangeRow{AutonomyProposalChange: &auty.AutonomyProposalChange{}}
}
//CreateRow 新建数据行(注意index 数据一定也要保存到数据中,不能就保存heightindex)
func (r *ChangeRow) CreateRow() *table.Row {
return &table.Row{Data: &auty.AutonomyProposalChange{}}
}
//SetPayload 设置数据
func (r *ChangeRow) SetPayload(data types.Message) error {
if d, ok := data.(*auty.AutonomyProposalChange); ok {
r.AutonomyProposalChange = d
return nil
}
return types.ErrTypeAsset
}
//Get 按照indexName 查询 indexValue
func (r *ChangeRow) Get(key string) ([]byte, error) {
if key == "heightindex" {
return []byte(dapp.HeightIndexStr(r.Height, int64(r.Index))), nil
} else if key == "status" {
return []byte(fmt.Sprintf("%2d", r.Status)), nil
} else if key == "addr" {
return []byte(r.Address), nil
} else if key == "addr_status" {
return []byte(fmt.Sprintf("%s:%2d", r.Address, r.Status)), nil
}
return nil, types.ErrNotFound
}
......@@ -104,3 +104,29 @@ func (a *Autonomy) Exec_CommentProp(payload *auty.Comment, tx *types.Transaction
action := newAction(a, tx, int32(index))
return action.commentProp(payload)
}
// 提案修改董事会成员相关
// Exec_PropChange 创建提案规则
func (a *Autonomy) Exec_PropChange(payload *auty.ProposalChange, tx *types.Transaction, index int) (*types.Receipt, error) {
action := newAction(a, tx, int32(index))
return action.propChange(payload)
}
// Exec_RvkPropChange 撤销提案规则
func (a *Autonomy) Exec_RvkPropChange(payload *auty.RevokeProposalChange, tx *types.Transaction, index int) (*types.Receipt, error) {
action := newAction(a, tx, int32(index))
return action.rvkPropChange(payload)
}
// Exec_VotePropChange 投票提案规则
func (a *Autonomy) Exec_VotePropChange(payload *auty.VoteProposalChange, tx *types.Transaction, index int) (*types.Receipt, error) {
action := newAction(a, tx, int32(index))
return action.votePropChange(payload)
}
// Exec_TmintPropChange 终止提案规则
func (a *Autonomy) Exec_TmintPropChange(payload *auty.TerminateProposalChange, tx *types.Transaction, index int) (*types.Receipt, error) {
action := newAction(a, tx, int32(index))
return action.tmintPropChange(payload)
}
......@@ -84,3 +84,25 @@ func (a *Autonomy) ExecLocal_TmintPropRule(payload *auty.TerminateProposalRule,
func (a *Autonomy) ExecLocal_CommentProp(payload *auty.Comment, tx *types.Transaction, receiptData *types.ReceiptData, index int) (*types.LocalDBSet, error) {
return a.execAutoLocalCommentProp(tx, receiptData)
}
// 提案修改董事会成员相关
// ExecLocal_PropChange 创建提案规则
func (a *Autonomy) ExecLocal_PropChange(payload *auty.ProposalChange, tx *types.Transaction, receiptData *types.ReceiptData, index int) (*types.LocalDBSet, error) {
return a.execAutoLocalChange(tx, receiptData)
}
// ExecLocal_RvkPropChange 撤销提案规则
func (a *Autonomy) ExecLocal_RvkPropChange(payload *auty.RevokeProposalChange, tx *types.Transaction, receiptData *types.ReceiptData, index int) (*types.LocalDBSet, error) {
return a.execAutoLocalChange(tx, receiptData)
}
// ExecLocal_VotePropChange 投票提案规则
func (a *Autonomy) ExecLocal_VotePropChange(payload *auty.VoteProposalChange, tx *types.Transaction, receiptData *types.ReceiptData, index int) (*types.LocalDBSet, error) {
return a.execAutoLocalChange(tx, receiptData)
}
// ExecLocal_TmintPropChange 终止提案规则
func (a *Autonomy) ExecLocal_TmintPropChange(payload *auty.TerminateProposalChange, tx *types.Transaction, receiptData *types.ReceiptData, index int) (*types.LocalDBSet, error) {
return a.execAutoLocalChange(tx, receiptData)
}
......@@ -70,3 +70,12 @@ func calcCommentHeight(ID, heightindex string) []byte {
key := fmt.Sprintf(localCommentPrefix+"%s-"+"%s", ID, heightindex)
return []byte(key)
}
var (
// change
changePrefix = idPrefix + "change" + "-"
)
func propChangeID(txHash string) []byte {
return []byte(fmt.Sprintf("%s%s", changePrefix, txHash))
}
......@@ -13,7 +13,6 @@ import (
"github.com/33cn/chain33/util"
auty "github.com/33cn/plugin/plugin/dapp/autonomy/types"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestExecLocalProject(t *testing.T) {
......@@ -51,14 +50,14 @@ func testexecLocalProject(t *testing.T, auto bool) {
var err error
if !auto {
set, err = au.execLocalProject(receipt)
require.NoError(t, err)
require.NotNil(t, set)
assert.NoError(t, err)
assert.NotNil(t, set)
} else {
tx, err := types.CreateFormatTx(types.ExecName(auty.AutonomyX), nil)
assert.NoError(t, err)
set, err = au.execAutoLocalProject(tx, receipt)
require.NoError(t, err)
require.NotNil(t, set)
assert.NoError(t, err)
assert.NotNil(t, set)
}
//save to database
......@@ -81,8 +80,8 @@ func testexecLocalProject(t *testing.T, auto bool) {
{Ty: auty.TyLogRvkPropProject, Log: types.Encode(receiptProject1)},
},
})
require.NoError(t, err)
require.NotNil(t, set)
assert.NoError(t, err)
assert.NotNil(t, set)
} else {
tx, err := types.CreateFormatTx(types.ExecName(auty.AutonomyX), nil)
assert.NoError(t, err)
......@@ -92,8 +91,8 @@ func testexecLocalProject(t *testing.T, auto bool) {
{Ty: auty.TyLogRvkPropProject, Log: types.Encode(receiptProject1)},
},
})
require.NoError(t, err)
require.NotNil(t, set)
assert.NoError(t, err)
assert.NotNil(t, set)
}
//save to database
......@@ -118,8 +117,8 @@ func testexecLocalProject(t *testing.T, auto bool) {
{Ty: auty.TyLogVotePropProject, Log: types.Encode(receiptProject2)},
},
})
require.NoError(t, err)
require.NotNil(t, set)
assert.NoError(t, err)
assert.NotNil(t, set)
} else {
tx, err := types.CreateFormatTx(types.ExecName(auty.AutonomyX), nil)
assert.NoError(t, err)
......@@ -129,8 +128,8 @@ func testexecLocalProject(t *testing.T, auto bool) {
{Ty: auty.TyLogVotePropProject, Log: types.Encode(receiptProject2)},
},
})
require.NoError(t, err)
require.NotNil(t, set)
assert.NoError(t, err)
assert.NotNil(t, set)
}
//save to database
......@@ -174,13 +173,13 @@ func testexecDelLocalProject(t *testing.T) {
tx, err := types.CreateFormatTx(types.ExecName(auty.AutonomyX), nil)
assert.NoError(t, err)
set, err := au.execAutoLocalProject(tx, receipt)
require.NoError(t, err)
require.NotNil(t, set)
assert.NoError(t, err)
assert.NotNil(t, set)
saveKvs(sdb, set.KV)
set, err = au.execAutoDelLocal(tx, receipt)
require.NoError(t, err)
require.NotNil(t, set)
assert.NoError(t, err)
assert.NotNil(t, set)
saveKvs(sdb, set.KV)
// check
......@@ -211,8 +210,8 @@ func testexecDelLocalProject(t *testing.T) {
tx, err = types.CreateFormatTx(types.ExecName(auty.AutonomyX), nil)
assert.NoError(t, err)
set, err = au.execAutoLocalProject(tx, receipt)
require.NoError(t, err)
require.NotNil(t, set)
assert.NoError(t, err)
assert.NotNil(t, set)
saveKvs(sdb, set.KV)
// 正常测试退回
......@@ -220,15 +219,15 @@ func testexecDelLocalProject(t *testing.T) {
assert.NoError(t, err)
set, err = au.execAutoLocalProject(tx, recpt)
require.NoError(t, err)
require.NotNil(t, set)
assert.NoError(t, err)
assert.NotNil(t, set)
saveKvs(sdb, set.KV)
// check
checkExecLocalProject(t, kvdb, cur)
set, err = au.execAutoDelLocal(tx, recpt)
require.NoError(t, err)
require.NotNil(t, set)
assert.NoError(t, err)
assert.NotNil(t, set)
saveKvs(sdb, set.KV)
checkExecLocalProject(t, kvdb, pre1)
......@@ -243,9 +242,9 @@ func TestGetProposalProject(t *testing.T) {
tx := "1111111111111111111"
storedb.Set(propProjectID(tx), types.Encode(&auty.AutonomyProposalProject{}))
rsp, err := au.getProposalProject(&types.ReqString{Data: tx})
require.NoError(t, err)
require.NotNil(t, rsp)
require.Equal(t, len(rsp.(*auty.ReplyQueryProposalProject).PropProjects), 1)
assert.NoError(t, err)
assert.NotNil(t, rsp)
assert.Equal(t, len(rsp.(*auty.ReplyQueryProposalProject).PropProjects), 1)
}
func TestListProposalProject(t *testing.T) {
......@@ -295,9 +294,9 @@ func TestListProposalProject(t *testing.T) {
cur.Index = int32(tcase.index)
err := table.Replace(cur)
require.NoError(t, err)
assert.NoError(t, err)
kv, err := table.Save()
require.NoError(t, err)
assert.NoError(t, err)
kvs = append(kvs, kv...)
}
saveKvs(sdb, kvs)
......@@ -310,12 +309,12 @@ func TestListProposalProject(t *testing.T) {
Index: -1,
}
rsp, err := au.listProposalProject(req)
require.NoError(t, err)
require.Equal(t, len(rsp.(*auty.ReplyQueryProposalProject).PropProjects), len(testcase2))
assert.NoError(t, err)
assert.Equal(t, len(rsp.(*auty.ReplyQueryProposalProject).PropProjects), len(testcase2))
k := 2
for _, tcase := range testcase2 {
require.Equal(t, rsp.(*auty.ReplyQueryProposalProject).PropProjects[k].Height, tcase.height)
require.Equal(t, rsp.(*auty.ReplyQueryProposalProject).PropProjects[k].Index, int32(tcase.index))
assert.Equal(t, rsp.(*auty.ReplyQueryProposalProject).PropProjects[k].Height, tcase.height)
assert.Equal(t, rsp.(*auty.ReplyQueryProposalProject).PropProjects[k].Index, int32(tcase.index))
k--
}
......@@ -327,11 +326,11 @@ func TestListProposalProject(t *testing.T) {
Index: -1,
}
rsp, err = au.listProposalProject(req)
require.NoError(t, err)
require.Equal(t, len(rsp.(*auty.ReplyQueryProposalProject).PropProjects), len(testcase2))
assert.NoError(t, err)
assert.Equal(t, len(rsp.(*auty.ReplyQueryProposalProject).PropProjects), len(testcase2))
for i, tcase := range testcase2 {
require.Equal(t, rsp.(*auty.ReplyQueryProposalProject).PropProjects[i].Height, tcase.height)
require.Equal(t, rsp.(*auty.ReplyQueryProposalProject).PropProjects[i].Index, int32(tcase.index))
assert.Equal(t, rsp.(*auty.ReplyQueryProposalProject).PropProjects[i].Height, tcase.height)
assert.Equal(t, rsp.(*auty.ReplyQueryProposalProject).PropProjects[i].Index, int32(tcase.index))
}
// 翻页查找
......@@ -342,12 +341,12 @@ func TestListProposalProject(t *testing.T) {
Index: -1,
}
rsp, err = au.listProposalProject(req)
require.NoError(t, err)
require.Equal(t, len(rsp.(*auty.ReplyQueryProposalProject).PropProjects), 1)
assert.NoError(t, err)
assert.Equal(t, len(rsp.(*auty.ReplyQueryProposalProject).PropProjects), 1)
height := rsp.(*auty.ReplyQueryProposalProject).PropProjects[0].Height
index := rsp.(*auty.ReplyQueryProposalProject).PropProjects[0].Index
require.Equal(t, height, testcase2[2].height)
require.Equal(t, index, int32(testcase2[2].index))
assert.Equal(t, height, testcase2[2].height)
assert.Equal(t, index, int32(testcase2[2].index))
//
req = &auty.ReqQueryProposalProject{
Status: auty.AutonomyStatusProposalProject,
......@@ -357,12 +356,12 @@ func TestListProposalProject(t *testing.T) {
Index: index,
}
rsp, err = au.listProposalProject(req)
require.NoError(t, err)
require.Equal(t, len(rsp.(*auty.ReplyQueryProposalProject).PropProjects), 2)
require.Equal(t, rsp.(*auty.ReplyQueryProposalProject).PropProjects[0].Height, testcase2[1].height)
require.Equal(t, rsp.(*auty.ReplyQueryProposalProject).PropProjects[0].Index, int32(testcase2[1].index))
require.Equal(t, rsp.(*auty.ReplyQueryProposalProject).PropProjects[1].Height, testcase2[0].height)
require.Equal(t, rsp.(*auty.ReplyQueryProposalProject).PropProjects[1].Index, int32(testcase2[0].index))
assert.NoError(t, err)
assert.Equal(t, len(rsp.(*auty.ReplyQueryProposalProject).PropProjects), 2)
assert.Equal(t, rsp.(*auty.ReplyQueryProposalProject).PropProjects[0].Height, testcase2[1].height)
assert.Equal(t, rsp.(*auty.ReplyQueryProposalProject).PropProjects[0].Index, int32(testcase2[1].index))
assert.Equal(t, rsp.(*auty.ReplyQueryProposalProject).PropProjects[1].Height, testcase2[0].height)
assert.Equal(t, rsp.(*auty.ReplyQueryProposalProject).PropProjects[1].Index, int32(testcase2[0].index))
}
func checkExecLocalProject(t *testing.T, kvdb db.KVDB, cur *auty.AutonomyProposalProject) {
......
......@@ -12,13 +12,19 @@ import (
"github.com/33cn/chain33/common/address"
)
const (
maxBoardPeriodAmount = types.Coin * 10000 * 300 // 每个时期董事会审批最大额度300万
boardPeriod = 17280 * 30 * 1 // 时期为一个月
)
func (a *action) propProject(prob *auty.ProposalProject) (*types.Receipt, error) {
if err := address.CheckAddress(prob.ToAddr); err != nil {
alog.Error("propProject ", "addr", prob.ToAddr, "check toAddr error", err)
return nil, types.ErrInvalidAddress
}
if prob.StartBlockHeight < a.height || prob.EndBlockHeight < a.height || prob.Amount <= 0 {
if prob.StartBlockHeight < a.height || prob.EndBlockHeight < a.height || prob.Amount <= 0 ||
prob.StartBlockHeight+startEndBlockPeriod > prob.EndBlockHeight {
alog.Error("propProject height or amount invaild", "StartBlockHeight", prob.StartBlockHeight, "EndBlockHeight",
prob.EndBlockHeight, "height", a.height, "amount", prob.Amount)
return nil, types.ErrInvalidParam
......@@ -30,6 +36,20 @@ func (a *action) propProject(prob *auty.ProposalProject) (*types.Receipt, error)
alog.Error("propProject ", "addr", a.fromaddr, "execaddr", a.execaddr, "get getActiveBoard failed", err)
return nil, err
}
// 检查是否可以对已审批额度归0,如果可以则设置kv
var kva *types.KeyValue
if a.height > pboard.StartHeight+boardPeriod {
pboard.StartHeight = a.height
pboard.Amount = 0
kva = &types.KeyValue{Key: activeBoardID(), Value: types.Encode(pboard)}
}
// 检查额度
pass := a.checkPeriodAmount(pboard, prob.Amount)
if !pass {
err = auty.ErrNoPeriodAmount
alog.Error("propProject ", "addr", a.fromaddr, "cumsum amount", pboard.Amount, "this period board have enough amount", err)
return nil, err
}
// 获取当前生效提案规则
rule, err := a.getActiveRule()
if err != nil {
......@@ -75,6 +95,9 @@ func (a *action) propProject(prob *auty.ProposalProject) (*types.Receipt, error)
ProposalID: common.ToHex(a.txhash),
}
kv = append(kv, &types.KeyValue{Key: propProjectID(common.ToHex(a.txhash)), Value: types.Encode(cur)})
if kva != nil {
kv = append(kv, kva)
}
receiptLog := getProjectReceiptLog(nil, cur, auty.TyLogPropProject)
logs = append(logs, receiptLog)
......@@ -189,7 +212,7 @@ func (a *action) votePropProject(voteProb *auty.VoteProposalProject) (*types.Rec
}
// 检查是否已经参与投票
votes, err := a.checkVotesRecord(boardVotesRecord(voteProb.ProposalID))
votes, err := a.checkVotesRecord([]string{a.fromaddr}, boardVotesRecord(voteProb.ProposalID))
if err != nil {
alog.Error("votePropProject ", "addr", a.fromaddr, "execaddr", a.execaddr, "checkVotesRecord boardVotesRecord failed",
voteProb.ProposalID, "err", err)
......@@ -220,9 +243,7 @@ func (a *action) votePropProject(voteProb *auty.VoteProposalProject) (*types.Rec
}
if cur.BoardVoteRes.TotalVotes != 0 &&
cur.BoardVoteRes.ApproveVotes+cur.BoardVoteRes.OpposeVotes != 0 &&
float32(cur.BoardVoteRes.ApproveVotes+cur.BoardVoteRes.OpposeVotes)/float32(cur.BoardVoteRes.TotalVotes) >= float32(cur.CurRule.BoardAttendRatio)/100.0 &&
float32(cur.BoardVoteRes.ApproveVotes)/float32(cur.BoardVoteRes.ApproveVotes+cur.BoardVoteRes.OpposeVotes) >= float32(cur.CurRule.BoardApproveRatio)/100.0 {
float32(cur.BoardVoteRes.ApproveVotes)/float32(cur.BoardVoteRes.TotalVotes) >= float32(cur.CurRule.BoardApproveRatio)/100.0 {
cur.BoardVoteRes.Pass = true
cur.PropProject.RealEndBlockHeight = a.height
}
......@@ -244,6 +265,13 @@ func (a *action) votePropProject(voteProb *auty.VoteProposalProject) (*types.Rec
}
logs = append(logs, receipt.Logs...)
kv = append(kv, receipt.KV...)
// 需要更新该董事会的累计审批金
pakv, err := a.updatePeriodAmount(cur.PropProject.Amount)
if err != nil {
alog.Error("votePropProject ", "addr", cur.Address, "execaddr", a.execaddr, "updatePeriodAmount fail", err)
return nil, err
}
kv = append(kv, pakv)
}
}
kv = append(kv, &types.KeyValue{Key: key, Value: types.Encode(cur)})
......@@ -290,15 +318,39 @@ func (a *action) pubVotePropProject(voteProb *auty.PubVoteProposalProject) (*typ
return nil, err
}
if len(voteProb.OriginAddr) > 0 {
for _, board := range voteProb.OriginAddr {
if err := address.CheckAddress(board); err != nil {
alog.Error("pubVotePropProject ", "addr", board, "check toAddr error", err)
return nil, types.ErrInvalidAddress
}
}
// 挖矿地址验证
addr, err := a.verifyMinerAddr(voteProb.OriginAddr, a.fromaddr)
if err != nil {
alog.Error("pubVotePropProject ", "from addr", a.fromaddr, "error addr", addr, "ProposalID",
voteProb.ProposalID, "err", err)
return nil, err
}
}
// 本次参与投票地址
var addrs []string
if len(voteProb.OriginAddr) == 0 {
addrs = append(addrs, a.fromaddr)
} else {
addrs = append(addrs, voteProb.OriginAddr...)
}
// 检查是否已经参与投票
votes, err := a.checkVotesRecord(votesRecord(voteProb.ProposalID))
votes, err := a.checkVotesRecord(addrs, votesRecord(voteProb.ProposalID))
if err != nil {
alog.Error("pubVotePropProject ", "addr", a.fromaddr, "execaddr", a.execaddr, "checkVotesRecord failed",
voteProb.ProposalID, "err", err)
return nil, err
}
// 更新投票记录
votes.Address = append(votes.Address, a.fromaddr)
votes.Address = append(votes.Address, addrs...)
if cur.GetPubVote().TotalVotes == 0 { //需要统计总票数
vtCouts, err := a.getTotalVotes(start)
......@@ -309,8 +361,10 @@ func (a *action) pubVotePropProject(voteProb *auty.PubVoteProposalProject) (*typ
}
// 获取该地址票数
vtCouts, err := a.getAddressVotes(a.fromaddr, start)
vtCouts, err := a.batchGetAddressVotes(addrs, start)
if err != nil {
alog.Error("pubVotePropProject ", "addr", a.fromaddr, "execaddr", a.execaddr, "batchGetAddressVotes failed",
voteProb.ProposalID, "err", err)
return nil, err
}
if voteProb.Oppose { //投反对票
......@@ -391,16 +445,14 @@ func (a *action) tmintPropProject(tmintProb *auty.TerminateProposalProject) (*ty
}
if cur.BoardVoteRes.TotalVotes != 0 &&
cur.BoardVoteRes.ApproveVotes+cur.BoardVoteRes.OpposeVotes != 0 &&
float32(cur.BoardVoteRes.ApproveVotes+cur.BoardVoteRes.OpposeVotes)/float32(cur.BoardVoteRes.TotalVotes) >= float32(cur.CurRule.BoardAttendRatio)/100.0 &&
float32(cur.BoardVoteRes.ApproveVotes)/float32(cur.BoardVoteRes.ApproveVotes+cur.BoardVoteRes.OpposeVotes) >= float32(cur.CurRule.BoardApproveRatio)/100.0 {
float32(cur.BoardVoteRes.ApproveVotes)/float32(cur.BoardVoteRes.TotalVotes) >= float32(cur.CurRule.BoardApproveRatio)/100.0 {
cur.BoardVoteRes.Pass = true
} else {
cur.BoardVoteRes.Pass = false
}
if cur.PubVote.Publicity {
if cur.GetBoardVoteRes().TotalVotes == 0 { //需要统计总票数
if cur.PubVote.TotalVotes == 0 { //需要统计总票数
vtCouts, err := a.getTotalVotes(start)
if err != nil {
return nil, err
......@@ -439,6 +491,13 @@ func (a *action) tmintPropProject(tmintProb *auty.TerminateProposalProject) (*ty
}
logs = append(logs, receipt.Logs...)
kv = append(kv, receipt.KV...)
// 需要更新该董事会的累计审批金
pakv, err := a.updatePeriodAmount(cur.PropProject.Amount)
if err != nil {
alog.Error("tmintPropProject ", "addr", cur.Address, "execaddr", a.execaddr, "updatePeriodAmount fail", err)
return nil, err
}
kv = append(kv, pakv)
} else {
// 解冻项目金
receiptPrj, err := a.coinsAccount.ExecActive(autonomyFundAddr, a.execaddr, cur.PropProject.Amount)
......@@ -473,12 +532,12 @@ func (a *action) getProposalProject(ID string) (*auty.AutonomyProposalProject, e
return cur, nil
}
func (a *action) getActiveBoard() (*auty.ProposalBoard, error) {
func (a *action) getActiveBoard() (*auty.ActiveBoard, error) {
value, err := a.db.Get(activeBoardID())
if err != nil {
return nil, err
}
pboard := &auty.ProposalBoard{}
pboard := &auty.ActiveBoard{}
err = types.Decode(value, pboard)
if err != nil {
return nil, err
......@@ -523,3 +582,26 @@ func copyAutonomyProposalProject(cur *auty.AutonomyProposalProject) *auty.Autono
}
return &newAut
}
func (a *action) checkPeriodAmount(act *auty.ActiveBoard, amount int64) bool {
if act == nil {
return false
}
if act.Amount+amount > maxBoardPeriodAmount {
return false
}
return true
}
func (a *action) updatePeriodAmount(amount int64) (*types.KeyValue, error) {
act, err := a.getActiveBoard()
if err != nil {
return nil, err
}
if a.height > act.StartHeight+boardPeriod {
act.StartHeight = a.height
act.Amount = 0
}
act.Amount += amount
return &types.KeyValue{Key: activeBoardID(), Value: types.Encode(act)}, nil
}
......@@ -19,6 +19,11 @@ func (a *Autonomy) Query_ListProposalBoard(in *auty.ReqQueryProposalBoard) (type
return a.listProposalBoard(in)
}
// Query_GetActiveBoard 查询当前board
func (a *Autonomy) Query_GetActiveBoard(in *types.ReqString) (types.Message, error) {
return a.getActiveBoard()
}
// Query_GetProposalProject 查询提案项目
func (a *Autonomy) Query_GetProposalProject(in *types.ReqString) (types.Message, error) {
return a.getProposalProject(in)
......@@ -39,7 +44,22 @@ func (a *Autonomy) Query_ListProposalRule(in *auty.ReqQueryProposalRule) (types.
return a.listProposalRule(in)
}
// Query_GetActiveRule 查询当前rule
func (a *Autonomy) Query_GetActiveRule(in *types.ReqString) (types.Message, error) {
return a.getActiveRule()
}
// Query_ListProposalComment 批量查询提案评论
func (a *Autonomy) Query_ListProposalComment(in *auty.ReqQueryProposalComment) (types.Message, error) {
return a.listProposalComment(in)
}
// Query_GetProposalChange 查询提案修改董事会成员
func (a *Autonomy) Query_GetProposalChange(in *types.ReqString) (types.Message, error) {
return a.getProposalChange(in)
}
// Query_ListProposalChange 批量查询
func (a *Autonomy) Query_ListProposalChange(in *auty.ReqQueryProposalChange) (types.Message, error) {
return a.listProposalChange(in)
}
......@@ -124,6 +124,24 @@ func (a *Autonomy) listProposalRule(req *auty.ReqQueryProposalRule) (types.Messa
return &rep, nil
}
func (a *Autonomy) getActiveRule() (types.Message, error) {
rule := &auty.RuleConfig{}
value, err := a.GetStateDB().Get(activeRuleID())
if err == nil {
err = types.Decode(value, rule)
if err != nil {
return nil, err
}
} else { // 载入系统默认值
rule.BoardApproveRatio = boardApproveRatio
rule.PubOpposeRatio = pubOpposeRatio
rule.ProposalAmount = proposalAmount
rule.LargeProjectAmount = largeProjectAmount
rule.PublicPeriod = publicPeriod
}
return rule, nil
}
func (a *Autonomy) execAutoLocalCommentProp(tx *types.Transaction, receiptData *types.ReceiptData) (*types.LocalDBSet, error) {
set, err := a.execLocalCommentProp(receiptData)
if err != nil {
......
This diff is collapsed.
......@@ -9,23 +9,51 @@ import (
"github.com/33cn/chain33/types"
auty "github.com/33cn/plugin/plugin/dapp/autonomy/types"
"github.com/33cn/chain33/common/address"
"github.com/33cn/chain33/system/dapp"
)
const (
// 最小董事会赞成率
minBoardApproveRatio = 50
// 最大董事会赞成率
maxBoardApproveRatio = 66
// 最小全体持票人否决率
minPubOpposeRatio = 33
// 最大全体持票人否决率
maxPubOpposeRatio = 50
// 最小公示周期
minPublicPeriod int32 = 17280 * 7
// 最大公示周期
maxPublicPeriod int32 = 17280 * 14
// 最小重大项目阈值
minLargeProjectAmount = types.Coin * 100 * 10000
// 最大重大项目阈值
maxLargeProjectAmount = types.Coin * 300 * 10000
// 最小提案金
minProposalAmount = types.Coin * 20
// 最大提案金
maxProposalAmount = types.Coin * 2000
)
func (a *action) propRule(prob *auty.ProposalRule) (*types.Receipt, error) {
//如果全小于等于0,则说明该提案规则参数不正确
if prob.RuleCfg == nil || prob.RuleCfg.BoardAttendRatio <= 0 && prob.RuleCfg.BoardApproveRatio <= 0 &&
prob.RuleCfg.PubOpposeRatio <= 0 && prob.RuleCfg.ProposalAmount <= 0 && prob.RuleCfg.LargeProjectAmount <= 0 &&
prob.RuleCfg.PublicPeriod <= 0 {
if prob.RuleCfg == nil || prob.RuleCfg.BoardApproveRatio <= 0 && prob.RuleCfg.PubOpposeRatio <= 0 &&
prob.RuleCfg.ProposalAmount <= 0 && prob.RuleCfg.LargeProjectAmount <= 0 && prob.RuleCfg.PublicPeriod <= 0 {
alog.Error("propRule ", "ProposalRule RuleCfg invaild or have no modify param", prob.RuleCfg)
return nil, types.ErrInvalidParam
}
if prob.RuleCfg.BoardAttendRatio > 100 || prob.RuleCfg.BoardApproveRatio > 100 || prob.RuleCfg.PubOpposeRatio > 100 {
alog.Error("propRule RuleCfg invaild", "BoardAttendRatio", prob.RuleCfg.BoardAttendRatio, "BoardApproveRatio",
prob.RuleCfg.BoardApproveRatio, "PubOpposeRatio", prob.RuleCfg.PubOpposeRatio)
if (prob.RuleCfg.BoardApproveRatio > 0 && (prob.RuleCfg.BoardApproveRatio > maxBoardApproveRatio || prob.RuleCfg.BoardApproveRatio < minBoardApproveRatio)) ||
(prob.RuleCfg.PubOpposeRatio > 0 && (prob.RuleCfg.PubOpposeRatio > maxPubOpposeRatio || prob.RuleCfg.PubOpposeRatio < minPubOpposeRatio)) ||
(prob.RuleCfg.PublicPeriod > 0 && (prob.RuleCfg.PublicPeriod > maxPublicPeriod || prob.RuleCfg.PublicPeriod < minPublicPeriod)) ||
(prob.RuleCfg.LargeProjectAmount > 0 && (prob.RuleCfg.LargeProjectAmount > maxLargeProjectAmount || prob.RuleCfg.LargeProjectAmount < minLargeProjectAmount)) ||
(prob.RuleCfg.ProposalAmount > 0 && (prob.RuleCfg.ProposalAmount > maxProposalAmount || prob.RuleCfg.ProposalAmount < minProposalAmount)) {
alog.Error("propRule RuleCfg invaild", "ruleCfg", prob.RuleCfg)
return nil, types.ErrInvalidParam
}
if prob.StartBlockHeight < a.height || prob.EndBlockHeight < a.height {
if prob.StartBlockHeight < a.height || prob.EndBlockHeight < a.height ||
prob.StartBlockHeight+startEndBlockPeriod > prob.EndBlockHeight {
alog.Error("propRule height invaild", "StartBlockHeight", prob.StartBlockHeight, "EndBlockHeight",
prob.EndBlockHeight, "height", a.height)
return nil, types.ErrInvalidParam
......@@ -152,15 +180,39 @@ func (a *action) votePropRule(voteProb *auty.VoteProposalRule) (*types.Receipt,
return nil, err
}
if len(voteProb.OriginAddr) > 0 {
for _, board := range voteProb.OriginAddr {
if err := address.CheckAddress(board); err != nil {
alog.Error("votePropRule ", "addr", board, "check toAddr error", err)
return nil, types.ErrInvalidAddress
}
}
// 挖矿地址验证
addr, err := a.verifyMinerAddr(voteProb.OriginAddr, a.fromaddr)
if err != nil {
alog.Error("votePropRule ", "from addr", a.fromaddr, "error addr", addr, "ProposalID",
voteProb.ProposalID, "err", err)
return nil, err
}
}
// 本次参与投票地址
var addrs []string
if len(voteProb.OriginAddr) == 0 {
addrs = append(addrs, a.fromaddr)
} else {
addrs = append(addrs, voteProb.OriginAddr...)
}
// 检查是否已经参与投票
votes, err := a.checkVotesRecord(votesRecord(voteProb.ProposalID))
votes, err := a.checkVotesRecord(addrs, votesRecord(voteProb.ProposalID))
if err != nil {
alog.Error("votePropRule ", "addr", a.fromaddr, "execaddr", a.execaddr, "checkVotesRecord failed",
voteProb.ProposalID, "err", err)
return nil, err
}
// 更新投票记录
votes.Address = append(votes.Address, a.fromaddr)
votes.Address = append(votes.Address, addrs...)
if cur.GetVoteResult().TotalVotes == 0 { //需要统计票数
vtCouts, err := a.getTotalVotes(start)
......@@ -171,8 +223,10 @@ func (a *action) votePropRule(voteProb *auty.VoteProposalRule) (*types.Receipt,
}
// 获取可投票数
vtCouts, err := a.getAddressVotes(a.fromaddr, start)
vtCouts, err := a.batchGetAddressVotes(addrs, start)
if err != nil {
alog.Error("votePropRule ", "addr", a.fromaddr, "execaddr", a.execaddr, "batchGetAddressVotes failed",
voteProb.ProposalID, "err", err)
return nil, err
}
if voteProb.Approve {
......@@ -396,9 +450,6 @@ func upgradeRule(cur, modify *auty.RuleConfig) *auty.RuleConfig {
return nil
}
new := *cur
if modify.BoardAttendRatio > 0 {
new.BoardAttendRatio = modify.BoardAttendRatio
}
if modify.BoardApproveRatio > 0 {
new.BoardApproveRatio = modify.BoardApproveRatio
}
......
......@@ -8,6 +8,7 @@ syntax = "proto3";
import "board.proto";
import "project.proto";
import "rule.proto";
import "change.proto";
package types;
......@@ -33,6 +34,11 @@ message AutonomyAction {
// 发展基金转自治系统合约
TransferFund transfer = 14;
Comment commentProp = 15;
// 提案改变董事会成员
ProposalChange propChange = 16;
RevokeProposalChange rvkPropChange = 17;
VoteProposalChange votePropChange = 18;
TerminateProposalChange tmintPropChange = 19;
}
int32 ty = 16;
int32 ty = 20;
}
\ No newline at end of file
......@@ -46,6 +46,7 @@ message RevokeProposalBoard {
message VoteProposalBoard {
string proposalID = 1;
bool approve = 2;
repeated string originAddr = 3;
}
message TerminateProposalBoard {
......
// 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.
syntax = "proto3";
import "lcommon.proto";
package types;
message AutonomyProposalChange {
ProposalChange propChange = 1;
// 投票该提案的规则
RuleConfig curRule = 2;
// 投票董事会
ActiveBoard board = 3;
// 全体持票人投票结果
VoteResult voteResult = 4;
// 状态
int32 status = 5;
string address = 6;
int64 height = 7;
int32 index = 8;
string proposalID = 9;
}
// action
message ProposalChange {
// 提案时间
int32 year = 1;
int32 month = 2;
int32 day = 3;
// 修改董事会成员
repeated Change Changes = 4;
// 投票相关
int64 startBlockHeight = 5; // 提案开始投票高度
int64 endBlockHeight = 6; // 提案结束投票高度
int64 realEndBlockHeight = 7; // 实际提案结束投票高度
}
message Change {
// 1 取消 0 恢复
bool cancel = 1;
string addr = 2;
}
message RevokeProposalChange {
string proposalID = 1;
}
message VoteProposalChange {
string proposalID = 1;
bool approve = 2;
}
message TerminateProposalChange {
string proposalID = 1;
}
// receipt
message ReceiptProposalChange {
AutonomyProposalChange prev = 1;
AutonomyProposalChange current = 2;
}
message LocalProposalChange {
AutonomyProposalChange propBd = 1;
repeated string comments = 2;
}
// query
message ReqQueryProposalChange {
int32 status = 1;
string addr = 2;
int32 count = 3;
int32 direction = 4;
int64 height = 5;
int32 index = 6;
}
message ReplyQueryProposalChange {
repeated AutonomyProposalChange propChanges = 1;
}
\ No newline at end of file
......@@ -33,16 +33,21 @@ message VotesRecord {
}
message RuleConfig {
// 董事会成员参与率,以%为单位,只保留整数部分
int32 boardAttendRatio = 1;
// 董事会成员赞成率
int32 boardApproveRatio = 2;
// 董事会成员赞成率,以%为单位,只保留整数部分
int32 boardApproveRatio = 1;
// 全体持票人否决率
int32 pubOpposeRatio = 3;
int32 pubOpposeRatio = 2;
// 提案金额
int64 proposalAmount = 4;
int64 proposalAmount = 3;
// 重大项目公示金额阈值
int64 largeProjectAmount = 5;
int64 largeProjectAmount = 4;
// 重大项目公示时间(以区块数为单位)
int32 publicPeriod = 6;
int32 publicPeriod = 5;
}
message ActiveBoard {
repeated string boards = 1;
repeated string revboards = 2;
int64 amount = 3;
int64 startHeight = 4;
}
\ No newline at end of file
......@@ -63,6 +63,7 @@ message VoteProposalProject {
message PubVoteProposalProject {
string proposalID = 1;
bool oppose = 2;
repeated string originAddr = 3;
}
message TerminateProposalProject {
......
......@@ -42,6 +42,7 @@ message RevokeProposalRule {
message VoteProposalRule {
string proposalID = 1;
bool approve = 2;
repeated string originAddr = 3;
}
message TerminateProposalRule {
......
......@@ -96,3 +96,12 @@ func testListProposalBoardCmd(t *testing.T, jrpc *jsonclient.JSONClient) error {
rep = &auty.ReplyQueryProposalBoard{}
return jrpc.Call("Chain33.Query", params, rep)
}
func testGetActiveBoardCmd(t *testing.T, jrpc *jsonclient.JSONClient) error {
var rep interface{}
var params rpctypes.Query4Jrpc
params.FuncName = auty.GetActiveBoard
params.Payload = types.MustPBToJSON(&types.ReqString{})
rep = &auty.ActiveBoard{}
return jrpc.Call("Chain33.Query", params, rep)
}
// 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 rpc_test
import (
"testing"
"encoding/json"
"github.com/33cn/chain33/rpc/jsonclient"
rpctypes "github.com/33cn/chain33/rpc/types"
_ "github.com/33cn/chain33/system"
"github.com/33cn/chain33/types"
_ "github.com/33cn/plugin/plugin"
auty "github.com/33cn/plugin/plugin/dapp/autonomy/types"
)
func testPropChangeTxCmd(t *testing.T, jrpc *jsonclient.JSONClient) error {
params := &auty.ProposalChange{}
payLoad, err := json.Marshal(params)
if err != nil {
return err
}
pm := &rpctypes.CreateTxIn{
Execer: types.ExecName(auty.AutonomyX),
ActionName: "PropChange",
Payload: payLoad,
}
var res string
return jrpc.Call("Chain33.CreateTransaction", pm, &res)
}
func testRevokeProposalChangeTxCmd(t *testing.T, jrpc *jsonclient.JSONClient) error {
params := &auty.RevokeProposalChange{}
payLoad, err := json.Marshal(params)
if err != nil {
return err
}
pm := &rpctypes.CreateTxIn{
Execer: types.ExecName(auty.AutonomyX),
ActionName: "RvkPropChange",
Payload: payLoad,
}
var res string
return jrpc.Call("Chain33.CreateTransaction", pm, &res)
}
func testVoteProposalChangeTxCmd(t *testing.T, jrpc *jsonclient.JSONClient) error {
params := &auty.VoteProposalChange{}
payLoad, err := json.Marshal(params)
if err != nil {
return err
}
pm := &rpctypes.CreateTxIn{
Execer: types.ExecName(auty.AutonomyX),
ActionName: "VotePropChange",
Payload: payLoad,
}
var res string
return jrpc.Call("Chain33.CreateTransaction", pm, &res)
}
func testTerminateProposalChangeTxCmd(t *testing.T, jrpc *jsonclient.JSONClient) error {
params := &auty.TerminateProposalChange{}
payLoad, err := json.Marshal(params)
if err != nil {
return err
}
pm := &rpctypes.CreateTxIn{
Execer: types.ExecName(auty.AutonomyX),
ActionName: "TmintPropChange",
Payload: payLoad,
}
var res string
return jrpc.Call("Chain33.CreateTransaction", pm, &res)
}
func testGetProposalChangeCmd(t *testing.T, jrpc *jsonclient.JSONClient) error {
var rep interface{}
var params rpctypes.Query4Jrpc
req := &types.ReqString{}
params.FuncName = auty.GetProposalChange
params.Payload = types.MustPBToJSON(req)
rep = &auty.ReplyQueryProposalChange{}
return jrpc.Call("Chain33.Query", params, rep)
}
func testListProposalChangeCmd(t *testing.T, jrpc *jsonclient.JSONClient) error {
var rep interface{}
var params rpctypes.Query4Jrpc
req := &auty.ReqQueryProposalChange{}
params.FuncName = auty.ListProposalChange
params.Payload = types.MustPBToJSON(req)
rep = &auty.ReplyQueryProposalChange{}
return jrpc.Call("Chain33.Query", params, rep)
}
......@@ -42,6 +42,7 @@ func TestJRPCChannel(t *testing.T) {
{fn: testTerminateProposalBoardTxCmd},
{fn: testGetProposalBoardCmd},
{fn: testListProposalBoardCmd},
{fn: testGetActiveBoardCmd},
{fn: testPropProjectTxCmd},
{fn: testRevokeProposalProjectTxCmd},
......@@ -57,10 +58,18 @@ func TestJRPCChannel(t *testing.T) {
{fn: testTerminateProposalRuleTxCmd},
{fn: testGetProposalRuleCmd},
{fn: testListProposalRuleCmd},
{fn: testGetActiveRuleCmd},
{fn: testTransferFundTxCmd},
{fn: testCommentProposalTxCmd},
{fn: testListProposalCommentCmd},
{fn: testPropChangeTxCmd},
{fn: testRevokeProposalChangeTxCmd},
{fn: testVoteProposalChangeTxCmd},
{fn: testTerminateProposalChangeTxCmd},
{fn: testGetProposalChangeCmd},
{fn: testListProposalChangeCmd},
}
for index, testCase := range testCases {
err := testCase.fn(t, jrpcClient)
......
......@@ -97,6 +97,15 @@ func testListProposalRuleCmd(t *testing.T, jrpc *jsonclient.JSONClient) error {
return jrpc.Call("Chain33.Query", params, rep)
}
func testGetActiveRuleCmd(t *testing.T, jrpc *jsonclient.JSONClient) error {
var rep interface{}
var params rpctypes.Query4Jrpc
params.FuncName = auty.GetActiveRule
params.Payload = types.MustPBToJSON(&types.ReqString{})
rep = &auty.RuleConfig{}
return jrpc.Call("Chain33.Query", params, rep)
}
func testTransferFundTxCmd(t *testing.T, jrpc *jsonclient.JSONClient) error {
params := &auty.TransferFund{}
payLoad, err := json.Marshal(params)
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -25,6 +25,11 @@ const (
AutonomyActionTransfer
AutonomyActionCommentProp
AutonomyActionPropChange
AutonomyActionRvkPropChange
AutonomyActionVotePropChange
AutonomyActionTmintPropChange
//log for autonomy
TyLogPropBoard = 2101
TyLogRvkPropBoard = 2102
......@@ -43,6 +48,11 @@ const (
TyLogTmintPropRule = 2124
TyLogCommentProp = 2131
TyLogPropChange = 2141
TyLogRvkPropChange = 2142
TyLogVotePropChange = 2143
TyLogTmintPropChange = 2144
)
// Board status
......@@ -70,11 +80,21 @@ const (
AutonomyStatusTmintPropRule
)
// Change status
const (
AutonomyStatusProposalChange = iota + 1
AutonomyStatusRvkPropChange
AutonomyStatusVotePropChange
AutonomyStatusTmintPropChange
)
const (
// GetProposalBoard 用于在cmd里面的区分不同的查询
GetProposalBoard = "GetProposalBoard"
// ListProposalBoard 查询多个
ListProposalBoard = "ListProposalBoard"
// GetActiveBoard 查询当前的
GetActiveBoard = "GetActiveBoard"
// GetProposalProject 用于在cmd里面的区分不同的查询
GetProposalProject = "GetProposalProject"
// ListProposalProject 查询多个
......@@ -83,8 +103,14 @@ const (
GetProposalRule = "GetProposalRule"
// ListProposalRule 查询多个
ListProposalRule = "ListProposalRule"
// GetActiveRule 查询当前的
GetActiveRule = "GetActiveRule"
// ListProposalComment 查询多个
ListProposalComment = "ListProposalComment"
// GetProposalChange 用于在cmd里面的区分不同的查询
GetProposalChange = "GetProposalChange"
// ListProposalChange 查询多个
ListProposalChange = "ListProposalChange"
)
//包的名字可以通过配置文件来配置
......
......@@ -23,4 +23,16 @@ var (
ErrNoActiveBoard = errors.New("ErrNoActiveBoard")
// ErrNoAutonomyExec 非Autonomy执行器
ErrNoAutonomyExec = errors.New("ErrNoAutonomyExec")
// ErrNoPeriodAmount 当前没有足够额度
ErrNoPeriodAmount = errors.New("ErrNoPeriodAmount")
// ErrMinerAddr 无效挖矿地址
ErrMinerAddr = errors.New("ErrMinerAddr")
// ErrBindAddr 无效绑定地址
ErrBindAddr = errors.New("ErrBindAddr")
// ErrChangeBoardAddr 无效修改董事会成员地址
ErrChangeBoardAddr = errors.New("ErrChangeBoardAddr")
// ErrBoardNumber 董事会成员数错误
ErrBoardNumber = errors.New("ErrBoardNumber")
// ErrRepeatAddr 重复地址
ErrRepeatAddr = errors.New("ErrRepeatAddr")
)
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -57,6 +57,11 @@ func (a *AutonomyType) GetLogMap() map[int64]*types.LogInfo {
TyLogTmintPropRule: {Ty: reflect.TypeOf(ReceiptProposalRule{}), Name: "LogTmintPropRule"},
TyLogCommentProp: {Ty: reflect.TypeOf(ReceiptProposalComment{}), Name: "LogCommentProp"},
TyLogPropChange: {Ty: reflect.TypeOf(ReceiptProposalChange{}), Name: "LogPropChange"},
TyLogRvkPropChange: {Ty: reflect.TypeOf(ReceiptProposalChange{}), Name: "LogRvkPropChange"},
TyLogVotePropChange: {Ty: reflect.TypeOf(ReceiptProposalChange{}), Name: "LogVotePropChange"},
TyLogTmintPropChange: {Ty: reflect.TypeOf(ReceiptProposalChange{}), Name: "LogTmintPropChange"},
}
}
......@@ -86,5 +91,10 @@ func (a *AutonomyType) GetTypeMap() map[string]int32 {
"Transfer": AutonomyActionTransfer,
"CommentProp": AutonomyActionCommentProp,
"PropChange": AutonomyActionPropChange,
"RvkPropChange": AutonomyActionRvkPropChange,
"VotePropChange": AutonomyActionVotePropChange,
"TmintPropChange": AutonomyActionTmintPropChange,
}
}
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