github.com/aergoio/aergo@v1.3.1/account/accountservice.go (about)

     1  package account
     2  
     3  import (
     4  	"sync"
     5  
     6  	"github.com/aergoio/aergo-actor/actor"
     7  	"github.com/aergoio/aergo-lib/log"
     8  	"github.com/aergoio/aergo/account/key"
     9  	cfg "github.com/aergoio/aergo/config"
    10  	"github.com/aergoio/aergo/contract/name"
    11  	"github.com/aergoio/aergo/message"
    12  	"github.com/aergoio/aergo/pkg/component"
    13  	"github.com/aergoio/aergo/state"
    14  	"github.com/aergoio/aergo/types"
    15  )
    16  
    17  type AccountService struct {
    18  	*component.BaseComponent
    19  	cfg         *cfg.Config
    20  	sdb         *state.ChainStateDB
    21  	ks          *key.Store
    22  	accountLock sync.RWMutex
    23  	accounts    []*types.Account
    24  	testConfig  bool
    25  }
    26  
    27  //NewAccountService create account service
    28  func NewAccountService(cfg *cfg.Config, sdb *state.ChainStateDB) *AccountService {
    29  	actor := &AccountService{
    30  		cfg: cfg,
    31  		sdb: sdb,
    32  	}
    33  	actor.BaseComponent = component.NewBaseComponent(message.AccountsSvc, actor, log.NewLogger("account"))
    34  
    35  	return actor
    36  }
    37  
    38  func (as *AccountService) BeforeStart() {
    39  	as.ks = key.NewStore(as.cfg.DataDir, as.cfg.Account.UnlockTimeout)
    40  
    41  	as.accounts = []*types.Account{}
    42  	addresses, err := as.ks.GetAddresses()
    43  	if err != nil {
    44  		as.Logger.Error().Err(err).Msg("could not open addresses")
    45  	}
    46  	for _, v := range addresses {
    47  		as.accounts = append(as.accounts, &types.Account{Address: v})
    48  	}
    49  }
    50  
    51  func (as *AccountService) AfterStart() {}
    52  
    53  func (as *AccountService) BeforeStop() {
    54  	as.ks.CloseStore()
    55  	as.accounts = nil
    56  }
    57  
    58  func (as *AccountService) Statistics() *map[string]interface{} {
    59  	return &map[string]interface{}{
    60  		"totalaccounts": len(as.accounts),
    61  		"personal":      as.cfg.Personal,
    62  		"config":        as.cfg.Account,
    63  	}
    64  }
    65  func (as *AccountService) resolveName(namedAddress []byte) ([]byte, error) {
    66  	scs, err := as.sdb.GetStateDB().OpenContractStateAccount(types.ToAccountID([]byte(types.AergoName)))
    67  	if err != nil {
    68  		return nil, err
    69  	}
    70  	return name.GetAddress(scs, namedAddress), nil
    71  }
    72  
    73  func (as *AccountService) Receive(context actor.Context) {
    74  
    75  	switch msg := context.Message().(type) {
    76  	case *message.GetAccounts:
    77  		accountList := as.getAccounts()
    78  		context.Respond(&message.GetAccountsRsp{Accounts: &types.AccountList{Accounts: accountList}})
    79  	case *message.CreateAccount:
    80  		account, _ := as.createAccount(msg.Passphrase)
    81  		context.Respond(&message.CreateAccountRsp{Account: account})
    82  	case *message.LockAccount:
    83  		actualAddress := msg.Account.Address
    84  		var err error
    85  		if len(actualAddress) == types.NameLength {
    86  			actualAddress, err = as.resolveName(actualAddress)
    87  			if err != nil {
    88  				context.Respond(&message.AccountRsp{
    89  					Account: &types.Account{Address: actualAddress},
    90  					Err:     err,
    91  				})
    92  			}
    93  		}
    94  		account, err := as.lockAccount(actualAddress, msg.Passphrase)
    95  		context.Respond(&message.AccountRsp{Account: account, Err: err})
    96  	case *message.UnlockAccount:
    97  		actualAddress := msg.Account.Address
    98  		var err error
    99  		if len(actualAddress) == types.NameLength {
   100  			actualAddress, err = as.resolveName(actualAddress)
   101  			if err != nil {
   102  				context.Respond(&message.AccountRsp{
   103  					Account: &types.Account{Address: actualAddress},
   104  					Err:     err,
   105  				})
   106  			}
   107  		}
   108  		account, err := as.unlockAccount(actualAddress, msg.Passphrase)
   109  		context.Respond(&message.AccountRsp{Account: account, Err: err})
   110  	case *message.ImportAccount:
   111  		account, err := as.importAccount(msg.Wif, msg.OldPass, msg.NewPass)
   112  		context.Respond(&message.ImportAccountRsp{Account: account, Err: err})
   113  	case *message.ExportAccount:
   114  		wif, err := as.exportAccount(msg.Account.Address, msg.Pass)
   115  		context.Respond(&message.ExportAccountRsp{Wif: wif, Err: err})
   116  	case *message.SignTx:
   117  		var err error
   118  		actualAddress := msg.Tx.GetBody().GetAccount()
   119  		if len(actualAddress) == types.NameLength {
   120  			actualAddress, err = as.resolveName(msg.Tx.GetBody().GetAccount())
   121  			if err != nil {
   122  				context.Respond(&message.SignTxRsp{Tx: nil, Err: err})
   123  			}
   124  			msg.Requester = actualAddress
   125  		}
   126  		err = as.signTx(context, msg)
   127  		if err != nil {
   128  			context.Respond(&message.SignTxRsp{Tx: nil, Err: err})
   129  		}
   130  	case *message.VerifyTx:
   131  		err := as.verifyTx(msg.Tx)
   132  		if err != nil {
   133  			context.Respond(&message.VerifyTxRsp{Tx: nil, Err: err})
   134  		} else {
   135  			context.Respond(&message.VerifyTxRsp{Tx: msg.Tx, Err: nil})
   136  		}
   137  	}
   138  }
   139  
   140  func (as *AccountService) getAccounts() []*types.Account {
   141  	as.accountLock.RLock()
   142  	defer as.accountLock.RUnlock()
   143  	return as.accounts
   144  }
   145  
   146  func (as *AccountService) createAccount(passphrase string) (*types.Account, error) {
   147  	address, err := as.ks.CreateKey(passphrase)
   148  	if err != nil {
   149  		return nil, err
   150  	}
   151  	account := types.NewAccount(address)
   152  
   153  	//append list
   154  	as.accountLock.Lock()
   155  	//TODO: performance turning here
   156  	as.ks.SaveAddress(address)
   157  	as.accounts = append(as.accounts, account)
   158  	as.accountLock.Unlock()
   159  	return account, nil
   160  }
   161  
   162  func (as *AccountService) importAccount(wif []byte, old string, new string) (*types.Account, error) {
   163  	address, err := as.ks.ImportKey(wif, old, new)
   164  	if err != nil {
   165  		return nil, err
   166  	}
   167  	//append list
   168  	account := &types.Account{Address: address}
   169  	as.accountLock.Lock()
   170  	//TODO: performance turning here
   171  	as.ks.SaveAddress(address)
   172  	as.accounts = append(as.accounts, account)
   173  	as.accountLock.Unlock()
   174  	return account, nil
   175  }
   176  
   177  func (as *AccountService) exportAccount(address []byte, pass string) ([]byte, error) {
   178  	wif, err := as.ks.ExportKey(address, pass)
   179  	if err != nil {
   180  		return nil, err
   181  	}
   182  	return wif, nil
   183  }
   184  
   185  func (as *AccountService) unlockAccount(address []byte, passphrase string) (*types.Account, error) {
   186  	addr, err := as.ks.Unlock(address, passphrase)
   187  	if err != nil {
   188  		as.Warn().Err(err).Msg("could not find the key")
   189  		return nil, err
   190  	}
   191  	return &types.Account{Address: addr}, nil
   192  }
   193  
   194  func (as *AccountService) lockAccount(address []byte, passphrase string) (*types.Account, error) {
   195  	addr, err := as.ks.Lock(address, passphrase)
   196  	if err != nil {
   197  		as.Warn().Err(err).Msg("could not load the key")
   198  		return nil, err
   199  	}
   200  	return &types.Account{Address: addr}, nil
   201  }
   202  
   203  func (as *AccountService) signTx(c actor.Context, msg *message.SignTx) error {
   204  	//sign tx
   205  	prop := actor.FromInstance(NewSigner(as.ks))
   206  	signer := c.Spawn(prop)
   207  	signer.Request(msg, c.Sender())
   208  	return nil
   209  }
   210  
   211  func (as *AccountService) verifyTx(tx *types.Tx) error {
   212  	return as.ks.VerifyTx(tx)
   213  }