github.com/sixexorg/magnetic-ring@v0.0.0-20191119090307-31705a21e419/radar/mainchain/league_consumes.go (about) 1 package mainchain 2 3 import ( 4 "log" 5 "math/big" 6 "sync" 7 8 "fmt" 9 10 "github.com/sixexorg/magnetic-ring/common" 11 maintypes "github.com/sixexorg/magnetic-ring/core/mainchain/types" 12 orgtypes "github.com/sixexorg/magnetic-ring/core/orgchain/types" 13 14 "time" 15 16 "bytes" 17 18 "sort" 19 20 "github.com/sixexorg/magnetic-ring/errors" 21 "github.com/sixexorg/magnetic-ring/store/mainchain/extstorages" 22 "github.com/sixexorg/magnetic-ring/store/storelaw" 23 ) 24 25 var ( 26 leagueConsumers *LeagueConsumers 27 unlockEnergy = big.NewInt(0) 28 txTypeForReference = make(map[orgtypes.TransactionType]struct{}) 29 txTypeForTransfer = make(map[orgtypes.TransactionType]struct{}) 30 ) 31 32 func init() { 33 txTypeForReference[orgtypes.EnergyFromMain] = struct{}{} 34 txTypeForReference[orgtypes.Join] = struct{}{} 35 36 txTypeForTransfer[orgtypes.EnergyToMain] = struct{}{} 37 } 38 39 type LeagueConsumers struct { 40 m *sync.Mutex 41 42 lgHtCache map[common.Address]uint64 //last get league height cache 43 44 blockCh chan *orgtypes.Block 45 consumers map[common.Address]*LeagueConsumer // Circle address Circle consumer 46 47 isminer bool 48 adpter *ConsumerAdapter 49 ledgeror storelaw.Ledger4Validation 50 51 //These properties are designed to perform switching logicοΌ 52 // but this logic is not needed now and is now used for unit tests 53 wg *sync.WaitGroup 54 lighthouse bool //Notifies the program that this round of calculations will be closed 55 leagueSize int // Number of circles 56 stopSignal chan common.Address 57 txs maintypes.Transactions 58 } 59 60 func NewLeagueConsumers(adpter *ConsumerAdapter) *LeagueConsumers { 61 leagueConsumers = &LeagueConsumers{ 62 m: new(sync.Mutex), 63 consumers: make(map[common.Address]*LeagueConsumer), 64 blockCh: make(chan *orgtypes.Block, 10000), //todo Need to control the details of the upper limit, add later 65 stopSignal: make(chan common.Address, 1000), 66 wg: new(sync.WaitGroup), 67 adpter: adpter, 68 } 69 go leagueConsumers.routing() 70 //actor := NewMainRadarActor(leagueConsumers.ReceiveBlock) 71 72 //pid, err := startActor(actor, "main radar actor") 73 return leagueConsumers 74 } 75 76 func GetLeagueConsumersInstance() *LeagueConsumers { 77 return leagueConsumers 78 } 79 80 func (this *LeagueConsumers) CommitLastHeight() { 81 for _, v := range this.consumers { 82 v.commitLastHeight() 83 } 84 } 85 func (this *LeagueConsumers) RollbackWillDo() { 86 for _, v := range this.consumers { 87 v.rollbackWillDo() 88 } 89 } 90 91 func (this *LeagueConsumers) GetLeagueHeight() map[common.Address]uint64 { 92 re := make(map[common.Address]uint64) 93 for k, v := range this.consumers { 94 curHeight := v.currentHeight() 95 re[k] = curHeight 96 } 97 this.lgHtCache = re 98 return re 99 } 100 func (this *LeagueConsumers) GenerateMainTxs() (maintypes.Transactions, error) { 101 return this.GenerateMainTxByLeagueHeight(nodeLHC.getNodeLHs()) 102 } 103 104 func (this *LeagueConsumers) GenerateMainTxByLeagueHeight(earth map[common.Address]uint64, nodes []map[common.Address]uint64) (maintypes.Transactions, error) { 105 local := this.GetLeagueHeight() 106 lh := this.interceptHeight(local, earth, nodes...) 107 for k, v := range lh { 108 fmt.Println("π π π key:", k.ToString(), " height:", v) 109 } 110 txs, err := this.generateMainTx(lh) 111 if err != nil { 112 return nil, err 113 } 114 /* this.adpter.initTeller() 115 this.adpter.TxPoolTlr.Tell(txpool.MustPackTxsReq{ 116 Txs: txs, 117 })*/ 118 return txs, nil 119 } 120 121 type nodeHeight struct { 122 ndIdx int 123 h uint64 124 } 125 126 //get 127 128 func (this *LeagueConsumers) interceptHeight(local, earth map[common.Address]uint64, nodes ...map[common.Address]uint64) map[common.Address]uint64 { 129 l := len(local) 130 if l == 0 { 131 return nil 132 } 133 result := make(map[common.Address]uint64, l) 134 rl := uint64(len(nodes)) 135 idx := rl / 2 136 referenceIdx := make([]int, 0, idx+1) 137 realm := this.min(local, earth) 138 for ko, v := range realm { 139 tmpV := v 140 if tmpV == 0 { 141 result[ko] = tmpV 142 } else { 143 if len(referenceIdx) == 0 { 144 hsort := make([]*nodeHeight, 0, rl) 145 for ndIdx, remote := range nodes { 146 hsort = append(hsort, &nodeHeight{ndIdx: ndIdx, h: remote[ko]}) 147 } 148 sort.Slice(hsort, func(i, j int) bool { 149 return hsort[i].h < hsort[j].h 150 }) 151 for _, rv := range hsort[idx:] { 152 referenceIdx = append(referenceIdx, rv.ndIdx) 153 } 154 if hsort[idx].h > tmpV { 155 result[ko] = tmpV 156 } else { 157 result[ko] = hsort[idx].h 158 } 159 } else { 160 hs := make([]uint64, 0, idx+1) 161 for _, rv := range referenceIdx { 162 hs = append(hs, nodes[rv][ko]) 163 } 164 sort.Slice(hs, func(i, j int) bool { 165 return hs[i] < hs[j] 166 }) 167 if hs[0] > tmpV { 168 result[ko] = tmpV 169 } else { 170 result[ko] = hs[0] 171 } 172 } 173 } 174 } 175 return result 176 } 177 func (this *LeagueConsumers) min(local, earth map[common.Address]uint64) map[common.Address]uint64 { 178 result := make(map[common.Address]uint64, len(local)) 179 for k, v := range local { 180 for ki, vi := range earth { 181 if k.Equals(ki) { 182 if v < vi { 183 result[k] = v 184 } else { 185 result[k] = vi 186 } 187 } 188 } 189 } 190 return result 191 } 192 func (this *LeagueConsumers) generateMainTx(leagueHM map[common.Address]uint64) (maintypes.Transactions, error) { 193 mtcCh := make(chan *MainTxCradle, 50) 194 leagueLen := len(leagueHM) 195 wg := new(sync.WaitGroup) 196 wg.Add(leagueLen) 197 wg2 := new(sync.WaitGroup) 198 for k, v := range leagueHM { 199 lgcmer, ok := this.consumers[k] 200 if ok { 201 go func() { 202 mtc, err := lgcmer.generateMainTx(v) 203 if err != nil { 204 //todo log 205 fmt.Println("π ", lgcmer.leagueId.ToString(), " generate failed") 206 wg.Done() 207 return 208 } 209 wg2.Add(1) 210 mtcCh <- mtc 211 wg.Done() 212 }() 213 } else { 214 wg.Done() 215 } 216 } 217 txs := make(maintypes.Transactions, 0, leagueLen*5) 218 go func() { 219 for ch := range mtcCh { 220 txs = append(txs, ch.Check) 221 txs = append(txs, ch.ReferenceTxs...) 222 wg2.Done() 223 } 224 }() 225 226 wg.Wait() 227 wg2.Wait() 228 close(mtcCh) 229 return txs, nil 230 } 231 232 type objTxForCheck struct { 233 agg *maintypes.Transaction 234 sons maintypes.Transactions 235 } 236 237 /*func (this *LeagueConsumers) CheckLeaguesWithBoolResponse(txs maintypes.Transactions, timeout time.Duration) bool { 238 ch := make(chan bool, 1) 239 go func() { 240 lsp := NewLeagueStatePipe() 241 ch <- this.checkLeaguesResult(this.ConvertTxsToObjTxForCheck(txs), lsp, false) 242 243 }() 244 select { 245 case re := <-ch: 246 return re 247 case <-time.After(timeout): 248 return false 249 } 250 }*/ 251 func (this *LeagueConsumers) CheckLeaguesWithBoolResponse(txs maintypes.Transactions, timeout time.Duration) error { 252 ch := make(chan bool, 1) 253 go func() { 254 lsp := NewLeagueStatePipe() 255 objTx := this.ConvertTxsToObjTxForCheck(txs) 256 leagueLen := len(objTx) 257 this.checkLeaguesResult(objTx, lsp, true) 258 for { 259 select { 260 case <-lsp.Successed: 261 leagueLen-- 262 if leagueLen == 0 { 263 fmt.Println("π‘ β° CheckLeaguesWithBoolResponse break") 264 ch <- true 265 break 266 } 267 } 268 } 269 }() 270 select { 271 case <-ch: 272 fmt.Println("π‘ β° CheckLeaguesWithBoolResponse <- ch") 273 this.CommitLastHeight() 274 return nil 275 case <-time.After(timeout): 276 this.RollbackWillDo() 277 return errors.ERR_TIME_OUT 278 } 279 } 280 281 func (this *LeagueConsumers) CheckLeaguesResult(txs maintypes.Transactions, lsp *LeagueStatePipe) int { 282 lm := this.ConvertTxsToObjTxForCheck(txs) 283 this.checkLeaguesResult(lm, lsp, true) 284 return len(lm) 285 } 286 287 func (this *LeagueConsumers) ConvertTxsToObjTxForCheck(txs maintypes.Transactions) map[common.Address]*objTxForCheck { 288 leagueTxs := make(map[common.Address]*objTxForCheck) 289 for _, v := range txs { 290 tmpTX := v 291 if leagueTxs[tmpTX.TxData.LeagueId] == nil { 292 leagueTxs[tmpTX.TxData.LeagueId] = &objTxForCheck{} 293 } 294 if tmpTX.TxType == maintypes.ConsensusLeague || tmpTX.TxType == maintypes.LockLeague { 295 leagueTxs[tmpTX.TxData.LeagueId].agg = tmpTX 296 } else { 297 leagueTxs[tmpTX.TxData.LeagueId].sons = append(leagueTxs[tmpTX.TxData.LeagueId].sons, tmpTX) 298 } 299 } 300 return leagueTxs 301 } 302 303 func (this *LeagueConsumers) checkLeaguesResult(leagueTxs map[common.Address]*objTxForCheck, lsp *LeagueStatePipe, withState bool) bool { 304 for k, v := range leagueTxs { 305 go func(league common.Address, otfc *objTxForCheck) { 306 if this.consumers[league] == nil { 307 flag := true 308 for { 309 if flag { 310 flag = false 311 lsp.sendLeagueNeed(league, 1) 312 } 313 time.Sleep(time.Millisecond * 100) 314 if this.consumers[league] != nil { 315 fmt.Printf("π« π check league first fill successed,the id is %s\n", league.ToString()) 316 break 317 } 318 } 319 } 320 this.consumers[league].checkLeagueResultPart2(otfc, this.adpter.Ledger, lsp, withState) 321 }(k, v) 322 } 323 /* if !withState { 324 success := make(chan bool, 1) 325 count := len(leagueTxs) 326 go func(ch chan bool, c int) { 327 for such := range lsp.Successed { 328 if leagueTxs[such] != nil { 329 c-- 330 if c == 0 { 331 ch <- true 332 } 333 } 334 } 335 }(success, count) 336 go func(ch chan bool) { 337 for errch := range lsp.StateSignal { 338 switch errch.(type) { 339 case *LeagueNeed: 340 case *LeagueExec: 341 case *LeagueErr: 342 ch <- false 343 } 344 } 345 }(success) 346 select { 347 case re := <-success: 348 return re 349 } 350 }*/ 351 return false 352 } 353 354 //checkLeagueResult is verify league height 355 //otfc: mainTxs create by consensus, ledger:storage,lsp:channel response,withState:callback which league height need synchronous,true for p2p,false for consensus 356 func (this *LeagueConsumer) checkLeagueResultPart2(otfc *objTxForCheck, ledger *extstorages.LedgerStoreImp, lsp *LeagueStatePipe, withState bool) { 357 /*ch := make(chan bool, 1) 358 go func() {*/ 359 start := otfc.agg.TxData.StartHeight 360 end := otfc.agg.TxData.EndHeight 361 isLock := otfc.agg.TxType == maintypes.LockLeague 362 root := otfc.agg.TxData.BlockRoot 363 var err error 364 if this.currentHeight() >= end { 365 goto DOIT 366 } else { 367 //todo Waiting for calculation, less logic 368 //lsp.sendLeagueExec(this.leagueId, this.currentHeight()) 369 sendCache := make(map[uint64]bool) 370 for { 371 cHeight := this.currentHeight() 372 fmt.Println("π« checkLeagueResultPart2 loop ", cHeight) 373 if cHeight >= end { 374 fmt.Println("π« checkLeagueResultPart2 break ", cHeight) 375 break 376 } else if withState { 377 targetH := cHeight + 1 378 if !sendCache[targetH] { 379 sendCache[targetH] = true 380 fmt.Printf("π« checkLeagueResultPart2 send need:%d target:%d \n", targetH, end) 381 lsp.sendLeagueNeed(this.leagueId, targetH) 382 } 383 } 384 time.Sleep(time.Millisecond * 100) 385 } 386 fmt.Println("π« checkLeagueResultPart2 go doit") 387 goto DOIT 388 } 389 DOIT: 390 fmt.Println("π« checkLeagueResultPart2 doit run") 391 err = this.checkInterval(start, end, root, isLock, withState, ledger) 392 if err != nil { 393 lsp.sendError(this.leagueId, err) 394 395 } else { 396 this.willdo = otfc.agg.TxData.EndHeight 397 lsp.sendOk(this.leagueId) 398 } 399 } 400 401 func (this *LeagueConsumer) getLeagueState() uint64 { 402 return this.currentHeight() 403 } 404 405 func (this *LeagueConsumer) checkInterval(start, end uint64, root common.Hash, islock, offsetUpdate bool, ledger *extstorages.LedgerStoreImp) error { 406 hashes := make(common.HashArray, 0, end-start+1) 407 needRemove := make([]uint64, 0, end-start+1) 408 for i := start; i <= end; i++ { 409 h, err := ledger.GetBlockHashByHeight4V(this.leagueId, i) 410 if err != nil { 411 //TODO Inconsistent preservation, need to be processed, a few 412 } 413 hashes = append(hashes, h) 414 needRemove = append(needRemove, i) 415 } 416 hashRoot := hashes.GetHashRoot() 417 if bytes.Equal(hashRoot[:], root[:]) { 418 if (this.lockerr != nil) == islock { 419 /* if offsetUpdate { 420 this.setLastHeight(end) 421 this.removeMainNewBefore(needRemove) 422 }*/ 423 return nil 424 } 425 } 426 err := fmt.Errorf("diff between local and remote") 427 return err 428 } 429 430 //SupplementLeagueConsumer is used to synchronize lost cross-chain storage 431 func (this *LeagueConsumers) SupplementLeagueConsumer(leagueId common.Address, blkHash common.Hash, height uint64) { 432 league := this.getLeagueConsume(leagueId) 433 if height == 1 { 434 435 if !this.isminer && !this.lighthouse { 436 //fmt.Println("π π‘ SupplementLeagueConsumer 1") 437 go func(league *LeagueConsumer) { 438 league.registerConsume(this.setStopSignal, this.getLightHouse) 439 }(league) 440 } 441 } 442 league.setBlockCurrentBySync(blkHash, height) 443 } 444 445 func (this *LeagueConsumers) ReceiveBlock(block *orgtypes.Block) { 446 //fmt.Println("π π‘ π 1") 447 this.blockCh <- block 448 /*this.adpter.initTeller() 449 this.adpter.P2pTlr.Tell(&p2pcommon.OrgPendingData{ 450 BANodeSrc: false, // true:ANode send staller false:staller send staller 451 OrgId: block.Header.LeagueId, // orgid 452 Block: block, // tx 453 })*/ 454 //fmt.Println("π π‘ π 2") 455 } 456 func (this *LeagueConsumers) setStopSignal(leagueId common.Address, tx *maintypes.Transaction) { 457 log.Println("setStopSignal:", leagueId.ToString()) 458 this.stopSignal <- leagueId 459 if tx != nil { 460 this.txs = append(this.txs, tx) 461 } 462 } 463 func (this *LeagueConsumers) getLightHouse() bool { 464 return this.lighthouse 465 } 466 467 //NewRound is to actively launch validation 468 func (this *LeagueConsumers) NewRound() { 469 this.m.Lock() 470 defer this.m.Unlock() 471 { 472 this.isminer = true 473 this.refresh() 474 for _, v := range this.consumers { 475 v.registerConsume(this.setStopSignal, this.getLightHouse) 476 } 477 } 478 } 479 480 //Truncate is to notifies the program that this round of calculations will be closed 481 func (this *LeagueConsumers) Settlement() { 482 this.m.Lock() 483 defer this.m.Unlock() 484 { 485 if this.lighthouse { 486 return 487 } 488 this.lighthouse = true 489 log.Println("leagueSize:", this.leagueSize) 490 this.wg.Add(this.leagueSize) 491 this.await() 492 return 493 } 494 } 495 496 //await is asynchronous waiting 497 func (this *LeagueConsumers) await() { 498 go func() { 499 for ch := range this.stopSignal { 500 log.Println(ch.ToString(), " over") 501 this.wg.Done() 502 } 503 }() 504 this.wg.Wait() 505 } 506 507 func (this *LeagueConsumers) refresh() { 508 this.lighthouse = false 509 this.txs = nil 510 this.stopSignal = make(chan common.Address, 1000) 511 } 512 513 func (this *LeagueConsumers) routing() { 514 for block := range this.blockCh { 515 //todo need check 516 //fmt.Println("π π‘ routing 1") 517 league := this.getLeagueConsume(block.Header.LeagueId) 518 //fmt.Println("π π‘ routing 2", block.Header.Height) 519 league.receiveBlock(block) 520 //fmt.Println("π π‘ routing 3", this.isminer, this.lighthouse) 521 if !this.isminer && !this.lighthouse { 522 //fmt.Println("π π‘ routing 4 registerConsume") 523 //league.registerConsume(this.adpter, this.setStopSignal, this.getLightHouse) 524 go func(league *LeagueConsumer) { 525 league.registerConsume(this.setStopSignal, this.getLightHouse) 526 }(league) 527 } 528 } 529 } 530 531 func (this *LeagueConsumers) getLeagueConsume(leagueId common.Address) *LeagueConsumer { 532 this.m.Lock() 533 defer this.m.Unlock() 534 { 535 if this.consumers[leagueId] == nil { 536 this.consumers[leagueId] = &LeagueConsumer{ 537 blockPool: make(map[uint64]*orgtypes.Block), 538 receiveSign: make(chan uint64, 100), 539 leagueId: leagueId, 540 mainTxUsed: make(common.HashArray, 0, 50), 541 mainTxsNew: make(map[uint64]maintypes.Transactions), 542 adapter: this.adpter, 543 } 544 //fmt.Println("blockHash len:", len(this.consumers[leagueId].blockHashes)) 545 this.leagueSize++ 546 } 547 return this.consumers[leagueId] 548 } 549 } 550 551 /*func (this *LeagueConsumers) checkMainTx(tx *maintypes.Transaction) error { 552 if tx.TxType != maintypes.ConsensusLeague || tx.TxType != maintypes.LockLeague { 553 return nil 554 } 555 if tx.TxData.StartHeight == 1 { 556 if this.consumers[tx.TxData.LeagueId] != nil { 557 return fmt.Errorf("maintx for league check not match.") 558 } 559 l := tx.TxData.EndHeight - tx.TxData.StartHeight 560 asses := make([]storelaw.AccountStaters, 0, l) 561 blocks := make([]*orgtypes.Block, l) 562 for i := tx.TxData.StartHeight; i <= tx.TxData.EndHeight; i++ { 563 block := this.consumers[tx.TxData.LeagueId].blockPool[i] 564 if block == nil { 565 return fmt.Errorf("maintx for league check not match.") 566 } 567 ass, _, err := this.consumers[tx.TxData.LeagueId].verifyBlock(block, this.adpter) 568 if err != nil { 569 return err 570 } 571 asses = append(asses, ass) 572 blocks = append(blocks, block) 573 } 574 575 } 576 return nil 577 } 578 */