-
Notifications
You must be signed in to change notification settings - Fork 215
MX-15029: Accept multiple delegateVoting #5857
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
6ef1556
d50e7d9
3a04c1a
2c233f4
5cb1114
9c89cc3
a0e0d59
5693577
f178fc7
898267e
70fde80
067d880
78a4644
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -37,6 +37,8 @@ func createEnableEpochsConfig() config.EnableEpochs { | |
| DoubleKeyProtectionEnableEpoch: 19, | ||
| ESDTEnableEpoch: 20, | ||
| GovernanceEnableEpoch: 21, | ||
| GovernanceDisableProposeEnableEpoch: 22, | ||
| GovernanceFixesEnableEpoch: 23, | ||
| DelegationManagerEnableEpoch: 22, | ||
| DelegationSmartContractEnableEpoch: 23, | ||
| CorrectLastUnjailedEnableEpoch: 24, | ||
|
|
@@ -213,6 +215,8 @@ func TestEnableEpochsHandler_IsFlagEnabled(t *testing.T) { | |
| require.False(t, handler.IsFlagEnabled(common.ESDTFlagInSpecificEpochOnly)) // == | ||
| require.True(t, handler.IsFlagEnabled(common.GovernanceFlag)) | ||
| require.False(t, handler.IsFlagEnabled(common.GovernanceFlagInSpecificEpochOnly)) // == | ||
| require.True(t, handler.IsFlagEnabled(common.GovernanceDisableProposeFlag)) // == | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. what is the purpose for the == comments? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Will remove in the next PR. |
||
| require.True(t, handler.IsFlagEnabled(common.GovernanceFixesFlag)) // == | ||
| require.True(t, handler.IsFlagEnabled(common.DelegationManagerFlag)) | ||
| require.True(t, handler.IsFlagEnabled(common.DelegationSmartContractFlag)) | ||
| require.False(t, handler.IsFlagEnabled(common.DelegationSmartContractFlagInSpecificEpochOnly)) // == | ||
|
|
@@ -326,6 +330,8 @@ func TestEnableEpochsHandler_GetActivationEpoch(t *testing.T) { | |
| require.Equal(t, cfg.DoubleKeyProtectionEnableEpoch, handler.GetActivationEpoch(common.DoubleKeyProtectionFlag)) | ||
| require.Equal(t, cfg.ESDTEnableEpoch, handler.GetActivationEpoch(common.ESDTFlag)) | ||
| require.Equal(t, cfg.GovernanceEnableEpoch, handler.GetActivationEpoch(common.GovernanceFlag)) | ||
| require.Equal(t, cfg.GovernanceDisableProposeEnableEpoch, handler.GetActivationEpoch(common.GovernanceDisableProposeFlag)) | ||
| require.Equal(t, cfg.GovernanceFixesEnableEpoch, handler.GetActivationEpoch(common.GovernanceFixesFlag)) | ||
| require.Equal(t, cfg.DelegationManagerEnableEpoch, handler.GetActivationEpoch(common.DelegationManagerFlag)) | ||
| require.Equal(t, cfg.DelegationSmartContractEnableEpoch, handler.GetActivationEpoch(common.DelegationSmartContractFlag)) | ||
| require.Equal(t, cfg.CorrectLastUnjailedEnableEpoch, handler.GetActivationEpoch(common.CorrectLastUnJailedFlag)) | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,4 @@ | ||
| //go:generate protoc -I=. -I=$GOPATH/src -I=$GOPATH/src/github.com/gogo/protobuf/protobuf --gogoslick_out=. governance.proto | ||
| //go:generate protoc -I=. -I=$GOPATH/src -I=$GOPATH/src/github.com/gogo/protobuf/protobuf --gogoslick_out=. governance.proto | ||
| package systemSmartContracts | ||
|
|
||
| import ( | ||
|
|
@@ -155,8 +155,6 @@ func (g *governanceContract) Execute(args *vmcommon.ContractCallInput) vmcommon. | |
| return g.viewVotingPower(args) | ||
| case "viewConfig": | ||
| return g.viewConfig(args) | ||
| case "viewUserVoteHistory": | ||
| return g.viewUserVoteHistory(args) | ||
| case "viewDelegatedVoteInfo": | ||
| return g.viewDelegatedVoteInfo(args) | ||
| case "viewProposal": | ||
|
|
@@ -284,6 +282,10 @@ func (g *governanceContract) changeConfig(args *vmcommon.ContractCallInput) vmco | |
|
|
||
| // proposal creates a new proposal from passed arguments | ||
| func (g *governanceContract) proposal(args *vmcommon.ContractCallInput) vmcommon.ReturnCode { | ||
| if g.enableEpochsHandler.IsFlagEnabled(common.GovernanceDisableProposeFlag) && !g.enableEpochsHandler.IsFlagEnabled(common.GovernanceFixesFlag) { | ||
AdoAdoAdo marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| g.eei.AddReturnMessage("proposing is disabled") | ||
| return vmcommon.UserError | ||
| } | ||
| err := g.eei.UseGas(g.gasCost.MetaChainSystemSCsCost.Proposal) | ||
| if err != nil { | ||
| g.eei.AddReturnMessage("not enough gas") | ||
|
|
@@ -398,7 +400,8 @@ func (g *governanceContract) vote(args *vmcommon.ContractCallInput) vmcommon.Ret | |
| string(args.Arguments[1]), | ||
| totalVotingPower, | ||
| totalStake, | ||
| true) | ||
| true, | ||
| nil) | ||
| if err != nil { | ||
| g.eei.AddReturnMessage(err.Error()) | ||
| return vmcommon.UserError | ||
|
|
@@ -465,7 +468,8 @@ func (g *governanceContract) delegateVote(args *vmcommon.ContractCallInput) vmco | |
| string(args.Arguments[1]), | ||
| votePower, | ||
| userStake, | ||
| false) | ||
| false, | ||
| args.CallerAddr) | ||
| if err != nil { | ||
| g.eei.AddReturnMessage(err.Error()) | ||
| return vmcommon.UserError | ||
|
|
@@ -524,9 +528,11 @@ func (g *governanceContract) addUserVote( | |
| totalVotingPower *big.Int, | ||
| totalStake *big.Int, | ||
| direct bool, | ||
| scAddress []byte, | ||
| ) error { | ||
| nonce := big.NewInt(0).SetBytes(nonceAsBytes) | ||
| err := g.updateUserVoteList(address, nonce.Uint64(), direct) | ||
| //TODO: remove extra struct & methods for V2 if no V1 proposal exists | ||
| err := g.updateUserVoteListV2(address, nonce.Uint64(), direct, scAddress) | ||
| if err != nil { | ||
| return err | ||
| } | ||
|
|
@@ -545,25 +551,57 @@ func (g *governanceContract) addUserVote( | |
| return g.saveGeneralProposal(proposal.CommitHash, proposal) | ||
| } | ||
|
|
||
| func (g *governanceContract) updateUserVoteList(address []byte, nonce uint64, direct bool) error { | ||
| userVoteList, err := g.getUserVotes(address) | ||
| func (g *governanceContract) updateUserVoteListV1(address []byte, nonce uint64, direct bool) error { | ||
| userVoteList, err := g.getUserVotesV1(address) | ||
| if err != nil { | ||
| return err | ||
| } | ||
|
|
||
| err = g.updateUserVotesV1(userVoteList, nonce, direct) | ||
| if err != nil { | ||
| return err | ||
| } | ||
|
|
||
| return g.saveUserVotesV1(address, userVoteList) | ||
| } | ||
|
|
||
| func (g *governanceContract) updateUserVoteListV2(address []byte, nonce uint64, direct bool, scAddress []byte) error { | ||
| if !g.enableEpochsHandler.IsFlagEnabled(common.GovernanceFixesFlag) { | ||
| return g.updateUserVoteListV1(address, nonce, direct) | ||
| } | ||
| userVoteList, err := g.getUserVotesV2(address) | ||
| if err != nil { | ||
| return err | ||
| } | ||
|
|
||
| err = g.updateUserVotesV2(userVoteList, nonce, direct, scAddress) | ||
| if err != nil { | ||
| return err | ||
| } | ||
|
|
||
| return g.saveUserVotesV2(address, userVoteList) | ||
| } | ||
|
|
||
| func (g *governanceContract) updateUserVotesV1(userVoteList *OngoingVotedList, nonce uint64, direct bool) error { | ||
| var err error | ||
| if direct { | ||
| userVoteList.Direct, err = addNewNonce(userVoteList.Direct, nonce) | ||
| if err != nil { | ||
| return err | ||
| } | ||
| } else { | ||
| userVoteList.Delegated, err = addNewNonce(userVoteList.Delegated, nonce) | ||
| if err != nil { | ||
| return err | ||
| } | ||
| return err | ||
| } | ||
|
|
||
| userVoteList.Delegated, err = addNewNonce(userVoteList.Delegated, nonce) | ||
| return err | ||
| } | ||
|
|
||
| func (g *governanceContract) updateUserVotesV2(userVoteList *OngoingVotedListV2, nonce uint64, direct bool, scAddress []byte) error { | ||
| var err error | ||
| if direct { | ||
| userVoteList.Direct, err = addNewNonce(userVoteList.Direct, nonce) | ||
| return err | ||
| } | ||
|
|
||
| return g.saveUserVotes(address, userVoteList) | ||
| userVoteList.DelegatedWithAddress, err = addNewNonceV2(userVoteList.DelegatedWithAddress, scAddress, nonce) | ||
| return err | ||
| } | ||
|
|
||
| func addNewNonce(nonceList []uint64, newNonce uint64) ([]uint64, error) { | ||
|
|
@@ -577,6 +615,20 @@ func addNewNonce(nonceList []uint64, newNonce uint64) ([]uint64, error) { | |
| return nonceList, nil | ||
| } | ||
|
|
||
| func addNewNonceV2(nonceList []*DelegatedWithAddress, newDelegatedAddress []byte, newNonce uint64) ([]*DelegatedWithAddress, error) { | ||
| for _, delegatedStruct := range nonceList { | ||
| if newNonce == delegatedStruct.Nonce && bytes.Equal(delegatedStruct.DelegatedAddress, newDelegatedAddress) { | ||
| return nil, vm.ErrDoubleVote | ||
| } | ||
| } | ||
|
|
||
| nonceList = append(nonceList, &DelegatedWithAddress{ | ||
| Nonce: newNonce, | ||
| DelegatedAddress: newDelegatedAddress, | ||
| }) | ||
| return nonceList, nil | ||
| } | ||
|
|
||
| func (g *governanceContract) getMinValueToVote() (*big.Int, error) { | ||
| delegationManagement, err := getDelegationManagement(g.eei, g.marshalizer, g.delegationMgrSCAddress) | ||
| if err != nil { | ||
|
|
@@ -756,41 +808,6 @@ func (g *governanceContract) viewConfig(args *vmcommon.ContractCallInput) vmcomm | |
| return vmcommon.Ok | ||
| } | ||
|
|
||
| func (g *governanceContract) viewUserVoteHistory(args *vmcommon.ContractCallInput) vmcommon.ReturnCode { | ||
| err := g.checkViewFuncArguments(args, 1) | ||
| if err != nil { | ||
| g.eei.AddReturnMessage(err.Error()) | ||
| return vmcommon.UserError | ||
| } | ||
|
|
||
| userVotes, err := g.getUserVotes(args.Arguments[0]) | ||
| if err != nil { | ||
| g.eei.AddReturnMessage(err.Error()) | ||
| return vmcommon.UserError | ||
| } | ||
|
|
||
| g.finishWithIntValue(len(userVotes.Delegated)) // first we send the number of delegated nonces and afterward the nonces | ||
| for _, val := range userVotes.Delegated { | ||
| g.finishWithIntValue(int(val)) | ||
| } | ||
|
|
||
| g.finishWithIntValue(len(userVotes.Direct)) // then we send the number of direct nonces and afterward the nonces | ||
| for _, val := range userVotes.Direct { | ||
| g.finishWithIntValue(int(val)) | ||
| } | ||
|
|
||
| return vmcommon.Ok | ||
| } | ||
|
|
||
| func (g *governanceContract) finishWithIntValue(value int) { | ||
| if value == 0 { | ||
| g.eei.Finish([]byte{0}) | ||
| return | ||
| } | ||
|
|
||
| g.eei.Finish(big.NewInt(int64(value)).Bytes()) | ||
| } | ||
|
|
||
| func (g *governanceContract) viewProposal(args *vmcommon.ContractCallInput) vmcommon.ReturnCode { | ||
| err := g.checkViewFuncArguments(args, 1) | ||
| if err != nil { | ||
|
|
@@ -1010,7 +1027,17 @@ func (g *governanceContract) getTotalStake(validatorAddress []byte) (*big.Int, e | |
| return validatorData.TotalStakeValue, nil | ||
| } | ||
|
|
||
| func (g *governanceContract) saveUserVotes(address []byte, votedList *OngoingVotedList) error { | ||
| func (g *governanceContract) saveUserVotesV1(address []byte, votedList *OngoingVotedList) error { | ||
| marshaledData, err := g.marshalizer.Marshal(votedList) | ||
dragos-rebegea marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| if err != nil { | ||
| return err | ||
| } | ||
| g.eei.SetStorage(address, marshaledData) | ||
|
|
||
| return nil | ||
| } | ||
|
|
||
| func (g *governanceContract) saveUserVotesV2(address []byte, votedList *OngoingVotedListV2) error { | ||
| marshaledData, err := g.marshalizer.Marshal(votedList) | ||
| if err != nil { | ||
| return err | ||
|
|
@@ -1020,7 +1047,7 @@ func (g *governanceContract) saveUserVotes(address []byte, votedList *OngoingVot | |
| return nil | ||
| } | ||
|
|
||
| func (g *governanceContract) getUserVotes(address []byte) (*OngoingVotedList, error) { | ||
| func (g *governanceContract) getUserVotesV1(address []byte) (*OngoingVotedList, error) { | ||
| onGoingList := &OngoingVotedList{ | ||
| Direct: make([]uint64, 0), | ||
| Delegated: make([]uint64, 0), | ||
|
|
@@ -1038,6 +1065,25 @@ func (g *governanceContract) getUserVotes(address []byte) (*OngoingVotedList, er | |
| return onGoingList, nil | ||
| } | ||
|
|
||
| // getUserVotesV2 returns the ongoing voted list for a user | ||
| // if the user has v1 ongoing list, it will be converted to v2, dropping Delegate field | ||
| func (g *governanceContract) getUserVotesV2(address []byte) (*OngoingVotedListV2, error) { | ||
| onGoingListV2 := &OngoingVotedListV2{ | ||
| Direct: make([]uint64, 0), | ||
| DelegatedWithAddress: make([]*DelegatedWithAddress, 0), | ||
| } | ||
| marshaledData := g.eei.GetStorage(address) | ||
| if len(marshaledData) == 0 { | ||
| return onGoingListV2, nil | ||
| } | ||
|
|
||
| err := g.marshalizer.Unmarshal(onGoingListV2, marshaledData) | ||
| if err != nil { | ||
| return nil, err | ||
| } | ||
| return onGoingListV2, nil | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You should return onGoingList not the v2 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. +1 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this method will be called only after GovernanceFixes gets activated, that means there is no ongoing v1 proposal, thus the information is not necessary anymore. |
||
| } | ||
|
|
||
| func (g *governanceContract) getDelegatedContractInfo(scAddress []byte, reference []byte) (*DelegatedSCVoteInfo, error) { | ||
| scVoteInfo := &DelegatedSCVoteInfo{ | ||
| TotalPower: big.NewInt(0), | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.