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  }