mirror of
				https://github.com/0glabs/0g-chain.git
				synced 2025-11-04 15:37:27 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			199 lines
		
	
	
		
			5.1 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			199 lines
		
	
	
		
			5.1 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
package cli
 | 
						|
 | 
						|
import (
 | 
						|
	"bufio"
 | 
						|
	"bytes"
 | 
						|
	"encoding/hex"
 | 
						|
	"errors"
 | 
						|
	"fmt"
 | 
						|
	"strconv"
 | 
						|
 | 
						|
	sdkmath "cosmossdk.io/math"
 | 
						|
	"github.com/0glabs/0g-chain/crypto/vrf"
 | 
						|
	"github.com/0glabs/0g-chain/x/council/v1/types"
 | 
						|
	"github.com/cosmos/cosmos-sdk/client"
 | 
						|
	"github.com/cosmos/cosmos-sdk/client/flags"
 | 
						|
	"github.com/cosmos/cosmos-sdk/client/tx"
 | 
						|
	sdkkr "github.com/cosmos/cosmos-sdk/crypto/keyring"
 | 
						|
	sdk "github.com/cosmos/cosmos-sdk/types"
 | 
						|
	stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
 | 
						|
 | 
						|
	vrfalgo "github.com/coniks-sys/coniks-go/crypto/vrf"
 | 
						|
	"github.com/cosmos/cosmos-sdk/client/input"
 | 
						|
	"github.com/spf13/cobra"
 | 
						|
)
 | 
						|
 | 
						|
// GetTxCmd returns the transaction commands for this module
 | 
						|
func GetTxCmd() *cobra.Command {
 | 
						|
	cmd := &cobra.Command{
 | 
						|
		Use:                        types.ModuleName,
 | 
						|
		Short:                      fmt.Sprintf("%s transactions subcommands", types.ModuleName),
 | 
						|
		DisableFlagParsing:         true,
 | 
						|
		SuggestionsMinimumDistance: 2,
 | 
						|
		RunE:                       client.ValidateCmd,
 | 
						|
	}
 | 
						|
	cmd.AddCommand(
 | 
						|
		NewRegisterCmd(),
 | 
						|
		NewVoteCmd(),
 | 
						|
	)
 | 
						|
	return cmd
 | 
						|
}
 | 
						|
 | 
						|
func NewRegisterCmd() *cobra.Command {
 | 
						|
	cmd := &cobra.Command{
 | 
						|
		Use:   "register",
 | 
						|
		Short: "Register a voter",
 | 
						|
		Args:  cobra.NoArgs,
 | 
						|
		RunE: func(cmd *cobra.Command, args []string) error {
 | 
						|
			// bypass the restriction of set keyring options
 | 
						|
			ctx := client.GetClientContextFromCmd(cmd).WithKeyringOptions(vrf.VrfOption())
 | 
						|
			client.SetCmdClientContext(cmd, ctx)
 | 
						|
			clientCtx, err := client.GetClientTxContext(cmd)
 | 
						|
			if err != nil {
 | 
						|
				return err
 | 
						|
			}
 | 
						|
 | 
						|
			kr := clientCtx.Keyring
 | 
						|
			// get account name by address
 | 
						|
			accAddr := clientCtx.GetFromAddress()
 | 
						|
			accRecord, err := kr.KeyByAddress(accAddr)
 | 
						|
			if err != nil {
 | 
						|
				// not found record by address in keyring
 | 
						|
				return nil
 | 
						|
			}
 | 
						|
 | 
						|
			// check voter account record exists
 | 
						|
			voterAccName := accRecord.Name + "-voter"
 | 
						|
			_, err = kr.Key(voterAccName)
 | 
						|
			if err == nil {
 | 
						|
				// account exists, ask for user confirmation
 | 
						|
				response, err2 := input.GetConfirmation(fmt.Sprintf("override the existing name %s", voterAccName), bufio.NewReader(clientCtx.Input), cmd.ErrOrStderr())
 | 
						|
				if err2 != nil {
 | 
						|
					return err2
 | 
						|
				}
 | 
						|
 | 
						|
				if !response {
 | 
						|
					return errors.New("aborted")
 | 
						|
				}
 | 
						|
 | 
						|
				err2 = kr.Delete(voterAccName)
 | 
						|
				if err2 != nil {
 | 
						|
					return err2
 | 
						|
				}
 | 
						|
			}
 | 
						|
 | 
						|
			keyringAlgos, _ := kr.SupportedAlgorithms()
 | 
						|
			algo, err := sdkkr.NewSigningAlgoFromString("vrf", keyringAlgos)
 | 
						|
			if err != nil {
 | 
						|
				return err
 | 
						|
			}
 | 
						|
 | 
						|
			newRecord, err := kr.NewAccount(voterAccName, "", "", "", algo)
 | 
						|
			if err != nil {
 | 
						|
				return err
 | 
						|
			}
 | 
						|
 | 
						|
			pubKey, err := newRecord.GetPubKey()
 | 
						|
			if err != nil {
 | 
						|
				return err
 | 
						|
			}
 | 
						|
 | 
						|
			valAddr, err := sdk.ValAddressFromHex(hex.EncodeToString(clientCtx.GetFromAddress().Bytes()))
 | 
						|
			if err != nil {
 | 
						|
				return err
 | 
						|
			}
 | 
						|
 | 
						|
			msg := &types.MsgRegister{
 | 
						|
				Voter: valAddr.String(),
 | 
						|
				Key:   pubKey.Bytes(),
 | 
						|
			}
 | 
						|
			return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg)
 | 
						|
		},
 | 
						|
	}
 | 
						|
 | 
						|
	flags.AddTxFlagsToCmd(cmd)
 | 
						|
	return cmd
 | 
						|
}
 | 
						|
 | 
						|
func NewVoteCmd() *cobra.Command {
 | 
						|
	cmd := &cobra.Command{
 | 
						|
		Use:   "vote council-id",
 | 
						|
		Short: "Vote on a proposal",
 | 
						|
		Args:  cobra.MinimumNArgs(1),
 | 
						|
		RunE: func(cmd *cobra.Command, args []string) error {
 | 
						|
			clientCtx, err := client.GetClientTxContext(cmd)
 | 
						|
			if err != nil {
 | 
						|
				return err
 | 
						|
			}
 | 
						|
 | 
						|
			kr := clientCtx.Keyring
 | 
						|
 | 
						|
			// get account name by address
 | 
						|
			inAddr := clientCtx.GetFromAddress()
 | 
						|
 | 
						|
			valAddr, err := sdk.ValAddressFromHex(hex.EncodeToString(inAddr.Bytes()))
 | 
						|
			if err != nil {
 | 
						|
				return err
 | 
						|
			}
 | 
						|
 | 
						|
			inRecord, err := kr.KeyByAddress(inAddr)
 | 
						|
			if err != nil {
 | 
						|
				// not found record by address in keyring
 | 
						|
				return nil
 | 
						|
			}
 | 
						|
 | 
						|
			// check voter account record exists
 | 
						|
			voterAccName := inRecord.Name + "-voter"
 | 
						|
			voterRecord, err := kr.Key(voterAccName)
 | 
						|
			if err != nil {
 | 
						|
				// not found voter account
 | 
						|
				return err
 | 
						|
			}
 | 
						|
			sk := vrfalgo.PrivateKey(voterRecord.GetLocal().PrivKey.Value)
 | 
						|
 | 
						|
			councilID, err := strconv.ParseUint(args[0], 10, 64)
 | 
						|
			if err != nil {
 | 
						|
				return err
 | 
						|
			}
 | 
						|
 | 
						|
			votingStartHeight := types.DefaultVotingStartHeight + (councilID-1)*types.DefaultVotingPeriod
 | 
						|
 | 
						|
			rsp, err := stakingtypes.NewQueryClient(clientCtx).HistoricalInfo(cmd.Context(), &stakingtypes.QueryHistoricalInfoRequest{Height: int64(votingStartHeight)})
 | 
						|
			if err != nil {
 | 
						|
				return err
 | 
						|
			}
 | 
						|
 | 
						|
			var tokens sdkmath.Int
 | 
						|
			for _, val := range rsp.Hist.Valset {
 | 
						|
				thisValAddr := val.GetOperator()
 | 
						|
 | 
						|
				if thisValAddr.Equals(valAddr) {
 | 
						|
					tokens = val.GetTokens()
 | 
						|
				}
 | 
						|
			}
 | 
						|
			// the denom of token is evm denom, need to convert to A0GI
 | 
						|
			a0giTokenCnt := tokens.Quo(sdk.NewInt(1_000_000_000_000_000_000))
 | 
						|
			// 1_000 0AGI token / vote
 | 
						|
			numBallots := a0giTokenCnt.Quo(sdk.NewInt(1_000)).Uint64()
 | 
						|
			ballots := make([]*types.Ballot, numBallots)
 | 
						|
			for i := range ballots {
 | 
						|
				ballotID := uint64(i)
 | 
						|
				ballots[i] = &types.Ballot{
 | 
						|
					ID:      ballotID,
 | 
						|
					Content: sk.Compute(bytes.Join([][]byte{rsp.Hist.Header.LastCommitHash, types.Uint64ToBytes(ballotID)}, nil)),
 | 
						|
				}
 | 
						|
			}
 | 
						|
 | 
						|
			msg := &types.MsgVote{
 | 
						|
				CouncilID: councilID,
 | 
						|
				Voter:     valAddr.String(),
 | 
						|
				Ballots:   ballots,
 | 
						|
			}
 | 
						|
			return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg)
 | 
						|
		},
 | 
						|
	}
 | 
						|
 | 
						|
	flags.AddTxFlagsToCmd(cmd)
 | 
						|
	return cmd
 | 
						|
}
 |