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

     1  package validation
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/sixexorg/magnetic-ring/common"
     7  	"github.com/sixexorg/magnetic-ring/errors"
     8  	"github.com/sixexorg/magnetic-ring/log"
     9  	"github.com/sixexorg/magnetic-ring/store/mainchain/states"
    10  )
    11  
    12  //The most important and the most complex
    13  //TODO Decide which oplog needs to be done
    14  //opIndes might the oplogs which need to rollback
    15  func (s *StateValidate) VerifyAccount(oplogs []*OpLog) (opIndes []int, err error) {
    16  	opIndes = make([]int, 0, len(oplogs))
    17  	for k, v := range oplogs {
    18  		opTmp := v
    19  		err = s.verifyAccount(opTmp)
    20  		if err == nil {
    21  			//already exec
    22  			opIndes = append(opIndes, k)
    23  		} else {
    24  			break
    25  		}
    26  	}
    27  	return opIndes, err
    28  }
    29  
    30  //just sub balance
    31  func (s *StateValidate) verifyAccount(oplog *OpLog) error {
    32  	s.M.Lock()
    33  	defer s.M.Unlock()
    34  	{
    35  		if oplog.method <= Account_energy_consume && oplog.method >= Account_box_add {
    36  			aa := oplog.data.(*OPAddressBigInt)
    37  			err := s.getAccountState(aa.Address)
    38  			if err != nil {
    39  				return err
    40  			}
    41  			switch oplog.method {
    42  			case Account_box_add:
    43  				return nil
    44  			case Account_energy_add:
    45  				return nil
    46  			case Account_box_sub:
    47  				crystal := s.DirtyAccountState[aa.Address].Data.Balance
    48  				if crystal.Cmp(aa.Num) == -1 {
    49  					return errors.ERR_STATE_LACK_BOX
    50  				}
    51  				s.DirtyAccountState[aa.Address].Data.Balance.Sub(crystal, aa.Num)
    52  				return nil
    53  			case Account_energy_sub: //special
    54  				energy := s.DirtyAccountState[aa.Address].Data.EnergyBalance
    55  				if energy.Cmp(aa.Num) == -1 {
    56  					return errors.ERR_STATE_LACK_GAS
    57  				}
    58  				s.DirtyAccountState[aa.Address].Data.EnergyBalance.Sub(energy, aa.Num)
    59  				return nil
    60  			case Account_energy_consume:
    61  				energyComsume := s.DirtyAccountState[aa.Address].Data.EnergyBalance
    62  				if energyComsume.Cmp(aa.Num) == -1 {
    63  					//todo blacklist to make the next nonce calculation easier
    64  					s.Blacklist[aa.Address] = true
    65  					return errors.ERR_STATE_GAS_OVER
    66  				}
    67  				s.DirtyAccountState[aa.Address].Data.EnergyBalance.Sub(energyComsume, aa.Num)
    68  				return nil
    69  			}
    70  		} else if oplog.method == Account_nonce_add {
    71  			an := oplog.data.(*OPAddressUint64)
    72  			err := s.getAccountState(an.Address)
    73  			if err != nil {
    74  				return err
    75  			}
    76  			nonceTmp := s.DirtyAccountState[an.Address].Data.Nonce
    77  			//fmt.Println("nonce dirty:", nonceTmp, " nonce from tx:", an.Num)
    78  			if nonceTmp+1 == an.Num {
    79  				s.DirtyAccountState[an.Address].Data.Nonce = an.Num
    80  				AccountNonceInstance.SetNonce(an.Address, an.Num)
    81  				return nil
    82  			} else if nonceTmp >= an.Num {
    83  				return errors.ERR_STATE_NONCE_USED
    84  			}
    85  
    86  			return errors.ERR_STATE_ACCOUNT_NONCE_DISCONTINUITY
    87  		}
    88  		return nil
    89  	}
    90  }
    91  
    92  func (s *StateValidate) RollbackAccount(oplogs []*OpLog, opIndes []int) {
    93  	for _, v := range opIndes {
    94  		s.rollbackAccount(oplogs[v])
    95  	}
    96  }
    97  
    98  //just resub balance
    99  func (s *StateValidate) rollbackAccount(oplog *OpLog) {
   100  	s.M.Lock()
   101  	defer s.M.Unlock()
   102  	{
   103  		if oplog.method <= Account_energy_consume && oplog.method >= Account_box_sub {
   104  			aa := oplog.data.(*OPAddressBigInt)
   105  			switch oplog.method {
   106  			case Account_box_sub:
   107  				crystal := s.DirtyAccountState[aa.Address].Data.Balance
   108  				s.DirtyAccountState[aa.Address].Data.Balance.Add(crystal, aa.Num)
   109  				break
   110  			case Account_energy_sub: //special
   111  				energy := s.DirtyAccountState[aa.Address].Data.EnergyBalance
   112  				s.DirtyAccountState[aa.Address].Data.EnergyBalance.Add(energy, aa.Num)
   113  				break
   114  			case Account_energy_consume:
   115  				energyComsume := s.DirtyAccountState[aa.Address].Data.EnergyBalance
   116  				s.DirtyAccountState[aa.Address].Data.EnergyBalance.Add(energyComsume, aa.Num)
   117  				break
   118  			}
   119  			return
   120  		} else if oplog.method == Account_nonce_add {
   121  			aa := oplog.data.(*OPAddressUint64)
   122  			s.DirtyAccountState[aa.Address].Data.Nonce--
   123  			AccountNonceInstance.nonceSub(aa.Address)
   124  		}
   125  	}
   126  }
   127  
   128  //todo fill MemoAccountState and DirtyAccountState for execute verifyAccount
   129  func (s *StateValidate) getAccountState(address common.Address) error {
   130  	if s.DirtyAccountState[address] != nil {
   131  		return nil
   132  	}
   133  	as, err := s.ledgerStore.GetAccountByHeight(s.currentBlockHeight, address)
   134  	if err != nil {
   135  		return err
   136  	}
   137  	//fmt.Println("func getAccountState", as.Data.Nonce, address.ToString(), as.Address.ToString(), as.Data.EnergyBalance.Uint64(), as.Data.Balance.Uint64())
   138  	//as.Address = address
   139  	log.Info(fmt.Sprintf("func getAccountState ====> address :%s,nonce:%d,crystal:%d,energy:%d,height:%d", as.Address.ToString(),
   140  		as.Data.Nonce, as.Data.Balance.Uint64(), as.Data.EnergyBalance.Uint64(), as.Height))
   141  	asDirty := &states.AccountState{}
   142  	common.DeepCopy(&asDirty, as)
   143  	s.MemoAccountState[address] = as
   144  	s.DirtyAccountState[address] = asDirty
   145  	return nil
   146  }