github.com/igggame/nebulas-go@v2.1.0+incompatible/core/state/account_state.go (about)

     1  // Copyright (C) 2017 go-nebulas authors
     2  //
     3  // This file is part of the go-nebulas library.
     4  //
     5  // the go-nebulas library is free software: you can redistribute it and/or modify
     6  // it under the terms of the GNU General Public License as published by
     7  // the Free Software Foundation, either version 3 of the License, or
     8  // (at your option) any later version.
     9  //
    10  // the go-nebulas library is distributed in the hope that it will be useful,
    11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    13  // GNU General Public License for more details.
    14  //
    15  // You should have received a copy of the GNU General Public License
    16  // along with the go-nebulas library.  If not, see <http://www.gnu.org/licenses/>.
    17  //
    18  
    19  package state
    20  
    21  import (
    22  	"errors"
    23  	"fmt"
    24  
    25  	"github.com/gogo/protobuf/proto"
    26  	"github.com/nebulasio/go-nebulas/common/trie"
    27  	"github.com/nebulasio/go-nebulas/core/pb"
    28  	"github.com/nebulasio/go-nebulas/storage"
    29  	"github.com/nebulasio/go-nebulas/util"
    30  	"github.com/nebulasio/go-nebulas/util/byteutils"
    31  )
    32  
    33  // Errors
    34  var (
    35  	ErrBalanceInsufficient     = errors.New("cannot subtract a value which is bigger than current balance")
    36  	ErrAccountNotFound         = errors.New("cannot found account in storage")
    37  	ErrContractAccountNotFound = errors.New("cannot found contract account in storage please check contract address is valid or deploy is success")
    38  )
    39  
    40  // account info in state Trie
    41  type account struct {
    42  	address byteutils.Hash
    43  	balance *util.Uint128
    44  	nonce   uint64
    45  	// UserType: Global Storage
    46  	// ContractType: Local Storage
    47  	variables *trie.Trie
    48  	// ContractType: Transaction Hash
    49  	birthPlace byteutils.Hash
    50  
    51  	contractMeta *corepb.ContractMeta
    52  }
    53  
    54  // ToBytes converts domain Account to bytes
    55  func (acc *account) ToBytes() ([]byte, error) {
    56  	value, err := acc.balance.ToFixedSizeByteSlice()
    57  	if err != nil {
    58  		return nil, err
    59  	}
    60  	pbAcc := &corepb.Account{
    61  		Address:      acc.address,
    62  		Balance:      value,
    63  		Nonce:        acc.nonce,
    64  		VarsHash:     acc.variables.RootHash(),
    65  		BirthPlace:   acc.birthPlace,
    66  		ContractMeta: acc.contractMeta,
    67  	}
    68  	bytes, err := proto.Marshal(pbAcc)
    69  	if err != nil {
    70  		return nil, err
    71  	}
    72  	return bytes, nil
    73  }
    74  
    75  // FromBytes converts bytes to Account
    76  func (acc *account) FromBytes(bytes []byte, storage storage.Storage) error {
    77  	pbAcc := &corepb.Account{}
    78  	if err := proto.Unmarshal(bytes, pbAcc); err != nil {
    79  		return err
    80  	}
    81  	value, err := util.NewUint128FromFixedSizeByteSlice(pbAcc.Balance)
    82  	if err != nil {
    83  		return err
    84  	}
    85  	acc.address = pbAcc.Address
    86  	acc.balance = value
    87  	acc.nonce = pbAcc.Nonce
    88  	acc.birthPlace = pbAcc.BirthPlace
    89  	acc.contractMeta = pbAcc.ContractMeta
    90  	acc.variables, err = trie.NewTrie(pbAcc.VarsHash, storage, false)
    91  	if err != nil {
    92  		return err
    93  	}
    94  	return nil
    95  }
    96  
    97  // Balance return account's balance
    98  func (acc *account) Balance() *util.Uint128 {
    99  	return acc.balance
   100  }
   101  
   102  // Address return account's address
   103  func (acc *account) Address() byteutils.Hash {
   104  	return acc.address
   105  }
   106  
   107  // Nonce return account's nonce
   108  func (acc *account) Nonce() uint64 {
   109  	return acc.nonce
   110  }
   111  
   112  // VarsHash return account's variables hash
   113  func (acc *account) VarsHash() byteutils.Hash {
   114  	return acc.variables.RootHash()
   115  }
   116  
   117  // BirthPlace return account's birth place
   118  func (acc *account) BirthPlace() byteutils.Hash {
   119  	return acc.birthPlace
   120  }
   121  
   122  // ContractMeta ..
   123  func (acc *account) ContractMeta() *corepb.ContractMeta {
   124  	return acc.contractMeta
   125  }
   126  
   127  // Clone account
   128  func (acc *account) Clone() (Account, error) {
   129  	variables, err := acc.variables.Clone()
   130  	if err != nil {
   131  		return nil, err
   132  	}
   133  
   134  	return &account{
   135  		address:      acc.address,
   136  		balance:      acc.balance,
   137  		nonce:        acc.nonce,
   138  		variables:    variables,
   139  		birthPlace:   acc.birthPlace,
   140  		contractMeta: acc.contractMeta, // TODO: Clone() ?
   141  	}, nil
   142  }
   143  
   144  // IncrNonce by 1
   145  func (acc *account) IncrNonce() {
   146  	acc.nonce++
   147  }
   148  
   149  // AddBalance to an account
   150  func (acc *account) AddBalance(value *util.Uint128) error {
   151  	balance, err := acc.balance.Add(value)
   152  	if err != nil {
   153  		return err
   154  	}
   155  	acc.balance = balance
   156  	return nil
   157  }
   158  
   159  // SubBalance to an account
   160  func (acc *account) SubBalance(value *util.Uint128) error {
   161  	if acc.balance.Cmp(value) < 0 {
   162  		return ErrBalanceInsufficient
   163  	}
   164  	balance, err := acc.balance.Sub(value)
   165  	if err != nil {
   166  		return err
   167  	}
   168  	acc.balance = balance
   169  	return nil
   170  }
   171  
   172  // Put into account's storage
   173  func (acc *account) Put(key []byte, value []byte) error {
   174  	_, err := acc.variables.Put(key, value)
   175  	return err
   176  }
   177  
   178  // Get from account's storage
   179  func (acc *account) Get(key []byte) ([]byte, error) {
   180  	return acc.variables.Get(key)
   181  }
   182  
   183  // Del from account's storage
   184  func (acc *account) Del(key []byte) error {
   185  	if _, err := acc.variables.Del(key); err != nil {
   186  		return err
   187  	}
   188  	return nil
   189  }
   190  
   191  // Iterator map var from account's storage
   192  func (acc *account) Iterator(prefix []byte) (Iterator, error) {
   193  	return acc.variables.Iterator(prefix)
   194  }
   195  
   196  func (acc *account) String() string {
   197  	return fmt.Sprintf("Account %p {Address: %v, Balance:%v; Nonce:%v; VarsHash:%v; BirthPlace:%v; ContractMeta:%v}",
   198  		acc,
   199  		byteutils.Hex(acc.address),
   200  		acc.balance,
   201  		acc.nonce,
   202  		byteutils.Hex(acc.variables.RootHash()),
   203  		acc.birthPlace.Hex(),
   204  		acc.contractMeta.String(), // TODO: check nil?
   205  	)
   206  }
   207  
   208  // AccountState manage account state in Block
   209  type accountState struct {
   210  	stateTrie    *trie.Trie
   211  	dirtyAccount map[byteutils.HexHash]Account
   212  	storage      storage.Storage
   213  }
   214  
   215  // NewAccountState create a new account state
   216  func NewAccountState(root byteutils.Hash, storage storage.Storage) (AccountState, error) {
   217  	stateTrie, err := trie.NewTrie(root, storage, false)
   218  	if err != nil {
   219  		return nil, err
   220  	}
   221  
   222  	return &accountState{
   223  		stateTrie:    stateTrie,
   224  		dirtyAccount: make(map[byteutils.HexHash]Account),
   225  		storage:      storage,
   226  	}, nil
   227  }
   228  
   229  func (as *accountState) recordDirtyAccount(addr byteutils.Hash, acc Account) {
   230  	as.dirtyAccount[addr.Hex()] = acc
   231  }
   232  
   233  func (as *accountState) newAccount(addr byteutils.Hash, birthPlace byteutils.Hash, contractMeta *corepb.ContractMeta) (Account, error) {
   234  	varTrie, err := trie.NewTrie(nil, as.storage, false)
   235  	if err != nil {
   236  		return nil, err
   237  	}
   238  	acc := &account{
   239  		address:      addr,
   240  		balance:      util.NewUint128(),
   241  		nonce:        0,
   242  		variables:    varTrie,
   243  		birthPlace:   birthPlace,
   244  		contractMeta: contractMeta,
   245  	}
   246  	as.recordDirtyAccount(addr, acc)
   247  	return acc, nil
   248  }
   249  
   250  func (as *accountState) getAccount(addr byteutils.Hash) (Account, error) {
   251  	// search in dirty account
   252  	if acc, ok := as.dirtyAccount[addr.Hex()]; ok {
   253  		return acc, nil
   254  	}
   255  	// search in storage
   256  	bytes, err := as.stateTrie.Get(addr)
   257  	if err != nil && err != storage.ErrKeyNotFound {
   258  		return nil, err
   259  	}
   260  	if err == nil {
   261  		acc := new(account)
   262  		err = acc.FromBytes(bytes, as.storage)
   263  		if err != nil {
   264  			return nil, err
   265  		}
   266  		as.recordDirtyAccount(addr, acc)
   267  		return acc, nil
   268  	}
   269  	return nil, ErrAccountNotFound
   270  }
   271  
   272  func (as *accountState) Flush() error {
   273  	for addr, acc := range as.dirtyAccount {
   274  		bytes, err := acc.ToBytes()
   275  		if err != nil {
   276  			return err
   277  		}
   278  		key, err := addr.Hash()
   279  		if err != nil {
   280  			return err
   281  		}
   282  		as.stateTrie.Put(key, bytes)
   283  	}
   284  	as.dirtyAccount = make(map[byteutils.HexHash]Account)
   285  	return nil
   286  }
   287  
   288  func (as *accountState) Abort() error {
   289  	as.dirtyAccount = make(map[byteutils.HexHash]Account)
   290  	return nil
   291  }
   292  
   293  // RootHash return root hash of account state
   294  func (as *accountState) RootHash() byteutils.Hash {
   295  	return as.stateTrie.RootHash()
   296  }
   297  
   298  // GetOrCreateUserAccount according to the addr
   299  func (as *accountState) GetOrCreateUserAccount(addr byteutils.Hash) (Account, error) {
   300  	acc, err := as.getAccount(addr)
   301  	if err != nil && err != ErrAccountNotFound {
   302  		return nil, err
   303  	}
   304  	if err == ErrAccountNotFound {
   305  		acc, err = as.newAccount(addr, nil, nil)
   306  		if err != nil {
   307  			return nil, err
   308  		}
   309  		return acc, nil
   310  	}
   311  	return acc, nil
   312  }
   313  
   314  // GetContractAccount from current AccountState
   315  func (as *accountState) GetContractAccount(addr byteutils.Hash) (Account, error) {
   316  	acc, err := as.getAccount(addr)
   317  
   318  	if err == ErrAccountNotFound {
   319  		err = ErrContractAccountNotFound
   320  	}
   321  	if err != nil {
   322  		return nil, err
   323  	}
   324  
   325  	return acc, nil
   326  }
   327  
   328  // CreateContractAccount according to the addr, and set birthPlace as creation tx hash
   329  func (as *accountState) CreateContractAccount(addr byteutils.Hash, birthPlace byteutils.Hash, contractMeta *corepb.ContractMeta) (Account, error) {
   330  	return as.newAccount(addr, birthPlace, contractMeta)
   331  }
   332  
   333  func (as *accountState) Accounts() ([]Account, error) { // TODO delete
   334  	accounts := []Account{}
   335  	iter, err := as.stateTrie.Iterator(nil)
   336  	if err != nil && err != storage.ErrKeyNotFound {
   337  		return nil, err
   338  	}
   339  	if err != nil {
   340  		return accounts, nil
   341  	}
   342  	exist, err := iter.Next()
   343  	if err != nil {
   344  		return nil, err
   345  	}
   346  	for exist {
   347  		acc := new(account)
   348  		err = acc.FromBytes(iter.Value(), as.storage)
   349  		if err != nil {
   350  			return nil, err
   351  		}
   352  		accounts = append(accounts, acc)
   353  		exist, err = iter.Next()
   354  		if err != nil {
   355  			return nil, err
   356  		}
   357  	}
   358  	return accounts, nil
   359  }
   360  
   361  // DirtyAccounts return all changed accounts
   362  func (as *accountState) DirtyAccounts() ([]Account, error) {
   363  	accounts := []Account{}
   364  	for _, account := range as.dirtyAccount {
   365  		accounts = append(accounts, account)
   366  	}
   367  	return accounts, nil
   368  }
   369  
   370  // Relay merge the done account state
   371  func (as *accountState) Replay(done AccountState) error {
   372  	state := done.(*accountState)
   373  	for addr, acc := range state.dirtyAccount {
   374  		as.dirtyAccount[addr] = acc
   375  	}
   376  	return nil
   377  }
   378  
   379  // Clone an accountState
   380  func (as *accountState) Clone() (AccountState, error) {
   381  	stateTrie, err := as.stateTrie.Clone()
   382  	if err != nil {
   383  		return nil, err
   384  	}
   385  
   386  	dirtyAccount := make(map[byteutils.HexHash]Account)
   387  	for addr, acc := range as.dirtyAccount {
   388  		dirtyAccount[addr], err = acc.Clone()
   389  		if err != nil {
   390  			return nil, err
   391  		}
   392  	}
   393  
   394  	return &accountState{
   395  		stateTrie:    stateTrie,
   396  		dirtyAccount: dirtyAccount,
   397  		storage:      as.storage,
   398  	}, nil
   399  }
   400  
   401  func (as *accountState) String() string {
   402  	return fmt.Sprintf("AccountState %p {RootHash:%s; dirtyAccount:%v; Storage:%p}",
   403  		as,
   404  		byteutils.Hex(as.stateTrie.RootHash()),
   405  		as.dirtyAccount,
   406  		as.storage,
   407  	)
   408  }
   409  
   410  // MockAccount nf/nvm/engine.CheckV8Run()  & cmd/v8/main.go
   411  func MockAccount(version string) Account {
   412  	return &account{
   413  		contractMeta: &corepb.ContractMeta{
   414  			Version: version,
   415  		},
   416  	}
   417  }