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  }