533 lines
14 KiB
Go
533 lines
14 KiB
Go
package v038
|
|
|
|
// DONTCOVER
|
|
// nolint
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"sort"
|
|
"strings"
|
|
|
|
"github.com/tendermint/tendermint/crypto"
|
|
|
|
"github.com/cosmos/cosmos-sdk/codec"
|
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
|
v034auth "github.com/cosmos/cosmos-sdk/x/auth/legacy/v0_34"
|
|
)
|
|
|
|
const (
|
|
ModuleName = "auth"
|
|
)
|
|
|
|
type (
|
|
// partial interface needed only for amino encoding and sanitization
|
|
Account interface {
|
|
GetAddress() sdk.AccAddress
|
|
GetAccountNumber() uint64
|
|
GetCoins() sdk.Coins
|
|
SetCoins(sdk.Coins) error
|
|
}
|
|
|
|
GenesisAccount interface {
|
|
Account
|
|
|
|
Validate() error
|
|
}
|
|
|
|
GenesisAccounts []GenesisAccount
|
|
|
|
GenesisState struct {
|
|
Params v034auth.Params `json:"params" yaml:"params"`
|
|
Accounts GenesisAccounts `json:"accounts" yaml:"accounts"`
|
|
}
|
|
|
|
BaseAccount struct {
|
|
Address sdk.AccAddress `json:"address" yaml:"address"`
|
|
Coins sdk.Coins `json:"coins,omitempty" yaml:"coins,omitempty"`
|
|
PubKey crypto.PubKey `json:"public_key" yaml:"public_key"`
|
|
AccountNumber uint64 `json:"account_number" yaml:"account_number"`
|
|
Sequence uint64 `json:"sequence" yaml:"sequence"`
|
|
}
|
|
|
|
baseAccountPretty struct {
|
|
Address sdk.AccAddress `json:"address" yaml:"address"`
|
|
Coins sdk.Coins `json:"coins,omitempty" yaml:"coins,omitempty"`
|
|
PubKey string `json:"public_key" yaml:"public_key"`
|
|
AccountNumber uint64 `json:"account_number" yaml:"account_number"`
|
|
Sequence uint64 `json:"sequence" yaml:"sequence"`
|
|
}
|
|
|
|
BaseVestingAccount struct {
|
|
*BaseAccount
|
|
|
|
OriginalVesting sdk.Coins `json:"original_vesting"`
|
|
DelegatedFree sdk.Coins `json:"delegated_free"`
|
|
DelegatedVesting sdk.Coins `json:"delegated_vesting"`
|
|
|
|
EndTime int64 `json:"end_time"`
|
|
}
|
|
|
|
vestingAccountPretty struct {
|
|
Address sdk.AccAddress `json:"address" yaml:"address"`
|
|
Coins sdk.Coins `json:"coins,omitempty" yaml:"coins,omitempty"`
|
|
PubKey string `json:"public_key" yaml:"public_key"`
|
|
AccountNumber uint64 `json:"account_number" yaml:"account_number"`
|
|
Sequence uint64 `json:"sequence" yaml:"sequence"`
|
|
OriginalVesting sdk.Coins `json:"original_vesting" yaml:"original_vesting"`
|
|
DelegatedFree sdk.Coins `json:"delegated_free" yaml:"delegated_free"`
|
|
DelegatedVesting sdk.Coins `json:"delegated_vesting" yaml:"delegated_vesting"`
|
|
EndTime int64 `json:"end_time" yaml:"end_time"`
|
|
|
|
// custom fields based on concrete vesting type which can be omitted
|
|
StartTime int64 `json:"start_time,omitempty" yaml:"start_time,omitempty"`
|
|
}
|
|
|
|
ContinuousVestingAccount struct {
|
|
*BaseVestingAccount
|
|
|
|
StartTime int64 `json:"start_time"`
|
|
}
|
|
|
|
DelayedVestingAccount struct {
|
|
*BaseVestingAccount
|
|
}
|
|
|
|
ModuleAccount struct {
|
|
*BaseAccount
|
|
|
|
Name string `json:"name" yaml:"name"`
|
|
Permissions []string `json:"permissions" yaml:"permissions"`
|
|
}
|
|
|
|
moduleAccountPretty struct {
|
|
Address sdk.AccAddress `json:"address" yaml:"address"`
|
|
Coins sdk.Coins `json:"coins,omitempty" yaml:"coins,omitempty"`
|
|
PubKey string `json:"public_key" yaml:"public_key"`
|
|
AccountNumber uint64 `json:"account_number" yaml:"account_number"`
|
|
Sequence uint64 `json:"sequence" yaml:"sequence"`
|
|
Name string `json:"name" yaml:"name"`
|
|
Permissions []string `json:"permissions" yaml:"permissions"`
|
|
}
|
|
)
|
|
|
|
func NewGenesisState(params v034auth.Params, accounts GenesisAccounts) GenesisState {
|
|
return GenesisState{
|
|
Params: params,
|
|
Accounts: accounts,
|
|
}
|
|
}
|
|
|
|
func NewBaseAccountWithAddress(addr sdk.AccAddress) BaseAccount {
|
|
return BaseAccount{
|
|
Address: addr,
|
|
}
|
|
}
|
|
|
|
func NewBaseAccount(
|
|
address sdk.AccAddress, coins sdk.Coins, pk crypto.PubKey, accountNumber, sequence uint64,
|
|
) *BaseAccount {
|
|
|
|
return &BaseAccount{
|
|
Address: address,
|
|
Coins: coins,
|
|
PubKey: pk,
|
|
AccountNumber: accountNumber,
|
|
Sequence: sequence,
|
|
}
|
|
}
|
|
|
|
func (acc BaseAccount) GetAddress() sdk.AccAddress {
|
|
return acc.Address
|
|
}
|
|
|
|
func (acc *BaseAccount) GetAccountNumber() uint64 {
|
|
return acc.AccountNumber
|
|
}
|
|
|
|
func (acc *BaseAccount) GetCoins() sdk.Coins {
|
|
return acc.Coins
|
|
}
|
|
|
|
func (acc *BaseAccount) SetCoins(coins sdk.Coins) error {
|
|
acc.Coins = coins
|
|
return nil
|
|
}
|
|
|
|
func (acc BaseAccount) Validate() error {
|
|
if acc.PubKey != nil && acc.Address != nil &&
|
|
!bytes.Equal(acc.PubKey.Address().Bytes(), acc.Address.Bytes()) {
|
|
return errors.New("pubkey and address pair is invalid")
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (acc BaseAccount) MarshalJSON() ([]byte, error) {
|
|
alias := baseAccountPretty{
|
|
Address: acc.Address,
|
|
Coins: acc.Coins,
|
|
AccountNumber: acc.AccountNumber,
|
|
Sequence: acc.Sequence,
|
|
}
|
|
|
|
if acc.PubKey != nil {
|
|
pks, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, acc.PubKey)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
alias.PubKey = pks
|
|
}
|
|
|
|
return json.Marshal(alias)
|
|
}
|
|
|
|
// UnmarshalJSON unmarshals raw JSON bytes into a BaseAccount.
|
|
func (acc *BaseAccount) UnmarshalJSON(bz []byte) error {
|
|
var alias baseAccountPretty
|
|
if err := json.Unmarshal(bz, &alias); err != nil {
|
|
return err
|
|
}
|
|
|
|
if alias.PubKey != "" {
|
|
pk, err := sdk.GetPubKeyFromBech32(sdk.Bech32PubKeyTypeAccPub, alias.PubKey)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
acc.PubKey = pk
|
|
}
|
|
|
|
acc.Address = alias.Address
|
|
acc.Coins = alias.Coins
|
|
acc.AccountNumber = alias.AccountNumber
|
|
acc.Sequence = alias.Sequence
|
|
|
|
return nil
|
|
}
|
|
|
|
func NewBaseVestingAccount(
|
|
baseAccount *BaseAccount, originalVesting, delegatedFree, delegatedVesting sdk.Coins, endTime int64,
|
|
) *BaseVestingAccount {
|
|
|
|
return &BaseVestingAccount{
|
|
BaseAccount: baseAccount,
|
|
OriginalVesting: originalVesting,
|
|
DelegatedFree: delegatedFree,
|
|
DelegatedVesting: delegatedVesting,
|
|
EndTime: endTime,
|
|
}
|
|
}
|
|
|
|
func (bva BaseVestingAccount) Validate() error {
|
|
if (bva.Coins.IsZero() && !bva.OriginalVesting.IsZero()) ||
|
|
bva.OriginalVesting.IsAnyGT(bva.Coins) {
|
|
return errors.New("vesting amount cannot be greater than total amount")
|
|
}
|
|
|
|
return bva.BaseAccount.Validate()
|
|
}
|
|
|
|
// MarshalJSON returns the JSON representation of a BaseVestingAccount.
|
|
func (bva BaseVestingAccount) MarshalJSON() ([]byte, error) {
|
|
alias := vestingAccountPretty{
|
|
Address: bva.Address,
|
|
Coins: bva.Coins,
|
|
AccountNumber: bva.AccountNumber,
|
|
Sequence: bva.Sequence,
|
|
OriginalVesting: bva.OriginalVesting,
|
|
DelegatedFree: bva.DelegatedFree,
|
|
DelegatedVesting: bva.DelegatedVesting,
|
|
EndTime: bva.EndTime,
|
|
}
|
|
|
|
if bva.PubKey != nil {
|
|
pks, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, bva.PubKey)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
alias.PubKey = pks
|
|
}
|
|
|
|
return json.Marshal(alias)
|
|
}
|
|
|
|
// UnmarshalJSON unmarshals raw JSON bytes into a BaseVestingAccount.
|
|
func (bva *BaseVestingAccount) UnmarshalJSON(bz []byte) error {
|
|
var alias vestingAccountPretty
|
|
if err := json.Unmarshal(bz, &alias); err != nil {
|
|
return err
|
|
}
|
|
|
|
var (
|
|
pk crypto.PubKey
|
|
err error
|
|
)
|
|
|
|
if alias.PubKey != "" {
|
|
pk, err = sdk.GetPubKeyFromBech32(sdk.Bech32PubKeyTypeAccPub, alias.PubKey)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
bva.BaseAccount = NewBaseAccount(alias.Address, alias.Coins, pk, alias.AccountNumber, alias.Sequence)
|
|
bva.OriginalVesting = alias.OriginalVesting
|
|
bva.DelegatedFree = alias.DelegatedFree
|
|
bva.DelegatedVesting = alias.DelegatedVesting
|
|
bva.EndTime = alias.EndTime
|
|
|
|
return nil
|
|
}
|
|
|
|
func NewContinuousVestingAccountRaw(bva *BaseVestingAccount, startTime int64) *ContinuousVestingAccount {
|
|
return &ContinuousVestingAccount{
|
|
BaseVestingAccount: bva,
|
|
StartTime: startTime,
|
|
}
|
|
}
|
|
|
|
func (cva ContinuousVestingAccount) Validate() error {
|
|
if cva.StartTime >= cva.EndTime {
|
|
return errors.New("vesting start-time cannot be before end-time")
|
|
}
|
|
|
|
return cva.BaseVestingAccount.Validate()
|
|
}
|
|
|
|
// MarshalJSON returns the JSON representation of a ContinuousVestingAccount.
|
|
func (cva ContinuousVestingAccount) MarshalJSON() ([]byte, error) {
|
|
alias := vestingAccountPretty{
|
|
Address: cva.Address,
|
|
Coins: cva.Coins,
|
|
AccountNumber: cva.AccountNumber,
|
|
Sequence: cva.Sequence,
|
|
OriginalVesting: cva.OriginalVesting,
|
|
DelegatedFree: cva.DelegatedFree,
|
|
DelegatedVesting: cva.DelegatedVesting,
|
|
EndTime: cva.EndTime,
|
|
StartTime: cva.StartTime,
|
|
}
|
|
|
|
if cva.PubKey != nil {
|
|
pks, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, cva.PubKey)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
alias.PubKey = pks
|
|
}
|
|
|
|
return json.Marshal(alias)
|
|
}
|
|
|
|
// UnmarshalJSON unmarshals raw JSON bytes into a ContinuousVestingAccount.
|
|
func (cva *ContinuousVestingAccount) UnmarshalJSON(bz []byte) error {
|
|
var alias vestingAccountPretty
|
|
if err := json.Unmarshal(bz, &alias); err != nil {
|
|
return err
|
|
}
|
|
|
|
var (
|
|
pk crypto.PubKey
|
|
err error
|
|
)
|
|
|
|
if alias.PubKey != "" {
|
|
pk, err = sdk.GetPubKeyFromBech32(sdk.Bech32PubKeyTypeAccPub, alias.PubKey)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
cva.BaseVestingAccount = &BaseVestingAccount{
|
|
BaseAccount: NewBaseAccount(alias.Address, alias.Coins, pk, alias.AccountNumber, alias.Sequence),
|
|
OriginalVesting: alias.OriginalVesting,
|
|
DelegatedFree: alias.DelegatedFree,
|
|
DelegatedVesting: alias.DelegatedVesting,
|
|
EndTime: alias.EndTime,
|
|
}
|
|
cva.StartTime = alias.StartTime
|
|
|
|
return nil
|
|
}
|
|
|
|
func NewDelayedVestingAccountRaw(bva *BaseVestingAccount) *DelayedVestingAccount {
|
|
return &DelayedVestingAccount{
|
|
BaseVestingAccount: bva,
|
|
}
|
|
}
|
|
|
|
func (dva DelayedVestingAccount) Validate() error {
|
|
return dva.BaseVestingAccount.Validate()
|
|
}
|
|
|
|
// MarshalJSON returns the JSON representation of a DelayedVestingAccount.
|
|
func (dva DelayedVestingAccount) MarshalJSON() ([]byte, error) {
|
|
alias := vestingAccountPretty{
|
|
Address: dva.Address,
|
|
Coins: dva.Coins,
|
|
AccountNumber: dva.AccountNumber,
|
|
Sequence: dva.Sequence,
|
|
OriginalVesting: dva.OriginalVesting,
|
|
DelegatedFree: dva.DelegatedFree,
|
|
DelegatedVesting: dva.DelegatedVesting,
|
|
EndTime: dva.EndTime,
|
|
}
|
|
|
|
if dva.PubKey != nil {
|
|
pks, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, dva.PubKey)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
alias.PubKey = pks
|
|
}
|
|
|
|
return json.Marshal(alias)
|
|
}
|
|
|
|
// UnmarshalJSON unmarshals raw JSON bytes into a DelayedVestingAccount.
|
|
func (dva *DelayedVestingAccount) UnmarshalJSON(bz []byte) error {
|
|
var alias vestingAccountPretty
|
|
if err := json.Unmarshal(bz, &alias); err != nil {
|
|
return err
|
|
}
|
|
|
|
var (
|
|
pk crypto.PubKey
|
|
err error
|
|
)
|
|
|
|
if alias.PubKey != "" {
|
|
pk, err = sdk.GetPubKeyFromBech32(sdk.Bech32PubKeyTypeAccPub, alias.PubKey)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
dva.BaseVestingAccount = &BaseVestingAccount{
|
|
BaseAccount: NewBaseAccount(alias.Address, alias.Coins, pk, alias.AccountNumber, alias.Sequence),
|
|
OriginalVesting: alias.OriginalVesting,
|
|
DelegatedFree: alias.DelegatedFree,
|
|
DelegatedVesting: alias.DelegatedVesting,
|
|
EndTime: alias.EndTime,
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func NewModuleAddress(name string) sdk.AccAddress {
|
|
return sdk.AccAddress(crypto.AddressHash([]byte(name)))
|
|
}
|
|
|
|
func NewModuleAccount(baseAccount *BaseAccount, name string, permissions ...string) *ModuleAccount {
|
|
return &ModuleAccount{
|
|
BaseAccount: baseAccount,
|
|
Name: name,
|
|
Permissions: permissions,
|
|
}
|
|
}
|
|
|
|
func (ma ModuleAccount) Validate() error {
|
|
if err := ValidatePermissions(ma.Permissions...); err != nil {
|
|
return err
|
|
}
|
|
|
|
if strings.TrimSpace(ma.Name) == "" {
|
|
return errors.New("module account name cannot be blank")
|
|
}
|
|
|
|
if !ma.Address.Equals(sdk.AccAddress(crypto.AddressHash([]byte(ma.Name)))) {
|
|
return fmt.Errorf("address %s cannot be derived from the module name '%s'", ma.Address, ma.Name)
|
|
}
|
|
|
|
return ma.BaseAccount.Validate()
|
|
}
|
|
|
|
// MarshalJSON returns the JSON representation of a ModuleAccount.
|
|
func (ma ModuleAccount) MarshalJSON() ([]byte, error) {
|
|
return json.Marshal(moduleAccountPretty{
|
|
Address: ma.Address,
|
|
Coins: ma.Coins,
|
|
PubKey: "",
|
|
AccountNumber: ma.AccountNumber,
|
|
Sequence: ma.Sequence,
|
|
Name: ma.Name,
|
|
Permissions: ma.Permissions,
|
|
})
|
|
}
|
|
|
|
// UnmarshalJSON unmarshals raw JSON bytes into a ModuleAccount.
|
|
func (ma *ModuleAccount) UnmarshalJSON(bz []byte) error {
|
|
var alias moduleAccountPretty
|
|
if err := json.Unmarshal(bz, &alias); err != nil {
|
|
return err
|
|
}
|
|
|
|
ma.BaseAccount = NewBaseAccount(alias.Address, alias.Coins, nil, alias.AccountNumber, alias.Sequence)
|
|
ma.Name = alias.Name
|
|
ma.Permissions = alias.Permissions
|
|
|
|
return nil
|
|
}
|
|
|
|
func ValidatePermissions(permissions ...string) error {
|
|
for _, perm := range permissions {
|
|
if strings.TrimSpace(perm) == "" {
|
|
return fmt.Errorf("module permission is empty")
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func SanitizeGenesisAccounts(genAccounts GenesisAccounts) GenesisAccounts {
|
|
sort.Slice(genAccounts, func(i, j int) bool {
|
|
return genAccounts[i].GetAccountNumber() < genAccounts[j].GetAccountNumber()
|
|
})
|
|
|
|
for _, acc := range genAccounts {
|
|
if err := acc.SetCoins(acc.GetCoins().Sort()); err != nil {
|
|
panic(err)
|
|
}
|
|
}
|
|
|
|
return genAccounts
|
|
}
|
|
|
|
func ValidateGenAccounts(genAccounts GenesisAccounts) error {
|
|
addrMap := make(map[string]bool, len(genAccounts))
|
|
for _, acc := range genAccounts {
|
|
|
|
// check for duplicated accounts
|
|
addrStr := acc.GetAddress().String()
|
|
if _, ok := addrMap[addrStr]; ok {
|
|
return fmt.Errorf("duplicate account found in genesis state; address: %s", addrStr)
|
|
}
|
|
|
|
addrMap[addrStr] = true
|
|
|
|
// check account specific validation
|
|
if err := acc.Validate(); err != nil {
|
|
return fmt.Errorf("invalid account found in genesis state; address: %s, error: %s", addrStr, err.Error())
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) {
|
|
cdc.RegisterInterface((*GenesisAccount)(nil), nil)
|
|
cdc.RegisterInterface((*Account)(nil), nil)
|
|
cdc.RegisterConcrete(&BaseAccount{}, "cosmos-sdk/Account", nil)
|
|
cdc.RegisterConcrete(&BaseVestingAccount{}, "cosmos-sdk/BaseVestingAccount", nil)
|
|
cdc.RegisterConcrete(&ContinuousVestingAccount{}, "cosmos-sdk/ContinuousVestingAccount", nil)
|
|
cdc.RegisterConcrete(&DelayedVestingAccount{}, "cosmos-sdk/DelayedVestingAccount", nil)
|
|
cdc.RegisterConcrete(&ModuleAccount{}, "cosmos-sdk/ModuleAccount", nil)
|
|
}
|