github.com/Finschia/finschia-sdk@v0.49.1/x/auth/types/account.go (about)

     1  package types
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/json"
     6  	"errors"
     7  	"fmt"
     8  	"strings"
     9  
    10  	"github.com/Finschia/ostracon/crypto"
    11  	"github.com/gogo/protobuf/proto"
    12  	"gopkg.in/yaml.v2"
    13  
    14  	"github.com/Finschia/finschia-sdk/codec"
    15  	codectypes "github.com/Finschia/finschia-sdk/codec/types"
    16  	cryptotypes "github.com/Finschia/finschia-sdk/crypto/types"
    17  	sdk "github.com/Finschia/finschia-sdk/types"
    18  )
    19  
    20  var (
    21  	_ AccountI                           = (*BaseAccount)(nil)
    22  	_ GenesisAccount                     = (*BaseAccount)(nil)
    23  	_ codectypes.UnpackInterfacesMessage = (*BaseAccount)(nil)
    24  	_ GenesisAccount                     = (*ModuleAccount)(nil)
    25  	_ ModuleAccountI                     = (*ModuleAccount)(nil)
    26  )
    27  
    28  // NewBaseAccount creates a new BaseAccount object
    29  //
    30  //nolint:interfacer
    31  func NewBaseAccount(address sdk.AccAddress, pubKey cryptotypes.PubKey, accountNumber, sequence uint64) *BaseAccount {
    32  	acc := &BaseAccount{
    33  		Address:       address.String(),
    34  		AccountNumber: accountNumber,
    35  		Sequence:      sequence,
    36  	}
    37  
    38  	err := acc.SetPubKey(pubKey)
    39  	if err != nil {
    40  		panic(err)
    41  	}
    42  
    43  	return acc
    44  }
    45  
    46  // ProtoBaseAccount - a prototype function for BaseAccount
    47  func ProtoBaseAccount() AccountI {
    48  	return &BaseAccount{}
    49  }
    50  
    51  // NewBaseAccountWithAddress - returns a new base account with a given address
    52  // leaving AccountNumber and Sequence to zero.
    53  func NewBaseAccountWithAddress(addr sdk.AccAddress) *BaseAccount {
    54  	return &BaseAccount{
    55  		Address: addr.String(),
    56  	}
    57  }
    58  
    59  // GetAddress - Implements sdk.AccountI.
    60  func (acc BaseAccount) GetAddress() sdk.AccAddress {
    61  	addr := sdk.MustAccAddressFromBech32(acc.Address)
    62  	return addr
    63  }
    64  
    65  // SetAddress - Implements sdk.AccountI.
    66  func (acc *BaseAccount) SetAddress(addr sdk.AccAddress) error {
    67  	if len(acc.Address) != 0 {
    68  		return errors.New("cannot override BaseAccount address")
    69  	}
    70  
    71  	acc.Address = addr.String()
    72  	return nil
    73  }
    74  
    75  // GetPubKey - Implements sdk.AccountI.
    76  func (acc BaseAccount) GetPubKey() (pk cryptotypes.PubKey) {
    77  	if acc.PubKey == nil {
    78  		return nil
    79  	}
    80  	content, ok := acc.PubKey.GetCachedValue().(cryptotypes.PubKey)
    81  	if !ok {
    82  		return nil
    83  	}
    84  	return content
    85  }
    86  
    87  // SetPubKey - Implements sdk.AccountI.
    88  func (acc *BaseAccount) SetPubKey(pubKey cryptotypes.PubKey) error {
    89  	if pubKey == nil {
    90  		acc.PubKey = nil
    91  		return nil
    92  	}
    93  	any, err := codectypes.NewAnyWithValue(pubKey)
    94  	if err == nil {
    95  		acc.PubKey = any
    96  	}
    97  	return err
    98  }
    99  
   100  // GetAccountNumber - Implements AccountI
   101  func (acc BaseAccount) GetAccountNumber() uint64 {
   102  	return acc.AccountNumber
   103  }
   104  
   105  // SetAccountNumber - Implements AccountI
   106  func (acc *BaseAccount) SetAccountNumber(accNumber uint64) error {
   107  	acc.AccountNumber = accNumber
   108  	return nil
   109  }
   110  
   111  // GetSequence - Implements sdk.AccountI.
   112  func (acc BaseAccount) GetSequence() uint64 {
   113  	return acc.Sequence
   114  }
   115  
   116  // SetSequence - Implements sdk.AccountI.
   117  func (acc *BaseAccount) SetSequence(seq uint64) error {
   118  	acc.Sequence = seq
   119  	return nil
   120  }
   121  
   122  // Validate checks for errors on the account fields
   123  func (acc BaseAccount) Validate() error {
   124  	if acc.Address == "" || acc.PubKey == nil {
   125  		return nil
   126  	}
   127  
   128  	accAddr, err := sdk.AccAddressFromBech32(acc.Address)
   129  	if err != nil {
   130  		return err
   131  	}
   132  
   133  	if !bytes.Equal(acc.GetPubKey().Address().Bytes(), accAddr.Bytes()) {
   134  		return errors.New("account address and pubkey address do not match")
   135  	}
   136  
   137  	return nil
   138  }
   139  
   140  func (acc BaseAccount) String() string {
   141  	out, _ := acc.MarshalYAML()
   142  	return out.(string)
   143  }
   144  
   145  // MarshalYAML returns the YAML representation of an account.
   146  func (acc BaseAccount) MarshalYAML() (interface{}, error) {
   147  	bz, err := codec.MarshalYAML(codec.NewProtoCodec(codectypes.NewInterfaceRegistry()), &acc)
   148  	if err != nil {
   149  		return nil, err
   150  	}
   151  	return string(bz), err
   152  }
   153  
   154  // UnpackInterfaces implements UnpackInterfacesMessage.UnpackInterfaces
   155  func (acc BaseAccount) UnpackInterfaces(unpacker codectypes.AnyUnpacker) error {
   156  	if acc.PubKey == nil {
   157  		return nil
   158  	}
   159  	var pubKey cryptotypes.PubKey
   160  	return unpacker.UnpackAny(acc.PubKey, &pubKey)
   161  }
   162  
   163  // NewModuleAddress creates an AccAddress from the hash of the module's name
   164  func NewModuleAddress(name string) sdk.AccAddress {
   165  	return sdk.AccAddress(crypto.AddressHash([]byte(name)))
   166  }
   167  
   168  // NewEmptyModuleAccount creates a empty ModuleAccount from a string
   169  func NewEmptyModuleAccount(name string, permissions ...string) *ModuleAccount {
   170  	moduleAddress := NewModuleAddress(name)
   171  	baseAcc := NewBaseAccountWithAddress(moduleAddress)
   172  
   173  	if err := validatePermissions(permissions...); err != nil {
   174  		panic(err)
   175  	}
   176  
   177  	return &ModuleAccount{
   178  		BaseAccount: baseAcc,
   179  		Name:        name,
   180  		Permissions: permissions,
   181  	}
   182  }
   183  
   184  // NewModuleAccount creates a new ModuleAccount instance
   185  func NewModuleAccount(ba *BaseAccount, name string, permissions ...string) *ModuleAccount {
   186  	if err := validatePermissions(permissions...); err != nil {
   187  		panic(err)
   188  	}
   189  
   190  	return &ModuleAccount{
   191  		BaseAccount: ba,
   192  		Name:        name,
   193  		Permissions: permissions,
   194  	}
   195  }
   196  
   197  // HasPermission returns whether or not the module account has permission.
   198  func (ma ModuleAccount) HasPermission(permission string) bool {
   199  	for _, perm := range ma.Permissions {
   200  		if perm == permission {
   201  			return true
   202  		}
   203  	}
   204  	return false
   205  }
   206  
   207  // GetName returns the the name of the holder's module
   208  func (ma ModuleAccount) GetName() string {
   209  	return ma.Name
   210  }
   211  
   212  // GetPermissions returns permissions granted to the module account
   213  func (ma ModuleAccount) GetPermissions() []string {
   214  	return ma.Permissions
   215  }
   216  
   217  // SetPubKey - Implements AccountI
   218  func (ma ModuleAccount) SetPubKey(pubKey cryptotypes.PubKey) error {
   219  	return fmt.Errorf("not supported for module accounts")
   220  }
   221  
   222  // Validate checks for errors on the account fields
   223  func (ma ModuleAccount) Validate() error {
   224  	if strings.TrimSpace(ma.Name) == "" {
   225  		return errors.New("module account name cannot be blank")
   226  	}
   227  
   228  	if ma.BaseAccount == nil {
   229  		return errors.New("uninitialized ModuleAccount: BaseAccount is nil")
   230  	}
   231  
   232  	if ma.Address != sdk.AccAddress(crypto.AddressHash([]byte(ma.Name))).String() {
   233  		return fmt.Errorf("address %s cannot be derived from the module name '%s'", ma.Address, ma.Name)
   234  	}
   235  
   236  	return ma.BaseAccount.Validate()
   237  }
   238  
   239  type moduleAccountPretty struct {
   240  	Address       sdk.AccAddress `json:"address" yaml:"address"`
   241  	PubKey        string         `json:"public_key" yaml:"public_key"`
   242  	AccountNumber uint64         `json:"account_number" yaml:"account_number"`
   243  	Sequence      uint64         `json:"sequence" yaml:"sequence"`
   244  	Name          string         `json:"name" yaml:"name"`
   245  	Permissions   []string       `json:"permissions" yaml:"permissions"`
   246  }
   247  
   248  func (ma ModuleAccount) String() string {
   249  	out, _ := ma.MarshalYAML()
   250  	return out.(string)
   251  }
   252  
   253  // MarshalYAML returns the YAML representation of a ModuleAccount.
   254  func (ma ModuleAccount) MarshalYAML() (interface{}, error) {
   255  	accAddr, err := sdk.AccAddressFromBech32(ma.Address)
   256  	if err != nil {
   257  		return nil, err
   258  	}
   259  
   260  	bs, err := yaml.Marshal(moduleAccountPretty{
   261  		Address:       accAddr,
   262  		PubKey:        "",
   263  		AccountNumber: ma.AccountNumber,
   264  		Sequence:      ma.Sequence,
   265  		Name:          ma.Name,
   266  		Permissions:   ma.Permissions,
   267  	})
   268  	if err != nil {
   269  		return nil, err
   270  	}
   271  
   272  	return string(bs), nil
   273  }
   274  
   275  // MarshalJSON returns the JSON representation of a ModuleAccount.
   276  func (ma ModuleAccount) MarshalJSON() ([]byte, error) {
   277  	accAddr, err := sdk.AccAddressFromBech32(ma.Address)
   278  	if err != nil {
   279  		return nil, err
   280  	}
   281  
   282  	return json.Marshal(moduleAccountPretty{
   283  		Address:       accAddr,
   284  		PubKey:        "",
   285  		AccountNumber: ma.AccountNumber,
   286  		Sequence:      ma.Sequence,
   287  		Name:          ma.Name,
   288  		Permissions:   ma.Permissions,
   289  	})
   290  }
   291  
   292  // UnmarshalJSON unmarshals raw JSON bytes into a ModuleAccount.
   293  func (ma *ModuleAccount) UnmarshalJSON(bz []byte) error {
   294  	var alias moduleAccountPretty
   295  	if err := json.Unmarshal(bz, &alias); err != nil {
   296  		return err
   297  	}
   298  
   299  	ma.BaseAccount = NewBaseAccount(alias.Address, nil, alias.AccountNumber, alias.Sequence)
   300  	ma.Name = alias.Name
   301  	ma.Permissions = alias.Permissions
   302  
   303  	return nil
   304  }
   305  
   306  // AccountI is an interface used to store coins at a given address within state.
   307  // It presumes a notion of sequence numbers for replay protection,
   308  // a notion of account numbers for replay protection for previously pruned accounts,
   309  // and a pubkey for authentication purposes.
   310  //
   311  // Many complex conditions can be used in the concrete struct which implements AccountI.
   312  type AccountI interface {
   313  	proto.Message
   314  
   315  	GetAddress() sdk.AccAddress
   316  	SetAddress(sdk.AccAddress) error // errors if already set.
   317  
   318  	GetPubKey() cryptotypes.PubKey // can return nil.
   319  	SetPubKey(cryptotypes.PubKey) error
   320  
   321  	GetAccountNumber() uint64
   322  	SetAccountNumber(uint64) error
   323  
   324  	GetSequence() uint64
   325  	SetSequence(uint64) error
   326  
   327  	// Ensure that account implements stringer
   328  	String() string
   329  }
   330  
   331  // ModuleAccountI defines an account interface for modules that hold tokens in
   332  // an escrow.
   333  type ModuleAccountI interface {
   334  	AccountI
   335  
   336  	GetName() string
   337  	GetPermissions() []string
   338  	HasPermission(string) bool
   339  }
   340  
   341  // GenesisAccounts defines a slice of GenesisAccount objects
   342  type GenesisAccounts []GenesisAccount
   343  
   344  // Contains returns true if the given address exists in a slice of GenesisAccount
   345  // objects.
   346  func (ga GenesisAccounts) Contains(addr sdk.Address) bool {
   347  	for _, acc := range ga {
   348  		if acc.GetAddress().Equals(addr) {
   349  			return true
   350  		}
   351  	}
   352  
   353  	return false
   354  }
   355  
   356  // GenesisAccount defines a genesis account that embeds an AccountI with validation capabilities.
   357  type GenesisAccount interface {
   358  	AccountI
   359  
   360  	Validate() error
   361  }