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 }