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 }