github.com/cheng762/platon-go@v1.8.17-0.20190529111256-7deff2d7be26/core/ppos/ticket_state.go (about) 1 package pposm 2 3 import ( 4 "bytes" 5 "errors" 6 "fmt" 7 "github.com/PlatONnetwork/PlatON-Go/common" 8 "github.com/PlatONnetwork/PlatON-Go/common/byteutil" 9 "github.com/PlatONnetwork/PlatON-Go/common/hexutil" 10 "github.com/PlatONnetwork/PlatON-Go/core/ppos_storage" 11 "github.com/PlatONnetwork/PlatON-Go/core/types" 12 "github.com/PlatONnetwork/PlatON-Go/core/vm" 13 "github.com/PlatONnetwork/PlatON-Go/log" 14 "github.com/PlatONnetwork/PlatON-Go/p2p/discover" 15 "github.com/PlatONnetwork/PlatON-Go/params" 16 "github.com/PlatONnetwork/PlatON-Go/rlp" 17 "math/big" 18 "sort" 19 "strings" 20 "sync" 21 ) 22 23 var ( 24 TicketPoolNilErr = errors.New("Ticket Insufficient quantity") 25 TicketPoolOverflowErr = errors.New("Number of ticket pool overflow") 26 EncodeTicketErr = errors.New("Encode Ticket error") 27 EncodePoolNumberErr = errors.New("Encode SurplusQuantity error") 28 DecodeTicketErr = errors.New("Decode Ticket error") 29 DecodePoolNumberErr = errors.New("Decode SurplusQuantity error") 30 RecordExpireTicketErr = errors.New("Record Expire Ticket error") 31 CandidateNotFindErr = errors.New("The Candidate not find") 32 CandidateNilTicketErr = errors.New("This candidate has no ticket") 33 TicketPoolBalanceErr = errors.New("TicketPool not sufficient funds") 34 TicketNotFindErr = errors.New("The Ticket not find") 35 HandleExpireTicketErr = errors.New("Failure to deal with expired tickets") 36 GetCandidateAttachErr = errors.New("Get CandidateAttach error") 37 SetCandidateAttachErr = errors.New("Update CandidateAttach error") 38 VoteTicketErr = errors.New("Voting failed") 39 ) 40 41 type TicketPool struct { 42 // Ticket price 43 TicketPrice *big.Int 44 // Maximum number of ticket pool 45 MaxCount uint32 46 // Reach expired quantity 47 ExpireBlockNumber uint32 48 lock *sync.Mutex 49 } 50 51 //var ticketPool *TicketPool 52 53 // initialize the global ticket pool object 54 func NewTicketPool(configs *params.PposConfig) *TicketPool { 55 //if nil != ticketPool { 56 // return ticketPool 57 //} 58 log.Debug("Build a New TicketPool Info ...") 59 if "" == strings.TrimSpace(configs.TicketConfig.TicketPrice) { 60 configs.TicketConfig.TicketPrice = "100000000000000000000" 61 } 62 var ticketPrice *big.Int 63 if price, ok := new(big.Int).SetString(configs.TicketConfig.TicketPrice, 10); !ok { 64 ticketPrice, _ = new(big.Int).SetString("100000000000000000000", 10) 65 } else { 66 ticketPrice = price 67 } 68 69 ticketPool := &TicketPool{ 70 TicketPrice: ticketPrice, 71 MaxCount: configs.TicketConfig.MaxCount, 72 ExpireBlockNumber: configs.TicketConfig.ExpireBlockNumber, 73 lock: &sync.Mutex{}, 74 } 75 return ticketPool 76 } 77 78 func (t *TicketPool) VoteTicket(stateDB vm.StateDB, owner common.Address, voteNumber uint32, deposit *big.Int, nodeId discover.NodeID, blockNumber *big.Int) (uint32, error) { 79 log.Debug("Call Voting", "statedb addr", fmt.Sprintf("%p", stateDB)) 80 log.Info("Start Voting,VoteTicket", "owner", owner.Hex(), "voteNumber", voteNumber, "price", deposit.Uint64(), "nodeId", nodeId.String(), "blockNumber", blockNumber.Uint64()) 81 successCount, err := t.voteTicket(stateDB, owner, voteNumber, deposit, nodeId, blockNumber) 82 if nil != err { 83 log.Error("Voting failed", "nodeId", nodeId.String(), "voteNumber", voteNumber, "successNum", successCount, "err", err) 84 return successCount, err 85 } 86 // Voting completed, candidates reordered 87 log.Debug("Successfully voted to start updating the list of candidates,VoteTicket", "successNum", successCount) 88 if err := cContext.UpdateElectedQueue(stateDB, blockNumber, nodeId); nil != err { 89 log.Error("Failed to Update candidate when voteTicket success", "err", err) 90 } 91 if successCount > 0 { 92 t := &types.Ticket{ 93 owner, 94 deposit, 95 nodeId, 96 blockNumber, 97 0, 98 } 99 ppos_storage.PutTicket(stateDB.TxHash(), t) 100 } 101 log.Debug("Successful vote, candidate list updated successfully,VoteTicket", "successNum", successCount) 102 return successCount, nil 103 } 104 105 func (t *TicketPool) voteTicket(stateDB vm.StateDB, owner common.Address, voteNumber uint32, deposit *big.Int, nodeId discover.NodeID, blockNumber *big.Int) (uint32, error) { 106 t.lock.Lock() 107 defer t.lock.Unlock() 108 // check ticket pool count 109 surplusQuantity := t.GetPoolNumber(stateDB) 110 log.Debug("Execute voteTicket", "surplusQuantity", surplusQuantity, "voteNumber", voteNumber, "blockNumber", blockNumber.Uint64()) 111 if surplusQuantity == 0 { 112 log.Error("Ticket Insufficient quantity") 113 return 0, TicketPoolNilErr 114 } 115 if surplusQuantity < voteNumber { 116 voteNumber = surplusQuantity 117 } 118 log.Debug("Start circular voting", "nodeId", nodeId.String(), "voteNumber", voteNumber) 119 120 ticketId := stateDB.TxHash() 121 //ticket := &types.Ticket{ 122 // owner, 123 // deposit, 124 // nodeId, 125 // blockNumber, 126 // voteNumber, 127 //} 128 //t.recordExpireTicket(stateDB, blockNumber, ticketId) 129 //log.Debug("Record the success of the ticket to expire, and start reducing the number of tickets", "blockNumber", blockNumber.Uint64(), "surplusQuantity", surplusQuantity, "ticketId", ticketId.Hex()) 130 t.setPoolNumber(stateDB, surplusQuantity-voteNumber) 131 stateDB.GetPPOSCache().AppendTicket(nodeId, ticketId, voteNumber, deposit) 132 log.Debug("Voting SUCCUESS !!!!!! Reduce the remaining amount of the ticket pool successfully", "surplusQuantity", t.GetPoolNumber(stateDB), "nodeId", nodeId.String(), "blockNumber", blockNumber.Uint64(), "ticketId", ticketId.Hex()) 133 return voteNumber, nil 134 } 135 136 func (t *TicketPool) calcExpireBlockNumber(stateDB vm.StateDB, blockNumber *big.Int) (*big.Int, bool) { 137 num := new(big.Int).SetUint64(0) 138 if blockNumber.Cmp(new(big.Int).SetUint64(uint64(t.ExpireBlockNumber))) >= 0 { 139 num.Sub(blockNumber, new(big.Int).SetUint64(uint64(t.ExpireBlockNumber))) 140 return num, true 141 } 142 return num, false 143 } 144 145 /*func (t *TicketPool) GetExpireTicketIds(stateDB vm.StateDB, blockNumber *big.Int) []common.Hash { 146 log.Debug("Call GetExpireTicketIds", "statedb addr", fmt.Sprintf("%p", stateDB)) 147 return stateDB.GetPPOSCache().GetExpireTicket(blockNumber) 148 }*/ 149 150 func (t *TicketPool) GetExpireTicketIds(stateDB vm.StateDB, blockNumber *big.Int) []common.Hash { 151 log.Debug("Call GetExpireTicketIds", "statedb addr", fmt.Sprintf("%p", stateDB)) 152 start := common.NewTimer() 153 start.Begin() 154 body := tContext.GetBody(blockNumber.Uint64()) 155 txs := make([]common.Hash, 0) 156 for _, tx := range body.Transactions { 157 if tx.To() != nil && *tx.To() == common.TicketPoolAddr { 158 txs = append(txs, tx.Hash()) 159 } 160 } 161 log.Debug("GetExpireTicketIds Time", "Time spent", fmt.Sprintf("%v ms", start.End())) 162 return txs 163 } 164 165 // In the current block, 166 // the ticket id is placed in the value slice with the block height as the key to find the expired ticket. 167 func (t *TicketPool) recordExpireTicket(stateDB vm.StateDB, blockNumber *big.Int, ticketId common.Hash) { 168 //stateDB.GetPPOSCache().SetExpireTicket(blockNumber, ticketId) 169 } 170 171 func (t *TicketPool) removeExpireTicket(stateDB vm.StateDB, blockNumber *big.Int, ticketId common.Hash) { 172 //stateDB.GetPPOSCache().RemoveExpireTicket(blockNumber, ticketId) 173 } 174 175 func (t *TicketPool) handleExpireTicket(stateDB vm.StateDB, expireBlockNumber *big.Int, currentBlockNumber *big.Int) ([]discover.NodeID, error) { 176 t.lock.Lock() 177 defer t.lock.Unlock() 178 ticketIdList := t.GetExpireTicketIds(stateDB, expireBlockNumber) 179 if len(ticketIdList) == 0 { 180 return nil, nil 181 } 182 log.Info("Pending ticket to be processed", "amount", len(ticketIdList), "expireBlockNumber", expireBlockNumber.Uint64(), "currentBlockNumber", currentBlockNumber.Uint64()) 183 candidateAttachMap := make(map[discover.NodeID]bool) 184 changeNodeIdList := make([]discover.NodeID, 0) 185 for _, ticketId := range ticketIdList { 186 ticket := t.GetTicket(stateDB, ticketId) 187 if ticket == nil { 188 continue 189 } 190 _, ok := candidateAttachMap[ticket.CandidateId] 191 if !ok { 192 candidateAttachMap[ticket.CandidateId] = true 193 changeNodeIdList = append(changeNodeIdList, ticket.CandidateId) 194 } 195 if _, err := t.releaseTxTicket(stateDB, ticket.CandidateId, ticketId, currentBlockNumber); nil != err { 196 return changeNodeIdList, err 197 } 198 } 199 return changeNodeIdList, nil 200 } 201 202 // Get ticket list 203 func (t *TicketPool) GetTicketList(stateDB vm.StateDB, ticketIds []common.Hash) []*types.Ticket { 204 log.Debug("Call GetTickList", "statedb addr", fmt.Sprintf("%p", stateDB)) 205 var tickets []*types.Ticket 206 for _, ticketId := range ticketIds { 207 ticket := t.GetTicket(stateDB, ticketId) 208 if ticket == nil { 209 log.Error("find this ticket fail", "ticketId", ticketId.Hex()) 210 continue 211 } 212 tickets = append(tickets, ticket) 213 } 214 return tickets 215 } 216 217 // Get ticket details based on TicketId 218 func (t *TicketPool) GetTicket(stateDB vm.StateDB, txHash common.Hash) *types.Ticket { 219 log.Debug("Call GetTicket", "statedb addr", fmt.Sprintf("%p", stateDB)) 220 221 start := common.NewTimer() 222 start.Begin() 223 224 if value := ppos_storage.GetTicket(txHash); nil != value { 225 return value 226 } 227 228 startTx := common.NewTimer() 229 startTx.Begin() 230 tx, _, blockNumber,_ := tContext.FindTransaction(txHash) 231 log.Debug("GetTicket Time Tx", "txHash", tx.Hash(), "Time spent", fmt.Sprintf("%v ms", startTx.End())) 232 if nil != tx && len(tx.Data()) > 0 { 233 startDecode := common.NewTimer() 234 startDecode.Begin() 235 var source [][]byte 236 if err := rlp.Decode(bytes.NewReader(tx.Data()), &source); nil != err { 237 log.Error("Failed to GetTicket", "txHash", txHash.Hex(), "err", err.Error()) 238 return nil 239 } 240 if len(source) !=5 || len(source[1]) == 0 || len(source[4]) == 0 || byteutil.BytesToString(source[1]) != "VoteTicket" { 241 return nil 242 } 243 log.Debug("GetTicket Time Decode", "Time spent", fmt.Sprintf("%v ms", startDecode.End())) 244 ticket := new(types.Ticket) 245 startSigner := common.NewTimer() 246 startSigner.Begin() 247 signer := types.NewEIP155Signer(tContext.chainConfig.ChainID) 248 if addr, err := signer.Sender(tx); nil != err { 249 log.Error("Failed to GetTicket, get tx owner is empty !!!!", "tx", tx.Hash().Hex(), "err", err) 250 return nil 251 } else { 252 ticket.Owner = addr 253 } 254 log.Debug("GetTicket Time startSigner", "Time spent", fmt.Sprintf("%v ms", startSigner.End())) 255 //startGetHeader := common.NewTimer() 256 //startGetHeader.Begin() 257 //block := tContext.GetHeader(blockHash, blockNumber) 258 //log.Debug("GetTicket Time startGetHeader", "Time spent", fmt.Sprintf("%v ms", startGetHeader.End())) 259 //startGetNewStateDB := common.NewTimer() 260 //startGetNewStateDB.Begin() 261 //if oldState, err := tContext.GetNewStateDB(block.Root, new(big.Int).SetUint64(blockNumber), blockHash); nil != err { 262 // return nil 263 //} else { 264 // ticket.Deposit = t.GetTicketPrice(oldState) 265 //} 266 //log.Debug("GetTicket Time startGetNewStateDB", "Time spent", fmt.Sprintf("%v ms", startGetNewStateDB.End())) 267 ticket.Deposit = t.GetTicketPrice(stateDB) 268 if (discover.NodeID{}) == byteutil.BytesToNodeId(source[4]) { 269 log.Error("Parse candidate ID error from Tx", "txHash", tx.Hash()) 270 return nil 271 } 272 ticket.CandidateId = byteutil.BytesToNodeId(source[4]) 273 ticket.BlockNumber = new(big.Int).SetUint64(blockNumber) 274 log.Debug("GetTicket Time", "Time spent", fmt.Sprintf("%v ms", start.End())) 275 return ticket 276 }else { 277 log.Error("Failed to GetTicket, the tx is empty", "txHash", txHash.Hex()) 278 } 279 return nil 280 } 281 282 func (t *TicketPool) GetTicketRemainByTxHash (stateDB vm.StateDB, txHash common.Hash) uint32 { 283 return stateDB.GetPPOSCache().GetTicketRemainByTxHash(txHash) 284 } 285 286 //func (t *TicketPool) setTicket(stateDB vm.StateDB, ticketId common.Hash, ticket *types.Ticket) { 287 // stateDB.GetPPOSCache().SetTicketInfo(ticketId, ticket) 288 //} 289 290 func (t *TicketPool) DropReturnTicket(stateDB vm.StateDB, blockNumber *big.Int, nodeIds ...discover.NodeID) error { 291 t.lock.Lock() 292 defer t.lock.Unlock() 293 log.Debug("Call DropReturnTicket", "statedb addr", fmt.Sprintf("%p", stateDB)) 294 log.Info("Start processing tickets for the drop list on DropReturnTicket", "candidateNum", len(nodeIds), "blockNumber", blockNumber.Uint64()) 295 for _, nodeId := range nodeIds { 296 if nodeId == (discover.NodeID{}) { 297 continue 298 } 299 candidateTicketIds := t.GetCandidateTicketIds(stateDB, nodeId) 300 if len(candidateTicketIds) == 0 { 301 continue 302 } 303 //epoch := t.GetCandidateEpoch(stateDB, nodeId) 304 ticketCount := t.GetCandidateTicketCount(stateDB, nodeId) 305 surplusQuantity := t.GetPoolNumber(stateDB) 306 log.Debug("Start reducing the number of tickets on DropReturnTicket", "surplusQuantity", surplusQuantity, "candidateTicketIds", ticketCount) 307 t.setPoolNumber(stateDB, surplusQuantity+ticketCount) 308 log.Debug("Start processing each invalid ticket on DropReturnTicket", "nodeId", nodeId.String(), "ticketSize", ticketCount) 309 for _, ticketId := range candidateTicketIds { 310 ticket := t.GetTicket(stateDB, ticketId) 311 if ticket == nil { 312 continue 313 } 314 if tinfo, err := stateDB.GetPPOSCache().RemoveTicket(nodeId, ticketId); err != nil { 315 return err 316 } else { 317 ticket.Remaining = tinfo.Remaining 318 ticket.Deposit = tinfo.Price 319 } 320 log.Debug("Start transfer on DropReturnTicket", "nodeId", nodeId.String(), "ticketId", ticketId.Hex(), "deposit", ticket.Deposit, "remaining", ticket.Remaining) 321 if err := transfer(stateDB, common.TicketPoolAddr, ticket.Owner, ticket.TotalDeposit()); nil != err { 322 return err 323 } 324 //t.removeExpireTicket(stateDB, ticket.BlockNumber, ticketId) 325 } 326 log.Debug("Delete candidate ticket collection on DropReturnTicket", "nodeId", nodeId.String(), "ticketSize", ticketCount) 327 stateDB.GetPPOSCache().RemoveTicketDependency(nodeId) 328 } 329 log.Debug("End processing the list on DropReturnTicket") 330 return nil 331 } 332 333 func (t *TicketPool) ReturnTicket(stateDB vm.StateDB, nodeId discover.NodeID, ticketId common.Hash, blockNumber *big.Int) error { 334 log.Debug("Call ReturnTicket", "statedb addr", fmt.Sprintf("%p", stateDB)) 335 log.Info("Release the selected ticket on ReturnTicket", "nodeId", nodeId.String(), "ticketId", ticketId.Hex(), "blockNumber", blockNumber.Uint64()) 336 t.lock.Lock() 337 defer t.lock.Unlock() 338 if ticketId == (common.Hash{}) { 339 return TicketNotFindErr 340 } 341 if nodeId == (discover.NodeID{}) { 342 return CandidateNotFindErr 343 } 344 _, err := t.releaseTicket(stateDB, nodeId, ticketId, blockNumber) 345 if nil != err { 346 return err 347 } 348 return nil 349 } 350 351 func (t *TicketPool) releaseTicket(stateDB vm.StateDB, candidateId discover.NodeID, ticketId common.Hash, blockNumber *big.Int) (*types.Ticket, error) { 352 log.Debug("Start executing releaseTicket", "nodeId", candidateId.String(), "ticketId", ticketId.Hex(), "blockNumber", blockNumber.Uint64()) 353 ticket := t.GetTicket(stateDB, ticketId) 354 if ticket == nil { 355 return nil, TicketNotFindErr 356 } 357 log.Debug("releaseTicket,Start Update", "nodeId", candidateId.String(), "ticketId", ticketId.Hex()) 358 if tinfo, err := stateDB.GetPPOSCache().SubTicket(candidateId, ticketId); err != nil { 359 return ticket, err 360 } else { 361 ticket.Remaining = tinfo.Remaining 362 ticket.Deposit = tinfo.Price 363 } 364 /*if ticket.Remaining == 0 { 365 // Remove from pending expire tickets 366 log.Debug("releaseTicket, Ticket has been used, deleted from waiting for expiration", "ticketId", ticketId.Hex(), "candidateId", candidateId.String(), "blockNumber", blockNumber.Uint64()) 367 t.removeExpireTicket(stateDB, ticket.BlockNumber, ticketId) 368 }*/ 369 log.Debug("releaseTicket, end update", "nodeId", candidateId.String()) 370 surplusQuantity := t.GetPoolNumber(stateDB) 371 log.Debug("releaseTicket, start to update the ticket pool", "surplusQuantity", surplusQuantity) 372 if err := t.addPoolNumber(stateDB); err != nil { 373 return ticket, err 374 } 375 surplusQuantity = t.GetPoolNumber(stateDB) 376 log.Debug("releaseTicket, end the update ticket pool", "surplusQuantity", surplusQuantity) 377 //epoch := t.GetCandidateEpoch(stateDB, candidateId) 378 //log.Debug("releaseTicket, start updating the total epoch of candidates", "nodeId", candidateId.String(), "totalEpoch", epoch, "blockNumber", blockNumber.Uint64(), "ticketBlockNumber", ticket.BlockNumber.Uint64()) 379 //if err := t.subCandidateEpoch(stateDB, candidateId, ticket.CalcEpoch(blockNumber)); nil != err { 380 // return ticket, err 381 //} 382 //epoch = t.GetCandidateEpoch(stateDB, candidateId) 383 //log.Debug("releaseTicket, the end of the update candidate total epoch", "nodeId", candidateId.String(), "totalEpoch", epoch, "blockNumber", blockNumber.Uint64(), "ticketBlockNumber", ticket.BlockNumber.Uint64()) 384 return ticket, transfer(stateDB, common.TicketPoolAddr, ticket.Owner, ticket.Deposit) 385 } 386 387 func (t *TicketPool) releaseTxTicket(stateDB vm.StateDB, candidateId discover.NodeID, ticketId common.Hash, blockNumber *big.Int) (*types.Ticket, error) { 388 log.Debug("Start executing releaseTxTicket", "nodeId", candidateId.String(), "ticketId", ticketId.Hex(), "blockNumber", blockNumber.Uint64()) 389 ticket := t.GetTicket(stateDB, ticketId) 390 if ticket == nil { 391 return nil, TicketNotFindErr 392 } 393 log.Debug("releaseTxTicket,Start Update", "nodeId", candidateId.String(), "ticketId", ticketId.Hex()) 394 if tinfo, err := stateDB.GetPPOSCache().RemoveTicket(candidateId, ticketId); err != nil && err != ppos_storage.TicketNotFindErr { 395 return ticket, err 396 } else { 397 if tinfo == nil { 398 log.Warn("releaseTxTicket, Not find TicketId", "ticketId", ticketId.Hex(), "nodeId", candidateId.String(), "blockNumber", blockNumber.Uint64()) 399 return nil, nil 400 } 401 ticket.Remaining = tinfo.Remaining 402 ticket.Deposit = tinfo.Price 403 } 404 log.Debug("releaseTxTicket, end update", "nodeId", candidateId.String()) 405 //t.removeExpireTicket(stateDB, ticket.BlockNumber, ticketId) 406 surplusQuantity := t.GetPoolNumber(stateDB) 407 log.Debug("releaseTxTicket, start to update the ticket pool", "surplusQuantity", surplusQuantity) 408 t.setPoolNumber(stateDB, surplusQuantity + ticket.Remaining) 409 surplusQuantity = t.GetPoolNumber(stateDB) 410 log.Debug("releaseTxTicket, end the update ticket pool", "surplusQuantity", surplusQuantity) 411 //epoch := t.GetCandidateEpoch(stateDB, candidateId) 412 //log.Debug("releaseTicket, start updating the total epoch of candidates", "nodeId", candidateId.String(), "totalEpoch", epoch, "blockNumber", blockNumber.Uint64(), "ticketBlockNumber", ticket.BlockNumber.Uint64()) 413 //if err := t.subCandidateEpoch(stateDB, candidateId, ticket.TotalEpoch(blockNumber)); nil != err { 414 // return ticket, err 415 //} 416 //epoch = t.GetCandidateEpoch(stateDB, candidateId) 417 //log.Debug("releaseTicket, the end of the update candidate total epoch", "nodeId", candidateId.String(), "totalEpoch", epoch, "blockNumber", blockNumber.Uint64(), "ticketBlockNumber", ticket.BlockNumber.Uint64()) 418 return ticket, transfer(stateDB, common.TicketPoolAddr, ticket.Owner, ticket.TotalDeposit()) 419 } 420 421 func (t *TicketPool) Notify(stateDB vm.StateDB, blockNumber *big.Int) error { 422 log.Debug("Call Notify", "statedb addr", fmt.Sprintf("%p", stateDB)) 423 // Check expired tickets 424 425 //ticket := t.GetTicket(stateDB, common.HexToHash("0xafdd2a272c9af265410369bba200960229e6c90e044d8241cbcd6abf8a1706f8")) 426 427 428 expireBlockNumber, ok := t.calcExpireBlockNumber(stateDB, blockNumber) 429 log.Debug("Check expired tickets on Notify", "isOk", ok, "expireBlockNumber", expireBlockNumber.Uint64()) 430 if ok { 431 if nodeIdList, err := t.handleExpireTicket(stateDB, expireBlockNumber, blockNumber); nil != err { 432 log.Error("OutBlockNotice method handleExpireTicket error", "blockNumber", blockNumber.Uint64(), "err", err) 433 return HandleExpireTicketErr 434 } else { 435 // Notify the candidate to update the list information after processing the expired ticket 436 log.Debug("After processing the expired ticket, start updating the candidate list on Notify", "blockNumber", blockNumber.Uint64(), "nodeIdList", len(nodeIdList)) 437 if len(nodeIdList) > 0 { 438 if err := cContext.UpdateElectedQueue(stateDB, blockNumber, nodeIdList...); nil != err { 439 log.Error("Failed to Update candidate when handleExpireTicket success on Notify", "err", err) 440 } 441 } 442 } 443 } 444 // Increase the total number of epoch for each candidate 445 /*log.Debug("Increase the total number of epoch for each candidate on Notify", "blockNumber", blockNumber.Uint64()) 446 if err := t.calcCandidateEpoch(stateDB, blockNumber); nil != err { 447 return err 448 }*/ 449 return nil 450 } 451 452 /*func (t *TicketPool) calcCandidateEpoch(stateDB vm.StateDB, blockNumber *big.Int) error { 453 t.lock.Lock() 454 defer t.lock.Unlock() 455 candidateList := cContext.GetCandidatePendArr(stateDB, 0) 456 for _, candidate := range candidateList { 457 epoch := t.GetCandidateEpoch(stateDB, candidate.CandidateId) 458 // Get the total number of votes, increase the total epoch 459 ticketCount := stateDB.GetPPOSCache().GetCandidateTicketCount(candidate.CandidateId) 460 log.Debug("increase the total epoch", "candidateId", candidate.CandidateId.String(), "blockNumber", blockNumber.Uint64(), "ticketCount", ticketCount, "epoch", epoch) 461 if ticketCount > 0 { 462 t.addCandidateEpoch(stateDB, candidate.CandidateId, uint64(ticketCount)) 463 epoch = t.GetCandidateEpoch(stateDB, candidate.CandidateId) 464 log.Debug("increase the total epoch success", "candidateId", candidate.CandidateId.String(), "blockNumber", blockNumber.Uint64(), "ticketCount", ticketCount, "epoch", epoch) 465 } 466 } 467 return nil 468 }*/ 469 470 // Simple version of the lucky ticket algorithm 471 // According to the previous block Hash, 472 // find the first ticket Id which is larger than the Hash. If not found, the last ticket Id is taken. 473 func (t *TicketPool) SelectionLuckyTicket(stateDB vm.StateDB, nodeId discover.NodeID, blockHash common.Hash) (common.Hash, error) { 474 log.Debug("Call SelectionLuckyTicket", "statedb addr", fmt.Sprintf("%p", stateDB)) 475 candidateTicketIds := t.GetCandidateTicketIds(stateDB, nodeId) 476 log.Debug("Start picking lucky tickets on SelectionLuckyTicket", "nodeId", nodeId.String(), "blockHash", blockHash.Hex(), "candidateTicketIds", len(candidateTicketIds)) 477 luckyTicketId := common.Hash{} 478 if len(candidateTicketIds) == 0 { 479 return luckyTicketId, nil 480 } 481 if len(candidateTicketIds) == 1 { 482 return candidateTicketIds[0], nil 483 } 484 decList := make([]float64, 0) 485 decMap := make(map[float64]common.Hash, 0) 486 for _, ticketId := range candidateTicketIds { 487 decNumber := hexutil.HexDec(ticketId.Hex()[2:]) 488 decList = append(decList, decNumber) 489 decMap[decNumber] = ticketId 490 } 491 sort.Float64s(decList) 492 index := findFirstMatch(decList, hexutil.HexDec(blockHash.Hex()[2:])) 493 log.Debug("Pick out a lucky ticket on SelectionLuckyTicket", "index", index) 494 luckyTicketId = decMap[decList[index]] 495 log.Debug("End the selection of lucky tickets on SelectionLuckyTicket", "nodeId", nodeId.String(), "blockHash", blockHash.Hex(), "luckyTicketId", luckyTicketId.Hex(), "candidateTicketIds", len(candidateTicketIds)) 496 return luckyTicketId, nil 497 } 498 499 func (t *TicketPool) addPoolNumber(stateDB vm.StateDB) error { 500 surplusQuantity := t.GetPoolNumber(stateDB) 501 if surplusQuantity == t.MaxCount { 502 return TicketPoolOverflowErr 503 } 504 surplusQuantity++ 505 t.setPoolNumber(stateDB, surplusQuantity) 506 return nil 507 } 508 509 func (t *TicketPool) subPoolNumber(stateDB vm.StateDB) error { 510 surplusQuantity := t.GetPoolNumber(stateDB) 511 if surplusQuantity == 0 { 512 return TicketPoolNilErr 513 } 514 surplusQuantity-- 515 t.setPoolNumber(stateDB, surplusQuantity) 516 return nil 517 } 518 519 func (t *TicketPool) setPoolNumber(stateDB vm.StateDB, surplusQuantity uint32) { 520 stateDB.GetPPOSCache().SetTotalRemain(int32(surplusQuantity)) 521 } 522 523 func (t *TicketPool) GetPoolNumber(stateDB vm.StateDB) uint32 { 524 if val := stateDB.GetPPOSCache().GetTotalRemian(); val >= 0 { 525 return uint32(val) 526 } else { 527 // Default initialization values 528 return t.MaxCount 529 } 530 } 531 532 /*func (t *TicketPool) subCandidateEpoch(stateDB vm.StateDB, nodeId discover.NodeID, epoch uint64) error { 533 dependency := stateDB.GetPPOSCache().GetTicketDependency(nodeId) 534 if nil == dependency { 535 return CandidateNotFindErr 536 } 537 dependency.SubAge(epoch) 538 return nil 539 }*/ 540 541 /*func (t *TicketPool) addCandidateEpoch(stateDB vm.StateDB, nodeId discover.NodeID, epoch uint64) error { 542 dependency := stateDB.GetPPOSCache().GetTicketDependency(nodeId) 543 if nil == dependency { 544 return CandidateNotFindErr 545 } 546 dependency.AddAge(epoch) 547 return nil 548 }*/ 549 550 // Get the remaining number of ticket 551 func (t *TicketPool) GetTicketRemaining(stateDB vm.StateDB, ticketId common.Hash) uint32 { 552 return t.GetTicketRemainByTxHash(stateDB, ticketId) 553 /*if nil == ticket { 554 return 0 555 } 556 return ticket.Remaining*/ 557 } 558 559 // Get the batch remaining number of ticket 560 func (t *TicketPool) GetBatchTicketRemaining(stateDB vm.StateDB, ticketIds []common.Hash) map[common.Hash]uint32 { 561 ticketsRemaining := make(map[common.Hash]uint32, len(ticketIds)) 562 var wg sync.WaitGroup 563 wg.Add(len(ticketIds)) 564 565 type result struct { 566 id common.Hash 567 count uint32 568 } 569 resCh := make(chan *result, len(ticketIds)) 570 571 for _, ticketId := range ticketIds { 572 /*remaining := t.GetTicketRemaining(stateDB, ticketId) 573 ticketsRemaining[ticketId] = remaining*/ 574 go func(txHash common.Hash) { 575 res := new(result) 576 res.id = txHash 577 res.count = t.GetTicketRemaining(stateDB, txHash) 578 resCh <- res 579 wg.Done() 580 }(ticketId) 581 } 582 wg.Wait() 583 close(resCh) 584 for res := range resCh { 585 ticketsRemaining[res.id] = res.count 586 } 587 return ticketsRemaining 588 } 589 590 func (t *TicketPool) GetCandidateTicketIds(stateDB vm.StateDB, nodeId discover.NodeID) []common.Hash { 591 log.Debug("Call GetCandidaieTicketIds", "statedb addr", fmt.Sprintf("%p", stateDB)) 592 return stateDB.GetPPOSCache().GetCandidateTxHashs(nodeId) 593 } 594 595 func (t *TicketPool) GetCandidatesTicketIds(stateDB vm.StateDB, nodeIds []discover.NodeID) map[discover.NodeID][]common.Hash { 596 log.Debug("Call GetCandidateArrTicketIds", "statedb addr", fmt.Sprintf("%p", stateDB)) 597 result := make(map[discover.NodeID][]common.Hash) 598 if nodeIds != nil { 599 for _, nodeId := range nodeIds { 600 ticketIds := t.GetCandidateTicketIds(stateDB, nodeId) 601 if nil == ticketIds { 602 continue 603 } 604 result[nodeId] = ticketIds 605 } 606 } 607 return result 608 } 609 610 func (t *TicketPool) GetCandidateTicketCount(stateDB vm.StateDB, nodeId discover.NodeID) uint32 { 611 return stateDB.GetPPOSCache().GetCandidateTicketCount(nodeId) 612 } 613 614 func (t *TicketPool) GetCandidatesTicketCount(stateDB vm.StateDB, nodeIds []discover.NodeID) map[discover.NodeID]uint32 { 615 log.Debug("Call GetCandidatesTicketCount", "statedb addr", fmt.Sprintf("%p", stateDB)) 616 result := make(map[discover.NodeID]uint32) 617 if nil != nodeIds { 618 for _, nodeId := range nodeIds { 619 result[nodeId] = stateDB.GetPPOSCache().GetCandidateTicketCount(nodeId) 620 } 621 } 622 return result 623 } 624 625 func (t *TicketPool) setCandidateEpoch(stateDB vm.StateDB, nodeId discover.NodeID, age uint64) { 626 stateDB.GetPPOSCache().SetCandidateTicketAge(nodeId, age) 627 } 628 629 func (t *TicketPool) GetCandidateEpoch(stateDB vm.StateDB, nodeId discover.NodeID) uint64 { 630 log.Debug("Call GetCandidateEpoch", "statedb addr", fmt.Sprintf("%p", stateDB)) 631 return stateDB.GetPPOSCache().GetCandidateTicketAge(nodeId) 632 } 633 634 func (t *TicketPool) GetTicketPrice(stateDB vm.StateDB) *big.Int { 635 return t.TicketPrice 636 } 637 638 // Save the hash value of the current state of the ticket pool 639 func (t *TicketPool) CommitHash(stateDB vm.StateDB, blockNumber *big.Int, blockHash common.Hash) error { 640 //hash := common.Hash{} 641 if hash, err := stateDB.GetPPOSCache().CalculateHash(blockNumber, blockHash); nil != err { 642 return err 643 }else { 644 setTicketPoolState(stateDB, addCommonPrefix(TicketPoolHashKey), hash.Bytes()) 645 return nil 646 } 647 } 648 649 //func GetTicketPtr() *TicketPool { 650 // return ticketPool 651 //} 652 653 func checkBalance(stateDB vm.StateDB, addr common.Address, amount *big.Int) bool { 654 if stateDB.GetBalance(addr).Cmp(amount) >= 0 { 655 return true 656 } 657 return false 658 } 659 660 func transfer(stateDB vm.StateDB, from common.Address, to common.Address, amount *big.Int) error { 661 if !checkBalance(stateDB, from, amount) { 662 log.Error("TicketPool not sufficient funds", "from", from.Hex(), "to", to.Hex(), "money", amount.Uint64()) 663 return TicketPoolBalanceErr 664 } 665 stateDB.SubBalance(from, amount) 666 stateDB.AddBalance(to, amount) 667 return nil 668 } 669 670 func getTicketPoolState(stateDB vm.StateDB, key []byte, result interface{}) error { 671 return getState(common.TicketPoolAddr, stateDB, key, result) 672 } 673 674 func getState(addr common.Address, stateDB vm.StateDB, key []byte, result interface{}) error { 675 if val := stateDB.GetState(addr, key); len(val) > 0 { 676 if err := rlp.DecodeBytes(val, result); nil != err { 677 log.Error("Decode Data error", "key", string(key), "err", err) 678 return err 679 } 680 } 681 return nil 682 } 683 684 func setTicketPoolState(stateDB vm.StateDB, key []byte, val []byte) { 685 stateDB.SetState(common.TicketPoolAddr, key, val) 686 } 687 688 func addCommonPrefix(key []byte) []byte { 689 return append(common.TicketPoolAddr.Bytes(), key...) 690 } 691 692 func findFirstMatch(list []float64, key float64) int { 693 left := 0 694 right := len(list) - 1 695 for left <= right { 696 mid := (left + right) / 2 697 if list[mid] >= key { 698 right = mid - 1 699 } else { 700 left = mid + 1 701 } 702 } 703 // If no match is found, the last subscript is returned by default. 704 if left >= len(list) { 705 return len(list) - 1 706 } 707 return left 708 }