github.com/sixexorg/magnetic-ring@v0.0.0-20191119090307-31705a21e419/store/orgchain/validation/state_validate_account.go (about)

     1  package validation
     2  
     3  import (
     4  	"github.com/sixexorg/magnetic-ring/common"
     5  	"github.com/sixexorg/magnetic-ring/errors"
     6  	"github.com/sixexorg/magnetic-ring/store/orgchain/states"
     7  	"github.com/sixexorg/magnetic-ring/store/storelaw"
     8  )
     9  
    10  //The most important and the most complex
    11  //TODO Decide which oplog needs to be done
    12  //opIndes might the oplogs which need to rollback
    13  func (s *StateValidate) VerifyAccount(oplogs []*OpLog) (opIndes []int, err error) {
    14  	opIndes = make([]int, 0, len(oplogs))
    15  	for k, v := range oplogs {
    16  		err = s.verifyAccount(v)
    17  		if err == nil {
    18  			//already exec
    19  			opIndes = append(opIndes, k)
    20  		} else {
    21  			break
    22  		}
    23  	}
    24  	return opIndes, err
    25  }
    26  
    27  //just sub balance
    28  func (s *StateValidate) verifyAccount(oplog *OpLog) error {
    29  	if oplog.method <= Account_energy_consume && oplog.method >= Account_ut_add {
    30  		aa := oplog.data.(*OPAddressBigInt)
    31  		s.getAccountState(aa.Address)
    32  		switch oplog.method {
    33  		case Account_ut_add:
    34  			return nil
    35  		case Account_energy_add:
    36  			return nil
    37  		case Account_ut_sub:
    38  			crystal := s.DirtyAccountState[aa.Address].Balance()
    39  			if crystal.Cmp(aa.Num) == -1 {
    40  				return errors.ERR_STATE_LACK_BOX
    41  			}
    42  			s.DirtyAccountState[aa.Address].BalanceSub(aa.Num)
    43  			return nil
    44  		case Account_energy_sub: //special
    45  			energy := s.DirtyAccountState[aa.Address].Energy()
    46  			if energy.Cmp(aa.Num) == -1 {
    47  				return errors.ERR_STATE_LACK_GAS
    48  			}
    49  			s.DirtyAccountState[aa.Address].EnergySub(aa.Num)
    50  			return nil
    51  		case Account_energy_consume:
    52  			energyComsume := s.DirtyAccountState[aa.Address].Energy()
    53  			if energyComsume.Cmp(aa.Num) == -1 {
    54  				//todo blacklist to make the next nonce calculation easier
    55  				s.Blacklist[aa.Address] = true
    56  				return errors.ERR_STATE_GAS_OVER
    57  			}
    58  			s.DirtyAccountState[aa.Address].EnergySub(aa.Num)
    59  			return nil
    60  		}
    61  	} else if oplog.method == Account_nonce_add {
    62  		an := oplog.data.(*OPAddressUint64)
    63  		s.getAccountState(an.Address)
    64  		nextNonce := s.DirtyAccountState[an.Address].Nonce() + 1
    65  		if nextNonce == an.Num {
    66  			s.DirtyAccountState[an.Address].NonceSet(an.Num)
    67  			return nil
    68  		} else if nextNonce > an.Num {
    69  			return errors.ERR_STATE_NONCE_USED
    70  		} else {
    71  			return errors.ERR_STATE_ACCOUNT_NONCE_DISCONTINUITY
    72  		}
    73  	}
    74  	return nil
    75  }
    76  
    77  func (s *StateValidate) RollbackAccount(oplogs []*OpLog, opIndes []int) {
    78  	for _, v := range opIndes {
    79  		s.rollbackAccount(oplogs[v])
    80  	}
    81  }
    82  
    83  //just resub balance
    84  func (s *StateValidate) rollbackAccount(oplog *OpLog) {
    85  	if oplog.method <= Account_energy_consume && oplog.method >= Account_ut_sub {
    86  		aa := oplog.data.(*OPAddressBigInt)
    87  		switch oplog.method {
    88  		case Account_ut_sub:
    89  			s.DirtyAccountState[aa.Address].BalanceAdd(aa.Num)
    90  			break
    91  		case Account_energy_sub, Account_energy_consume: //special
    92  			s.DirtyAccountState[aa.Address].BalanceAdd(aa.Num)
    93  			break
    94  		}
    95  		return
    96  	}
    97  	/*else if oplog.method == Account_nonce_add {
    98  		an := oplog.data.(*OPAddressUint64)
    99  		s.DirtyAccountState[an.Address].Data.Nonce--
   100  	}*/
   101  
   102  }
   103  
   104  //todo fill MemoAccountState and DirtyAccountState for execute verifyAccount
   105  //todo need optimize the Nil state in which a single Block retrieves data multiple times
   106  func (s *StateValidate) getAccountState(address common.Address) {
   107  	//fmt.Println("func GetAccountState address:", address.ToString())
   108  	if s.DirtyAccountState[address] != nil {
   109  		return
   110  	}
   111  	var (
   112  		as  storelaw.AccountStater
   113  		err error
   114  	)
   115  	as, err = s.ledgeror.GetPrevAccount4V(s.currentBlockHeight, address, s.leagueId)
   116  	if err != nil {
   117  		panic(err)
   118  	}
   119  	as.HeightSet(s.TargetHeight)
   120  	var asDirty *states.AccountState
   121  
   122  	common.DeepCopy(&asDirty, as)
   123  	s.MemoAccountState[address] = as
   124  	s.DirtyAccountState[address] = asDirty
   125  }
   126  
   127  func (s *StateValidate) GetPrevAccountState(account common.Address, height uint64) storelaw.AccountStater {
   128  	as, err := s.ledgeror.GetPrevAccount4V(height, account, s.leagueId)
   129  	if err != nil {
   130  		panic(err)
   131  	}
   132  	return as
   133  }