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 }