github.com/iotexproject/iotex-core@v1.14.1-rc1/actpool/actioniterator/actioniterator.go (about)

     1  // Copyright (c) 2019 IoTeX Foundation
     2  // This source code is provided 'as is' and no warranties are given as to title or non-infringement, merchantability
     3  // or fitness for purpose and, to the extent permitted by law, all liability for your use of the code is disclaimed.
     4  // This source code is governed by Apache License 2.0 that can be found in the LICENSE file.
     5  
     6  package actioniterator
     7  
     8  import (
     9  	"bytes"
    10  	"container/heap"
    11  
    12  	"github.com/iotexproject/iotex-core/action"
    13  )
    14  
    15  // ActionByPrice implements both the sort and the heap interface, making it useful
    16  // for all at once sorting as well as individually adding and removing elements.
    17  // It's essentially a big root heap of actions
    18  type actionByPrice []*action.SealedEnvelope
    19  
    20  func (s actionByPrice) Len() int { return len(s) }
    21  func (s actionByPrice) Less(i, j int) bool {
    22  	switch s[i].GasPrice().Cmp(s[j].GasPrice()) {
    23  	case 1:
    24  		return true
    25  	case 0:
    26  		hi, _ := s[i].Hash()
    27  		hj, _ := s[j].Hash()
    28  		return bytes.Compare(hi[:], hj[:]) > 0
    29  	default:
    30  		return false
    31  	}
    32  }
    33  
    34  func (s actionByPrice) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
    35  
    36  // Push define the push function of heap
    37  func (s *actionByPrice) Push(x interface{}) {
    38  	*s = append(*s, x.(*action.SealedEnvelope))
    39  }
    40  
    41  // Pop define the pop function of heap
    42  func (s *actionByPrice) Pop() interface{} {
    43  	old := *s
    44  	n := len(old)
    45  	x := old[n-1]
    46  	*s = old[0 : n-1]
    47  	return x
    48  }
    49  
    50  // ActionIterator define the interface of action iterator
    51  type ActionIterator interface {
    52  	Next() (*action.SealedEnvelope, bool)
    53  	PopAccount()
    54  }
    55  
    56  type actionIterator struct {
    57  	accountActs map[string][]*action.SealedEnvelope
    58  	heads       actionByPrice
    59  }
    60  
    61  // NewActionIterator return a new action iterator
    62  func NewActionIterator(accountActs map[string][]*action.SealedEnvelope) ActionIterator {
    63  	heads := make(actionByPrice, 0, len(accountActs))
    64  	for sender, accActs := range accountActs {
    65  		if len(accActs) == 0 {
    66  			continue
    67  		}
    68  
    69  		heads = append(heads, accActs[0])
    70  		if len(accActs) > 1 {
    71  			accountActs[sender] = accActs[1:]
    72  		} else {
    73  			accountActs[sender] = []*action.SealedEnvelope{}
    74  		}
    75  	}
    76  	heap.Init(&heads)
    77  	return &actionIterator{
    78  		accountActs: accountActs,
    79  		heads:       heads,
    80  	}
    81  }
    82  
    83  // LoadNext load next action of account of top action
    84  func (ai *actionIterator) loadNextActionForTopAccount() {
    85  	callerAddrStr := ai.heads[0].SenderAddress().String()
    86  	if actions, ok := ai.accountActs[callerAddrStr]; ok && len(actions) > 0 {
    87  		ai.heads[0], ai.accountActs[callerAddrStr] = actions[0], actions[1:]
    88  		heap.Fix(&ai.heads, 0)
    89  	} else {
    90  		heap.Pop(&ai.heads)
    91  	}
    92  }
    93  
    94  // Next load next action of account of top action
    95  func (ai *actionIterator) Next() (*action.SealedEnvelope, bool) {
    96  	if len(ai.heads) == 0 {
    97  		return nil, false
    98  	}
    99  
   100  	headAction := ai.heads[0]
   101  	ai.loadNextActionForTopAccount()
   102  	return headAction, true
   103  }
   104  
   105  // PopAccount will remove all actions related to this account
   106  func (ai *actionIterator) PopAccount() {
   107  	if len(ai.heads) != 0 {
   108  		heap.Pop(&ai.heads)
   109  	}
   110  }