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 }