github.com/iotexproject/iotex-core@v1.14.1-rc1/actpool/accountpool.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 actpool 7 8 import ( 9 "container/heap" 10 "math/big" 11 "time" 12 13 "github.com/iotexproject/iotex-core/action" 14 ) 15 16 type ( 17 accountItem struct { 18 index int 19 actQueue ActQueue 20 } 21 22 accountPriorityQueue []*accountItem 23 24 accountPool struct { 25 accounts map[string]*accountItem 26 priorityQueue accountPriorityQueue 27 } 28 ) 29 30 func newAccountPool() *accountPool { 31 ap := &accountPool{ 32 priorityQueue: accountPriorityQueue{}, 33 accounts: map[string]*accountItem{}, 34 } 35 heap.Init(&ap.priorityQueue) 36 37 return ap 38 } 39 40 func (ap *accountPool) Account(addr string) ActQueue { 41 if account, ok := ap.accounts[addr]; ok { 42 return account.actQueue 43 } 44 return nil 45 } 46 47 func (ap *accountPool) PopAccount(addr string) ActQueue { 48 if account, ok := ap.accounts[addr]; ok { 49 heap.Remove(&ap.priorityQueue, account.index) 50 delete(ap.accounts, addr) 51 return account.actQueue 52 } 53 54 return nil 55 } 56 57 func (ap *accountPool) PutAction( 58 addr string, 59 actpool *actPool, 60 pendingNonce uint64, 61 confirmedBalance *big.Int, 62 expiry time.Duration, 63 act *action.SealedEnvelope, 64 ) error { 65 account, ok := ap.accounts[addr] 66 if !ok { 67 queue := NewActQueue( 68 actpool, 69 addr, 70 pendingNonce, 71 confirmedBalance, 72 WithTimeOut(expiry), 73 ) 74 if err := queue.Put(act); err != nil { 75 return err 76 } 77 ap.accounts[addr] = &accountItem{ 78 index: len(ap.accounts), 79 actQueue: queue, 80 } 81 heap.Push(&ap.priorityQueue, ap.accounts[addr]) 82 return nil 83 } 84 85 if err := account.actQueue.Put(act); err != nil { 86 return err 87 } 88 heap.Fix(&ap.priorityQueue, account.index) 89 90 return nil 91 } 92 93 func (ap *accountPool) PopPeek() *action.SealedEnvelope { 94 if len(ap.accounts) == 0 { 95 return nil 96 } 97 act := ap.priorityQueue[0].actQueue.PopActionWithLargestNonce() 98 heap.Fix(&ap.priorityQueue, 0) 99 100 return act 101 } 102 103 func (ap *accountPool) Range(callback func(addr string, acct ActQueue)) { 104 for addr, account := range ap.accounts { 105 callback(addr, account.actQueue) 106 } 107 heap.Init(&ap.priorityQueue) 108 } 109 110 func (ap *accountPool) DeleteIfEmpty(addr string) { 111 account, ok := ap.accounts[addr] 112 if !ok { 113 return 114 } 115 if account.actQueue.Empty() { 116 heap.Remove(&ap.priorityQueue, account.index) 117 delete(ap.accounts, addr) 118 } 119 } 120 121 func (aq accountPriorityQueue) Len() int { return len(aq) } 122 func (aq accountPriorityQueue) Less(i, j int) bool { 123 is, igp := aq[i].actQueue.NextAction() 124 js, jgp := aq[j].actQueue.NextAction() 125 if jgp == nil { 126 return true 127 } 128 if igp == nil { 129 return false 130 } 131 if !is && js { 132 return true 133 } 134 if !js && is { 135 return false 136 } 137 138 return igp.Cmp(jgp) < 0 139 } 140 141 func (aq accountPriorityQueue) Swap(i, j int) { 142 aq[i], aq[j] = aq[j], aq[i] 143 aq[i].index = i 144 aq[j].index = j 145 } 146 147 func (aq *accountPriorityQueue) Push(x interface{}) { 148 if in, ok := x.(*accountItem); ok { 149 in.index = len(*aq) 150 *aq = append(*aq, in) 151 } 152 } 153 154 func (aq *accountPriorityQueue) Pop() interface{} { 155 old := *aq 156 n := len(old) 157 if n == 0 { 158 return nil 159 } 160 x := old[n-1] 161 old[n-1] = nil // avoid memory leak 162 *aq = old[0 : n-1] 163 return x 164 }