github.com/sixexorg/magnetic-ring@v0.0.0-20191119090307-31705a21e419/store/orgchain/validation/state_validate.go (about) 1 package validation 2 3 import ( 4 "math/big" 5 "sync" 6 7 "fmt" 8 9 "github.com/sixexorg/magnetic-ring/common" 10 "github.com/sixexorg/magnetic-ring/core/orgchain/types" 11 "github.com/sixexorg/magnetic-ring/errors" 12 "github.com/sixexorg/magnetic-ring/store/storelaw" 13 ) 14 15 var ( 16 ratU = big.NewRat(1e8, 1) 17 bigU = big.NewInt(1e8) 18 ) 19 20 // todo how to do with the nonce 21 type StateValidate struct { 22 TargetHeight uint64 23 currentBlockHeight uint64 24 currentBlockHash common.Hash 25 MemoAccountState map[common.Address]storelaw.AccountStater 26 //for one tx ,Take the lower limit,only the subtraction 27 DirtyAccountState map[common.Address]storelaw.AccountStater 28 29 //vote instant state 30 MemoVoteState map[common.Hash]*storelaw.VoteState 31 32 DirtyVote map[common.Hash]map[common.Address]struct{} 33 Blacklist map[common.Address]bool 34 35 receipts types.Receipts 36 txs types.Transactions 37 ParentBonusHeight uint64 38 WaitOplogs []*OpLog //Transactional submission 39 40 //the ut amount when the vote start 41 voteUT map[common.Hash]*TxUT 42 //new vote pool 43 voteNew []*storelaw.VoteState 44 accountVoteds map[common.Hash]map[common.Address]struct{} 45 ledgeror storelaw.Ledger4Validation 46 leagueId common.Address 47 48 m sync.Mutex 49 } 50 51 func NewStateValidate(ledgeror storelaw.Ledger4Validation, leadgeId common.Address) *StateValidate { 52 53 curHeight := ledgeror.GetCurrentBlockHeight4V(leadgeId) 54 s := &StateValidate{ 55 TargetHeight: curHeight + 1, 56 currentBlockHash: ledgeror.GetCurrentHeaderHash4V(leadgeId), 57 currentBlockHeight: curHeight, 58 MemoAccountState: make(map[common.Address]storelaw.AccountStater), 59 DirtyAccountState: make(map[common.Address]storelaw.AccountStater), 60 Blacklist: make(map[common.Address]bool), 61 MemoVoteState: make(map[common.Hash]*storelaw.VoteState), 62 voteUT: make(map[common.Hash]*TxUT), 63 accountVoteds: make(map[common.Hash]map[common.Address]struct{}), 64 DirtyVote: make(map[common.Hash]map[common.Address]struct{}), 65 WaitOplogs: []*OpLog{}, //Transactional submission 66 ledgeror: ledgeror, 67 leagueId: leadgeId, 68 } 69 return s 70 } 71 72 func (s *StateValidate) TxInheritance() <-chan *types.Transaction { 73 ch := make(chan *types.Transaction, 20) 74 for k, _ := range s.txs { 75 if !s.ledgeror.ContainTx4V(s.txs[k].Hash()) { 76 ch <- s.txs[k] 77 } 78 } 79 close(ch) 80 return ch 81 } 82 83 //ExecuteOplogs is perform the verified transaction calculation and generate the status data 84 func (s *StateValidate) ExecuteOplogs() *storelaw.OrgBlockInfo { 85 s.m.Lock() 86 defer s.m.Unlock() 87 { 88 //fmt.Println("⛏ ⛏ ExecuteOplogs txlen", s.txs.Len()) 89 var ( 90 aa *OPAddressBigInt 91 an *OPAddressUint64 92 ha *OPHashAddress 93 //ad *OPAddressAdress 94 fee = big.NewInt(0) 95 ) 96 ut := s.ledgeror.GetUTByHeight(s.currentBlockHeight, s.leagueId) 97 //the vote hasn't passed 98 afterVote := make(map[common.Hash]struct{}) 99 for k, v := range s.MemoVoteState { 100 //fmt.Println("⭕️ ExecuteOplogs vote hash ", k.String(), len(s.MemoVoteState)) 101 if !v.GetResult(s.voteUT[k].UT, 67) { 102 //fmt.Println("⭕️ ExecuteOplogs vote result ", s.voteUT[k].UT) 103 afterVote[k] = struct{}{} 104 } 105 } 106 for _, v := range s.WaitOplogs { 107 switch v.method { 108 case Account_ut_add: 109 aa = v.data.(*OPAddressBigInt) 110 s.MemoAccountState[aa.Address].BalanceAdd(aa.Num) 111 break 112 case Account_energy_add: 113 aa = v.data.(*OPAddressBigInt) 114 //fmt.Println("func ExecuteOplogs address:", aa.Address.ToString()) 115 s.MemoAccountState[aa.Address].EnergyAdd(aa.Num) 116 break 117 case Account_ut_sub: 118 aa = v.data.(*OPAddressBigInt) 119 s.MemoAccountState[aa.Address].BalanceSub(aa.Num) 120 break 121 case Account_energy_sub, Account_energy_consume: 122 aa = v.data.(*OPAddressBigInt) 123 s.MemoAccountState[aa.Address].EnergySub(aa.Num) 124 if v.method == Account_energy_consume { 125 fee.Add(fee, aa.Num) 126 } 127 break 128 case Account_bonus_left: 129 an = v.data.(*OPAddressUint64) 130 s.MemoAccountState[an.Address].BonusHSet(an.Num) 131 break 132 case Account_nonce_add: 133 an = v.data.(*OPAddressUint64) 134 s.MemoAccountState[an.Address].NonceSet(an.Num) 135 break 136 case Vote_abstention: 137 ha = v.data.(*OPHashAddress) 138 h := s.MemoVoteState[ha.Hash].Height 139 as := s.GetPrevAccountState(ha.Address, h) 140 s.MemoVoteState[ha.Hash].AddAbstention(as.Balance()) 141 case Vote_against: 142 ha = v.data.(*OPHashAddress) 143 h := s.MemoVoteState[ha.Hash].Height 144 as := s.GetPrevAccountState(ha.Address, h) 145 s.MemoVoteState[ha.Hash].AddAgainst(as.Balance()) 146 case Vote_agree: 147 ha = v.data.(*OPHashAddress) 148 h := s.MemoVoteState[ha.Hash].Height 149 as := s.GetPrevAccountState(ha.Address, h) 150 s.MemoVoteState[ha.Hash].AddAgree(as.Balance()) 151 case League_Raise_ut: 152 aa = v.data.(*OPAddressBigInt) 153 ut.Add(ut, aa.Num) 154 } 155 } 156 accountStates := storelaw.AccountStaters{} 157 for _, v := range s.MemoAccountState { 158 accountStates = append(accountStates, v) 159 } 160 161 //todo calculate memberRoot and fill it into memoLeagueState 162 block := &types.Block{ 163 Transactions: s.txs, 164 Header: &types.Header{ 165 Height: s.TargetHeight, 166 PrevBlockHash: s.currentBlockHash, 167 Version: 0x01, 168 TxRoot: s.txs.GetHashRoot(), 169 StateRoot: accountStates.GetHashRoot(), 170 ReceiptsRoot: s.receipts.GetHashRoot(), 171 LeagueId: s.leagueId, 172 }, 173 } 174 175 //fmt.Println("♌️ ♌️ ♌️ ♌️ ♌️ ut️:", ut, " leagueId:", s.leagueId.ToString()) 176 if s.TargetHeight%types.HWidth == 0 { 177 energyUsed := s.ledgeror.GetHeaderBonus(s.leagueId) 178 //fmt.Printf("♐️ ♐️ league ExecuteOplogs destroyEnergy:%d ut:%d\n ", energyUsed.Uint64(), ut.Uint64()) 179 rat1 := new(big.Rat).SetInt(ut) 180 rat2 := new(big.Rat).SetInt(energyUsed) 181 rat1.Inv(rat1) 182 rat1.Mul(rat1, rat2) 183 rat1.Mul(rat1, ratU) 184 rfTmp := big.NewFloat(0).SetRat(rat1) 185 integer, _ := rfTmp.Uint64() 186 block.Header.Bonus = integer 187 //fmt.Println("♐️ ♐️ league ExecuteOplogs bonus ", integer) 188 189 } 190 feeSum := big.NewInt(0) 191 for _, v := range s.receipts { 192 feeSum.Add(feeSum, big.NewInt(0).SetUint64(v.GasUsed)) 193 } 194 blkInfo := &storelaw.OrgBlockInfo{ 195 Block: block, 196 Receipts: s.receipts, 197 AccStates: accountStates, 198 FeeSum: feeSum, 199 VoteStates: make([]*storelaw.VoteState, 0, len(s.voteNew)+len(s.MemoVoteState)), 200 AccountVoteds: make([]*storelaw.AccountVoted, 0, len(s.DirtyVote)), 201 } 202 //put new vote into votestates 203 blkInfo.VoteStates = append(blkInfo.VoteStates, s.voteNew...) 204 if len(s.MemoVoteState) > 0 { 205 for k, v := range s.MemoVoteState { 206 blkInfo.VoteStates = append(blkInfo.VoteStates, v) 207 208 if v.GetResult(s.voteUT[k].UT, 67) { 209 if _, ok := afterVote[k]; ok { 210 fmt.Println("⭕️ vote first pass ", s.voteUT[k].Tx.Hash()) 211 blkInfo.VoteFirstPass = append(blkInfo.VoteFirstPass, s.voteUT[k].Tx) 212 } 213 } 214 } 215 } 216 for k, v := range s.DirtyVote { 217 av := &storelaw.AccountVoted{ 218 VoteId: k, 219 Height: s.TargetHeight, 220 Accounts: make([]common.Address, 0, len(v)), 221 } 222 for ki, _ := range v { 223 av.Accounts = append(av.Accounts, ki) 224 } 225 blkInfo.AccountVoteds = append(blkInfo.AccountVoteds, av) 226 } 227 //UT TODO if the tx causes a change in the ut amount,it needs to be calculated on ut. 228 blkInfo.UT = ut 229 return blkInfo 230 } 231 } 232 func (s *StateValidate) GetTxLen() int { 233 return s.txs.Len() 234 } 235 236 //VerifyTx is verify that the transaction is valid and return the processing plan 237 //returns: 238 // int ------ -1: throw tx,0: back to queue, 1: efficient transaction 239 // error ------ Existing warning 240 // if verify pass,tx is going to change StateValidate,append WaitOplogs,to affect dirtyState 241 func (s *StateValidate) VerifyTx(tx *types.Transaction) (int, error) { 242 s.m.Lock() 243 defer s.m.Unlock() 244 //fmt.Println("🔍 verifytx start") 245 err := s.CheckSign(tx) 246 if err != nil { 247 return -1, err 248 } 249 err = s.CheckFee(tx) 250 if err != nil { 251 return -1, err 252 253 } 254 oplogs := HandleTransaction(tx) 255 //route oplogs to its homestate 256 accountOps := make([]*OpLog, 0, len(oplogs)) 257 bonusOps := make([]*OpLog, 0, 3) 258 var ( 259 voteOp *OpLog 260 raiseOp *OpLog 261 ) 262 //feeOp := &OpLog{} 263 //check exits in dirtystate,if not then get 264 for k, v := range oplogs { 265 if v.method < AccountMaxLine { 266 accountOps = append(accountOps, oplogs[k]) 267 /*if v.method == Account_energy_consume { 268 feeOp = oplogs[k] 269 }*/ 270 } else if v.method == Account_bonus_fee { 271 bonusOps = append(bonusOps, v) 272 } else if v.method == League_Raise_ut { 273 raiseOp = v 274 } else { 275 voteOp = v 276 } 277 } 278 fee := uint64(0) 279 if tx.TxData.Fee != nil { 280 fee = tx.TxData.Fee.Uint64() 281 } 282 receipt := &types.Receipt{ 283 TxHash: tx.Hash(), 284 GasUsed: fee, 285 } 286 //fill oplogs into WaitOplogs and FeeOplogs (group by) 287 opIndes1, err := s.VerifyAccount(accountOps) 288 if err != nil { 289 s.RollbackAccount(accountOps, opIndes1) 290 if err == errors.ERR_STATE_ACCOUNT_NONCE_DISCONTINUITY { 291 return 0, err 292 } else { 293 return -1, err 294 } 295 /*err = s.verifyAccount(feeOp) 296 if err != nil { 297 return 0, err 298 } 299 s.appendWaitOplog(feeOp) 300 s.appendTx(tx) 301 s.appendReceipt(receipt) 302 return 1, nil*/ 303 } 304 if len(bonusOps) > 0 { 305 ops, err := s.verifyBonus(bonusOps[0]) 306 if err != nil { 307 s.RollbackAccount(accountOps, opIndes1) 308 return -1, err 309 } 310 bonusOps = append(bonusOps, ops...) 311 } 312 if voteOp != nil { 313 err = s.verifyVote(voteOp) 314 if err != nil { 315 s.RollbackAccount(accountOps, opIndes1) 316 return -1, err 317 } 318 } 319 320 receipt.Status = true 321 s.appendReceipt(receipt) 322 s.appendWaitOplogs(accountOps) 323 s.appendWaitOplog(voteOp) 324 s.appendWaitOplogs(bonusOps) 325 s.appendWaitOplog(raiseOp) 326 s.appendTx(tx) 327 return 1, nil 328 } 329 330 func (s *StateValidate) appendWaitOplogs(oplogs []*OpLog) { 331 s.WaitOplogs = append(s.WaitOplogs, oplogs...) 332 } 333 func (s *StateValidate) appendWaitOplog(oplog *OpLog) { 334 if oplog != nil { 335 s.WaitOplogs = append(s.WaitOplogs, oplog) 336 } 337 } 338 func (s *StateValidate) appendTx(tx *types.Transaction) { 339 s.txs = append(s.txs, tx) 340 s.appendVoteNew(tx) 341 } 342 func (s *StateValidate) appendVoteNew(tx *types.Transaction) { 343 if voteTypeContains(tx.TxType) { 344 vs := &storelaw.VoteState{ 345 VoteId: tx.Hash(), 346 Height: s.TargetHeight, 347 Agree: big.NewInt(0), 348 Against: big.NewInt(0), 349 Abstention: big.NewInt(0), 350 } 351 s.voteNew = append(s.voteNew, vs) 352 } 353 } 354 355 func (s *StateValidate) appendReceipt(receipt *types.Receipt) { 356 s.receipts = append(s.receipts, receipt) 357 } 358 359 // 360 func (s *StateValidate) CheckSign(tx *types.Transaction) error { 361 return nil 362 } 363 364 //todo 365 func (s *StateValidate) CheckFee(tx *types.Transaction) error { 366 return nil 367 } 368 func (s *StateValidate) CheckNodeId(nodeId common.Address) error { 369 return nil 370 } 371 372 //TODO get data from leder_store 373 func (s *StateValidate) checkMemberState(address, leagueId common.Address) error { 374 return nil 375 }