mirror of https://github.com/poanetwork/gecko.git
122 lines
3.0 KiB
Go
122 lines
3.0 KiB
Go
// (c) 2019-2020, Ava Labs, Inc. All rights reserved.
|
|
// See the file LICENSE for licensing terms.
|
|
|
|
package platformvm
|
|
|
|
import (
|
|
"errors"
|
|
|
|
"github.com/ava-labs/gecko/database"
|
|
"github.com/ava-labs/gecko/ids"
|
|
"github.com/ava-labs/gecko/utils/crypto"
|
|
)
|
|
|
|
// Key in the database whose corresponding value is the list of
|
|
// account IDs this user controls
|
|
var accountIDsKey = ids.Empty.Bytes()
|
|
|
|
var errDbNil = errors.New("db uninitialized")
|
|
|
|
type user struct {
|
|
// This user's database, acquired from the keystore
|
|
db database.Database
|
|
}
|
|
|
|
// Get the IDs of the accounts controlled by this user
|
|
func (u *user) getAccountIDs() ([]ids.ShortID, error) {
|
|
if u.db == nil {
|
|
return nil, errDbNil
|
|
}
|
|
|
|
// If user has no accounts, return empty list
|
|
hasAccounts, err := u.db.Has(accountIDsKey)
|
|
if err != nil {
|
|
return nil, errDB
|
|
}
|
|
if !hasAccounts {
|
|
return make([]ids.ShortID, 0), nil
|
|
}
|
|
// User has accounts. Get them.
|
|
bytes, err := u.db.Get(accountIDsKey)
|
|
if err != nil {
|
|
return nil, errDB
|
|
}
|
|
accountIDs := []ids.ShortID{}
|
|
if err := Codec.Unmarshal(bytes, &accountIDs); err != nil {
|
|
return nil, err
|
|
}
|
|
return accountIDs, nil
|
|
}
|
|
|
|
// controlsAccount returns true iff this user controls the account
|
|
// with the specified ID
|
|
func (u *user) controlsAccount(ID ids.ShortID) (bool, error) {
|
|
if u.db == nil {
|
|
return false, errDbNil
|
|
}
|
|
|
|
if _, err := u.db.Get(ID.Bytes()); err == nil {
|
|
return true, nil
|
|
}
|
|
return false, nil
|
|
}
|
|
|
|
// putAccount persists that this user controls the account whose ID is
|
|
// [privKey].PublicKey().Address()
|
|
func (u *user) putAccount(privKey *crypto.PrivateKeySECP256K1R) error {
|
|
newAccountID := privKey.PublicKey().Address() // Account thie privKey controls
|
|
controlsAccount, err := u.controlsAccount(newAccountID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if controlsAccount { // user already controls this account. Do nothing.
|
|
return nil
|
|
}
|
|
|
|
err = u.db.Put(newAccountID.Bytes(), privKey.Bytes()) // Account ID --> private key
|
|
if err != nil {
|
|
return errDB
|
|
}
|
|
|
|
accountIDs := make([]ids.ShortID, 0) // Add account to list of accounts user controls
|
|
userHasAccounts, err := u.db.Has(accountIDsKey)
|
|
if err != nil {
|
|
return errDB
|
|
}
|
|
if userHasAccounts { // Get accountIDs this user already controls, if they exist
|
|
if accountIDs, err = u.getAccountIDs(); err != nil {
|
|
return errDB
|
|
}
|
|
}
|
|
accountIDs = append(accountIDs, newAccountID)
|
|
bytes, err := Codec.Marshal(accountIDs)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if err := u.db.Put(accountIDsKey, bytes); err != nil {
|
|
return errDB
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Key returns the private key that controls the account with the specified ID
|
|
func (u *user) getKey(accountID ids.ShortID) (*crypto.PrivateKeySECP256K1R, error) {
|
|
if u.db == nil {
|
|
return nil, errDbNil
|
|
}
|
|
|
|
factory := crypto.FactorySECP256K1R{}
|
|
bytes, err := u.db.Get(accountID.Bytes())
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
sk, err := factory.ToPrivateKey(bytes)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if sk, ok := sk.(*crypto.PrivateKeySECP256K1R); ok {
|
|
return sk, nil
|
|
}
|
|
return nil, errDB
|
|
}
|