github.com/sixexorg/magnetic-ring@v0.0.0-20191119090307-31705a21e419/store/mainchain/validation/state_validate.go (about) 1 package validation 2 3 import ( 4 "sync" 5 6 "math/big" 7 8 "fmt" 9 10 "github.com/sixexorg/magnetic-ring/common" 11 "github.com/sixexorg/magnetic-ring/core/mainchain/types" 12 "github.com/sixexorg/magnetic-ring/errors" 13 "github.com/sixexorg/magnetic-ring/log" 14 "github.com/sixexorg/magnetic-ring/store/mainchain/states" 15 "github.com/sixexorg/magnetic-ring/store/mainchain/storages" 16 ) 17 18 var ( 19 feeLimit = big.NewInt(0) 20 objTypes = make(map[types.TransactionType]struct{}) 21 ) 22 23 func init() { 24 objTypes[types.ConsensusLeague] = struct{}{} 25 objTypes[types.LockLeague] = struct{}{} 26 objTypes[types.RaiseUT] = struct{}{} 27 } 28 func containObjTypes(key types.TransactionType) bool { 29 _, ok := objTypes[key] 30 return ok 31 } 32 33 // todo how to do with the nonce 34 type StateValidate struct { 35 TargetHeight uint64 36 currentBlockHeight uint64 37 currentBlockHash common.Hash 38 //Only contain changes state 39 CacheLMemberState map[common.Address]map[common.Address]*states.LeagueMember 40 41 MemoAccountState map[common.Address]*states.AccountState 42 MemoLeagueState map[common.Address]*states.LeagueState 43 44 TargetLMemberState map[common.Address]map[common.Address]*states.LeagueMember 45 46 //for one tx ,Take the lower limit,only the subtraction 47 DirtyAccountState map[common.Address]*states.AccountState 48 DirtyLeagueState map[common.Address]*states.LeagueState 49 //one by one,an account can only perform one operation about add or exit 50 DirtyLMemberState map[common.Address]map[common.Address]*states.LeagueMember 51 52 //if league is newly created,it can't accept anything else 53 LeagueForCreate []*storages.LeagueKV 54 SymbolForCreate map[common.Symbol]struct{} 55 Blacklist map[common.Address]bool 56 57 ParentBonusHeight uint64 58 WaitOplogs []*OpLog //Transactional submission 59 60 objTxs types.Transactions 61 receipts types.Receipts 62 txs types.Transactions 63 ledgerStore *storages.LedgerStoreImp 64 65 LeagueGas *big.Int 66 M *sync.Mutex 67 } 68 69 func NewStateValidate(ledgerStore *storages.LedgerStoreImp) *StateValidate { 70 log.Info("func validation NewStateValidate") 71 72 curHeight, curHash := ledgerStore.GetCurrentBlock() 73 AccountNonceInstance.reset(curHeight) 74 s := &StateValidate{ 75 TargetHeight: curHeight + 1, 76 currentBlockHash: curHash, 77 currentBlockHeight: curHeight, 78 MemoAccountState: make(map[common.Address]*states.AccountState), 79 MemoLeagueState: make(map[common.Address]*states.LeagueState), 80 DirtyAccountState: make(map[common.Address]*states.AccountState), 81 DirtyLeagueState: make(map[common.Address]*states.LeagueState), 82 LeagueForCreate: make([]*storages.LeagueKV, 0), 83 TargetLMemberState: make(map[common.Address]map[common.Address]*states.LeagueMember), //league account 84 CacheLMemberState: make(map[common.Address]map[common.Address]*states.LeagueMember), 85 DirtyLMemberState: make(map[common.Address]map[common.Address]*states.LeagueMember), 86 Blacklist: make(map[common.Address]bool), 87 SymbolForCreate: make(map[common.Symbol]struct{}), 88 ledgerStore: ledgerStore, 89 WaitOplogs: []*OpLog{}, //Transactional submission 90 LeagueGas: new(big.Int), 91 M: new(sync.Mutex), 92 } 93 94 return s 95 } 96 func (s *StateValidate) GetTxLen() int { 97 if s == nil { 98 return -1 99 } 100 return s.txs.Len() 101 } 102 func (s *StateValidate) TxInheritance() <-chan *types.Transaction { 103 ch := make(chan *types.Transaction, 20) 104 for k, _ := range s.txs { 105 if !s.ledgerStore.ContainTx(s.txs[k].Hash()) { 106 ch <- s.txs[k] 107 } 108 } 109 close(ch) 110 return ch 111 } 112 113 //ExecuteOplogs is perform the verified transaction calculation and generate the status data 114 func (s *StateValidate) ExecuteOplogs() ( 115 blockInfo *storages.BlockInfo) { 116 s.M.Lock() 117 defer s.M.Unlock() 118 { 119 log.Info("func ExecuteOplogs", "blockTargetHeight", s.TargetHeight, "txlen", s.txs.Len()) 120 var ( 121 aa *OPAddressBigInt 122 an *OPAddressUint64 123 ad *OPAddressAdress 124 fee = big.NewInt(0) 125 ) 126 /*for k, v := range s.MemoAccountState { 127 fmt.Println("ex you know", k.ToString(), v.Address.ToString(), v.Data.Nonce) 128 129 }*/ 130 for _, optmp := range s.WaitOplogs { 131 v := optmp 132 switch v.method { 133 case Account_box_add: 134 aa = v.data.(*OPAddressBigInt) 135 s.MemoAccountState[aa.Address].Data.Balance.Add(s.MemoAccountState[aa.Address].Data.Balance, aa.Num) 136 break 137 case Account_energy_add: 138 aa = v.data.(*OPAddressBigInt) 139 s.MemoAccountState[aa.Address].Data.EnergyBalance.Add(s.MemoAccountState[aa.Address].Data.EnergyBalance, aa.Num) 140 break 141 case Account_box_sub: 142 aa = v.data.(*OPAddressBigInt) 143 s.MemoAccountState[aa.Address].Data.Balance.Sub(s.MemoAccountState[aa.Address].Data.Balance, aa.Num) 144 break 145 case Account_energy_sub, Account_energy_consume: 146 aa = v.data.(*OPAddressBigInt) 147 s.MemoAccountState[aa.Address].Data.EnergyBalance.Sub(s.MemoAccountState[aa.Address].Data.EnergyBalance, aa.Num) 148 if v.method == Account_energy_consume { 149 fee.Add(fee, aa.Num) 150 } 151 break 152 case Account_bonus_left: 153 an = v.data.(*OPAddressUint64) 154 s.MemoAccountState[an.Address].Data.BonusHeight = an.Num 155 break 156 case Account_nonce_add: 157 an = v.data.(*OPAddressUint64) 158 s.MemoAccountState[an.Address].Data.Nonce = an.Num 159 break 160 case League_create: 161 modelCreate := v.data.(*OPCreateLeague) 162 leagueState := &states.LeagueState{ 163 Address: modelCreate.League, 164 Height: s.TargetHeight, 165 MinBox: modelCreate.Minbox, 166 Creator: modelCreate.Creator, 167 Rate: modelCreate.Rate, 168 Private: modelCreate.Private, 169 Data: &states.League{ 170 Nonce: 1, 171 FrozenBox: modelCreate.FrozenBox, 172 MemberRoot: common.Hash{}, //todo merkle root 173 Name: common.Hash{}, 174 }, 175 } 176 s.MemoLeagueState[leagueState.Address] = leagueState 177 break 178 case League_member_add, League_member_apply: 179 ad = v.data.(*OPAddressAdress) 180 if s.TargetLMemberState[ad.Second] == nil { 181 s.TargetLMemberState[ad.Second] = make(map[common.Address]*states.LeagueMember) 182 } 183 s.TargetLMemberState[ad.Second][ad.First] = s.DirtyLMemberState[ad.Second][ad.First] 184 fmt.Printf("🔆 ExecuteOplogs dirtyLMemberState %v\n", s.DirtyLMemberState[ad.Second][ad.First]) 185 break 186 case League_member_remove: 187 ad = v.data.(*OPAddressAdress) 188 if s.TargetLMemberState[ad.Second] == nil { 189 s.TargetLMemberState[ad.Second] = make(map[common.Address]*states.LeagueMember) 190 } 191 s.TargetLMemberState[ad.Second][ad.First] = s.DirtyLMemberState[ad.Second][ad.First] 192 fmt.Printf("🔆 ExecuteOplogs dirtyLMemberState %v\n", s.DirtyLMemberState[ad.Second][ad.First]) 193 case League_nonce_add: 194 an = v.data.(*OPAddressUint64) 195 s.MemoLeagueState[an.Address].Data.Nonce = an.Num 196 //fmt.Println("execute 2", an.Address.ToString(), an.Num) 197 break 198 case League_gas_destroy: 199 aa = v.data.(*OPAddressBigInt) 200 s.LeagueGas.Add(s.LeagueGas, aa.Num) 201 break 202 case League_raise: 203 aa = v.data.(*OPAddressBigInt) 204 s.MemoLeagueState[aa.Address].AddMetaBox(aa.Num) 205 break 206 } 207 } 208 accountStates := make(states.AccountStates, 0, len(s.MemoAccountState)) 209 for _, v := range s.MemoAccountState { 210 /* log.Info("--------------------------accountState------------start--------------") 211 fmt.Printf("energy:%d,crystal:%d,nonce:%d,height:%d,address:%s\n", v.Data.EnergyBalance.Uint64(), v.Data.Balance.Uint64(), v.Data.Nonce, v.Height, v.Address.ToString()) 212 as, _ := s.ledgerStore.GetAccountByHeight(v.Height, v.Address) 213 if as != nil { 214 215 fmt.Printf("accountState ====> address :%s,nonce:%d,crystal:%d,energy:%d,height:%d \n", as.Address.ToString(), as.Data.Nonce, as.Data.Balance.Uint64(), as.Data.EnergyBalance.Uint64(), as.Height) 216 log.Info("--------------------------accountState------------end--------------") 217 }*/ 218 as := v 219 accountStates = append(accountStates, as) 220 //fmt.Println("execute state rennbon", as.Address.ToString(), as.Data.Nonce) 221 /* 222 fmt.Println("key", k.ToString())*/ 223 } 224 225 //todo calculate memberRoot and fill it into memoLeagueState 226 leagueMembers := make(states.LeagueMembers, 0) 227 for k, v := range s.TargetLMemberState { 228 lms := make(states.LeagueMembers, 0) 229 for _, vi := range v { 230 member := vi 231 lms = append(lms, member) 232 hashRoot := lms.GetHashRoot() 233 s.MemoLeagueState[k].Data.MemberRoot = hashRoot 234 leagueMembers = append(leagueMembers, member) 235 } 236 } 237 leagueStates := make(states.LeagueStates, 0, len(s.MemoLeagueState)) 238 for k, _ := range s.MemoLeagueState { 239 leagueStates = append(leagueStates, s.MemoLeagueState[k]) 240 } 241 //todo calculate memberRoot and fill it into memoLeagueState 242 fmt.Println("🔨 🔧 ExecuteOplogs txlen:", s.txs.Len()) 243 txs := make(types.Transactions, 0, len(s.txs)+len(s.objTxs)) 244 txs = append(txs, s.txs...) 245 txs = append(txs, s.objTxs...) 246 block := &types.Block{ 247 Transactions: txs, 248 Header: &types.Header{ 249 Height: s.TargetHeight, 250 PrevBlockHash: s.currentBlockHash, 251 Version: 0x01, 252 TxRoot: txs.GetHashRoot(), 253 StateRoot: accountStates.GetHashRoot(), 254 LeagueRoot: leagueStates.GetHashRoot(), 255 ReceiptsRoot: s.receipts.GetHashRoot(), 256 }, 257 Sigs: &types.SigData{}, 258 } 259 // Temporary cancellation, account recovery system is not designed 260 //if s.TargetHeight%types.HWidth == 0 { 261 // lvs, err := s.ledgerStore.GetNextHeaderProperty(s.TargetHeight) 262 // if err != nil { 263 // panic(err) 264 // } 265 // fmt.Println("🔨 🔧 ExecuteOplogs pack block head bonus ", lvs) 266 // for k, v := range lvs { 267 // switch k { 268 // case 0: 269 // block.Header.Lv1 = v 270 // break 271 // case 1: 272 // block.Header.Lv2 = v 273 // break 274 // case 2: 275 // block.Header.Lv3 = v 276 // break 277 // case 3: 278 // block.Header.Lv4 = v 279 // break 280 // case 4: 281 // block.Header.Lv5 = v 282 // break 283 // case 5: 284 // block.Header.Lv6 = v 285 // break 286 // case 6: 287 // block.Header.Lv7 = v 288 // break 289 // case 7: 290 // block.Header.Lv8 = v 291 // break 292 // case 8: 293 // block.Header.Lv9 = v 294 // break 295 // } 296 // } 297 //} 298 feeSum := big.NewInt(0) 299 for _, v := range s.receipts { 300 feeSum.Add(feeSum, big.NewInt(0).SetUint64(v.GasUsed)) 301 } 302 303 /*gasDestroy1 := new(big.Int) 304 hundred := big.NewInt(100) 305 gasDestroy1.Mul(feeSum, hundred) 306 gasDestroy1.Div(gasDestroy1, big.NewInt(75)) 307 308 gasDestroy2 := new(big.Int) 309 gasDestroy2.Mul(s.LeagueGas, hundred) 310 gasDestroy2.Div(gasDestroy2, big.NewInt(30)) 311 312 gasDestroy1.Add(gasDestroy1, gasDestroy2)*/ 313 blockkInfo := &storages.BlockInfo{ 314 Block: block, 315 Receipts: s.receipts, 316 AccountStates: accountStates, 317 LeagueStates: leagueStates, 318 Members: leagueMembers, 319 FeeSum: feeSum, 320 LeagueKVs: s.LeagueForCreate, 321 ObjTxs: s.objTxs, 322 //GasDestroy: gasDestroy1, 323 } 324 //return block, s.receipts, accountStates, leagueStates, leagueMembers, fee 325 return blockkInfo 326 } 327 } 328 329 //VerifyTx is verify that the transaction is valid and return the processing plan 330 //returns: 331 // int ------ -1: throw tx,0: back to queue, 1: efficient transaction 332 // error ------ Existing warning 333 // if verify pass,tx is going to change StateValidate,append WaitOplogs,to affect dirtyState 334 func (s *StateValidate) VerifyTx(tx *types.Transaction) (int, error) { 335 //log.Info("func VerifyTx 01", "tx.Hash", tx.Hash().String()) 336 //log.Info("func VerifyTx 02", "txlen", s.txs.Len()) 337 //fmt.Println("bbbb", tx.TxData.Froms.Tis[0].Nonce) 338 err := s.CheckSign(tx) 339 if err != nil { 340 return -1, err 341 } 342 343 err = s.CheckFee(tx) 344 if err != nil { 345 return -1, err 346 347 } 348 //fmt.Println("---------tx start--------") 349 //defer fmt.Println("---------tx end--------") 350 oplogs := HandleTransaction(tx) 351 l := len(oplogs) 352 //route oplogs to its homestate 353 accountOps := make([]*OpLog, 0, l) 354 leagueOps := make([]*OpLog, 0, l) 355 bonusOps := make([]*OpLog, 0, 3) 356 //feeOp := &OpLog{} 357 gused := uint64(0) 358 if tx.TxData.Fee != nil { 359 gused = tx.TxData.Fee.Uint64() 360 } 361 receipt := &types.Receipt{ 362 GasUsed: gused, 363 TxHash: tx.Hash(), 364 } 365 //check exits in dirtystate,if not then get 366 for _, v := range oplogs { 367 opTmp := v 368 if v.method < AccountMaxLine { 369 accountOps = append(accountOps, opTmp) 370 /*if v.method == Account_energy_consume { 371 feeOp = opTmp 372 }*/ 373 } else if v.method > LeagueMinLine && v.method < LeagueMaxLine { 374 leagueOps = append(leagueOps, opTmp) 375 } else if v.method == Account_bonus_fee { 376 bonusOps = append(bonusOps, opTmp) 377 } 378 } 379 380 //fill oplogs into WaitOplogs and FeeOplogs (group by) 381 opIndes1, err := s.VerifyAccount(accountOps) 382 if err != nil { 383 s.RollbackAccount(accountOps, opIndes1) 384 if err == errors.ERR_STATE_ACCOUNT_NONCE_DISCONTINUITY { 385 return 0, err 386 } else { 387 return -1, err 388 } 389 /* err = s.verifyAccount(feeOp) 390 if err != nil { 391 return 0, err 392 } 393 s.appendWaitOplogs(feeOp) 394 s.appendReceipt(receipt) 395 s.appendTx(tx) 396 return 1, nil*/ 397 } 398 if len(bonusOps) > 0 { 399 ops, err := s.verifyBonus(bonusOps[0]) 400 if err != nil { 401 s.RollbackAccount(accountOps, opIndes1) 402 return -1, err 403 } 404 bonusOps = append(bonusOps, ops...) 405 } 406 opIndes2, err := s.VerifyLeague(leagueOps) 407 if err != nil { 408 //TODO if league has something that has to be done 409 s.RollbackAccount(accountOps, opIndes1) 410 s.RollbackLeague(leagueOps, opIndes2) 411 return -1, err 412 /*if err == errors.ERR_STATE_LEAGUE_NONCE_BIGGER { 413 return 0, err 414 } else {*/ 415 416 //} 417 /* err = s.verifyAccount(feeOp) 418 s.appendWaitOplogs(feeOp) 419 s.appendReceipt(receipt) 420 s.appendTx(tx) 421 return 1, nil*/ 422 } 423 424 receipt.Status = true 425 426 s.appendReceipt(receipt) 427 s.appendWaitOplogs(accountOps...) 428 s.appendWaitOplogs(leagueOps...) 429 s.appendWaitOplogs(bonusOps...) 430 s.appendTx(tx) 431 432 //log.Info("func VerifyTx 03", "appendTx", tx.Hash().String()) 433 434 if tx.TxType == types.EnergyToLeague { 435 fmt.Println("转energy到圈子") 436 } 437 return 1, nil 438 } 439 440 func (s *StateValidate) appendWaitOplogs(oplogs ...*OpLog) { 441 s.WaitOplogs = append(s.WaitOplogs, oplogs...) 442 } 443 444 func (s *StateValidate) appendReceipt(receipt *types.Receipt) { 445 s.receipts = append(s.receipts, receipt) 446 } 447 func (s *StateValidate) appendTx(tx *types.Transaction) { 448 if containObjTypes(tx.TxType) { 449 s.objTxs = append(s.objTxs, tx) 450 } else { 451 s.txs = append(s.txs, tx) 452 } 453 } 454 455 func (s *StateValidate) CheckSign(tx *types.Transaction) error { 456 if !containObjTypes(tx.TxType) { 457 b, err := tx.VerifySignature() 458 if err != nil { 459 return err 460 } 461 if !b { 462 return errors.ERR_TX_SIGN 463 } 464 } 465 return nil 466 } 467 468 //todo 469 func (s *StateValidate) CheckFee(tx *types.Transaction) error { 470 return nil 471 /* if containObjTypes(tx.TxType) { 472 return nil 473 } else { 474 feeLimit.SetUint64(2) 475 if tx.TxData.Fee.Cmp(feeLimit) == -1 { 476 return errors.NewErr("fee not enought") 477 } 478 return nil 479 }*/ 480 } 481 func (s *StateValidate) CheckNodeId(nodeId common.Address) error { 482 return nil 483 } 484 485 func (s *StateValidate) RemoveElementInLeagueForCreate(address common.Address) { 486 index := -1 487 for k, v := range s.LeagueForCreate { 488 if address == v.K { 489 index = k 490 } 491 } 492 if index != -1 { 493 if index == len(s.LeagueForCreate) { 494 s.LeagueForCreate = s.LeagueForCreate[:index] 495 } else { 496 s.LeagueForCreate = append(s.LeagueForCreate[:index], s.LeagueForCreate[index+1:]...) 497 } 498 } 499 }