以太坊原始碼分析(25)core-txlist交易池的一些資料結構原始碼分析

尹成發表於2018-05-14
## nonceHeap
nonceHeap實現了一個heap.Interface的資料結構,用來實現了一個堆的資料結構。 在heap.Interface的文件介紹中,預設實現的是最小堆。

如果h是一個陣列,只要陣列中的資料滿足下面的要求。那麼就認為h是一個最小堆。

    !h.Less(j, i) for 0 <= i < h.Len() and 2*i+1 <= j <= 2*i+2 and j < h.Len()
    // 把陣列看成是一顆滿的二叉樹,第一個元素是樹根,第二和第三個元素是樹根的兩個樹枝,
    // 這樣依次推下去 那麼如果樹根是 i 那麼它的兩個樹枝就是 2*i+2 和 2*i + 2。
    // 最小堆的定義是 任意的樹根不能比它的兩個樹枝大。 也就是上面的程式碼描述的定義。
    heap.Interface的定義
    
    我們只需要定義滿足下面介面的資料結構,就能夠使用heap的一些方法來實現為堆結構。
    type Interface interface {
        sort.Interface
        Push(x interface{}) // add x as element Len() 把x增加到最後
        Pop() interface{} // remove and return element Len() - 1. 移除並返回最後的一個元素
    }

nonceHeap的程式碼分析。

    // nonceHeap is a heap.Interface implementation over 64bit unsigned integers for
    // retrieving sorted transactions from the possibly gapped future queue.
    type nonceHeap []uint64
    
    func (h nonceHeap) Len() int { return len(h) }
    func (h nonceHeap) Less(i, j int) bool { return h[i] < h[j] }
    func (h nonceHeap) Swap(i, j int) { h[i], h[j] = h[j], h[i] }
    
    func (h *nonceHeap) Push(x interface{}) {
        *h = append(*h, x.(uint64))
    }
    
    func (h *nonceHeap) Pop() interface{} {
        old := *h
        n := len(old)
        x := old[n-1]
        *h = old[0 : n-1]
        return x
    }


## txSortedMap

txSortedMap,儲存的是同一個賬號下面的所有的交易。

結構

    // txSortedMap is a nonce->transaction hash map with a heap based index to allow
    // iterating over the contents in a nonce-incrementing way.
    // txSortedMap是一個具有基於堆的索引的nonce->交易 的hashmap,
    // 允許以nonce遞增的方式迭代內容。
    
    type Transactions []*Transaction

    type txSortedMap struct {
        items map[uint64]*types.Transaction // Hash map storing the transaction data
        index *nonceHeap // Heap of nonces of all the stored transactions (non-strict mode)
        cache types.Transactions // Cache of the transactions already sorted 用來快取已經排好序的交易。
    }

Put 和 Get, Get用於獲取指定nonce的交易, Put用來把交易插入到map中。
    
    // Get retrieves the current transactions associated with the given nonce.
    func (m *txSortedMap) Get(nonce uint64) *types.Transaction {
        return m.items[nonce]
    }
    
    // Put inserts a new transaction into the map, also updating the map's nonce
    // index. If a transaction already exists with the same nonce, it's overwritten.
    // 把一個新的事務插入到map中,同時更新map的nonce索引。 如果一個事務已經存在,就把它覆蓋。 同時任何快取的資料會被刪除。
    func (m *txSortedMap) Put(tx *types.Transaction) {
        nonce := tx.Nonce()
        if m.items[nonce] == nil {
            heap.Push(m.index, nonce)
        }
        m.items[nonce], m.cache = tx, nil
    }

Forward用於刪除所有nonce小於threshold的交易。 然後返回所有被移除的交易。
    
    // Forward removes all transactions from the map with a nonce lower than the
    // provided threshold. Every removed transaction is returned for any post-removal
    // maintenance.
    func (m *txSortedMap) Forward(threshold uint64) types.Transactions {
        var removed types.Transactions
    
        // Pop off heap items until the threshold is reached
        for m.index.Len() > 0 && (*m.index)[0] < threshold {
            nonce := heap.Pop(m.index).(uint64)
            removed = append(removed, m.items[nonce])
            delete(m.items, nonce)
        }
        // If we had a cached order, shift the front
        // cache是排好序的交易。
        if m.cache != nil {
            m.cache = m.cache[len(removed):]
        }
        return removed
    }
    
Filter, 刪除所有令filter函式呼叫返回true的交易,並返回那些交易。
            
    // Filter iterates over the list of transactions and removes all of them for which
    // the specified function evaluates to true.
    func (m *txSortedMap) Filter(filter func(*types.Transaction) bool) types.Transactions {
        var removed types.Transactions
    
        // Collect all the transactions to filter out
        for nonce, tx := range m.items {
            if filter(tx) {
                removed = append(removed, tx)
                delete(m.items, nonce)
            }
        }
        // If transactions were removed, the heap and cache are ruined
        // 如果事務被刪除,堆和快取被毀壞
        if len(removed) > 0 {
            *m.index = make([]uint64, 0, len(m.items))
            for nonce := range m.items {
                *m.index = append(*m.index, nonce)
            }
            // 需要重建堆
            heap.Init(m.index)
            // 設定cache為nil
            m.cache = nil
        }
        return removed
    }

Cap 對items裡面的數量有限制,返回超過限制的所有交易。
    
    // Cap places a hard limit on the number of items, returning all transactions
    // exceeding that limit.
    // Cap 對items裡面的數量有限制,返回超過限制的所有交易。
    func (m *txSortedMap) Cap(threshold int) types.Transactions {
        // Short circuit if the number of items is under the limit
        if len(m.items) <= threshold {
            return nil
        }
        // Otherwise gather and drop the highest nonce'd transactions
        var drops types.Transactions
    
        sort.Sort(*m.index) //從小到大排序 從尾部刪除。
        for size := len(m.items); size > threshold; size-- {
            drops = append(drops, m.items[(*m.index)[size-1]])
            delete(m.items, (*m.index)[size-1])
        }
        *m.index = (*m.index)[:threshold]
        // 重建堆
        heap.Init(m.index)
    
        // If we had a cache, shift the back
        if m.cache != nil {
            m.cache = m.cache[:len(m.cache)-len(drops)]
        }
        return drops
    }

Remove
    
    // Remove deletes a transaction from the maintained map, returning whether the
    // transaction was found.
    //
    func (m *txSortedMap) Remove(nonce uint64) bool {
        // Short circuit if no transaction is present
        _, ok := m.items[nonce]
        if !ok {
            return false
        }
        // Otherwise delete the transaction and fix the heap index
        for i := 0; i < m.index.Len(); i++ {
            if (*m.index)[i] == nonce {
                heap.Remove(m.index, i)
                break
            }
        }
        delete(m.items, nonce)
        m.cache = nil
    
        return true
    }

Ready函式 
    
    // Ready retrieves a sequentially increasing list of transactions starting at the
    // provided nonce that is ready for processing. The returned transactions will be
    // removed from the list.
    // Ready 返回一個從指定nonce開始,連續的交易。 返回的交易會被刪除。
    // Note, all transactions with nonces lower than start will also be returned to
    // prevent getting into and invalid state. This is not something that should ever
    // happen but better to be self correcting than failing!
    // 注意,請注意,所有具有低於start的nonce的交易也將被返回,以防止進入和無效狀態。
    // 這不是應該發生的事情,而是自我糾正而不是失敗!
    func (m *txSortedMap) Ready(start uint64) types.Transactions {
        // Short circuit if no transactions are available
        if m.index.Len() == 0 || (*m.index)[0] > start {
            return nil
        }
        // Otherwise start accumulating incremental transactions
        var ready types.Transactions
        // 從最小的開始,一個一個的增加,
        for next := (*m.index)[0]; m.index.Len() > 0 && (*m.index)[0] == next; next++ {
            ready = append(ready, m.items[next])
            delete(m.items, next)
            heap.Pop(m.index)
        }
        m.cache = nil
    
        return ready
    }

Flatten,返回一個基於nonce排序的交易列表。並快取到cache欄位裡面,以便在沒有修改的情況下反覆使用。
    
    // Len returns the length of the transaction map.
    func (m *txSortedMap) Len() int {
        return len(m.items)
    }
    
    // Flatten creates a nonce-sorted slice of transactions based on the loosely
    // sorted internal representation. The result of the sorting is cached in case
    // it's requested again before any modifications are made to the contents.
    func (m *txSortedMap) Flatten() types.Transactions {
        // If the sorting was not cached yet, create and cache it
        if m.cache == nil {
            m.cache = make(types.Transactions, 0, len(m.items))
            for _, tx := range m.items {
                m.cache = append(m.cache, tx)
            }
            sort.Sort(types.TxByNonce(m.cache))
        }
        // Copy the cache to prevent accidental modifications
        txs := make(types.Transactions, len(m.cache))
        copy(txs, m.cache)
        return txs
    }

## txList
txList 是屬於同一個賬號的交易列表, 按照nonce排序。可以用來儲存連續的可執行的交易。對於非連續的交易,有一些小的不同的行為。

結構
    
    // txList is a "list" of transactions belonging to an account, sorted by account
    // nonce. The same type can be used both for storing contiguous transactions for
    // the executable/pending queue; and for storing gapped transactions for the non-
    // executable/future queue, with minor behavioral changes.
    type txList struct {
        strict bool // Whether nonces are strictly continuous or not nonces是嚴格連續的還是非連續的
        txs *txSortedMap // Heap indexed sorted hash map of the transactions 基於堆索引的交易的hashmap
    
        costcap *big.Int // Price of the highest costing transaction (reset only if exceeds balance) 所有交易裡面,GasPrice * GasLimit最高的值
        gascap *big.Int // Gas limit of the highest spending transaction (reset only if exceeds block limit) 所有交易裡面, GasPrice最高的值
    }
Overlaps 返回給定的交易是否有具有相同nonce的交易存在。

    // Overlaps returns whether the transaction specified has the same nonce as one
    // already contained within the list.
    //
    func (l *txList) Overlaps(tx *types.Transaction) bool {
        return l.txs.Get(tx.Nonce()) != nil
    }
Add 執行這樣的操作,如果新的交易比老的交易的GasPrice值要高出一定的比值priceBump,那麼會替換老的交易。
    
    // Add tries to insert a new transaction into the list, returning whether the
    // transaction was accepted, and if yes, any previous transaction it replaced.
    // Add 嘗試插入一個新的交易,返回交易是否被接收,如果被接收,那麼任意之前的交易會被替換。
    // If the new transaction is accepted into the list, the lists' cost and gas
    // thresholds are also potentially updated.
    // 如果新的交易被接收,那麼總的cost和gas限制會被更新。
    func (l *txList) Add(tx *types.Transaction, priceBump uint64) (bool, *types.Transaction) {
        // If there's an older better transaction, abort
        // 如果存在老的交易。 而且新的交易的價格比老的高出一定的數量。那麼替換。
        old := l.txs.Get(tx.Nonce())
        if old != nil {
            threshold := new(big.Int).Div(new(big.Int).Mul(old.GasPrice(), big.NewInt(100+int64(priceBump))), big.NewInt(100))
            if threshold.Cmp(tx.GasPrice()) >= 0 {
                return false, nil
            }
        }
        // Otherwise overwrite the old transaction with the current one
        l.txs.Put(tx)
        if cost := tx.Cost(); l.costcap.Cmp(cost) < 0 {
            l.costcap = cost
        }
        if gas := tx.Gas(); l.gascap.Cmp(gas) < 0 {
            l.gascap = gas
        }
        return true, old
    }
Forward 刪除nonce小於某個值的所有交易。

    // Forward removes all transactions from the list with a nonce lower than the
    // provided threshold. Every removed transaction is returned for any post-removal
    // maintenance.
    func (l *txList) Forward(threshold uint64) types.Transactions {
        return l.txs.Forward(threshold)
    }

Filter,
    
    // Filter removes all transactions from the list with a cost or gas limit higher
    // than the provided thresholds. Every removed transaction is returned for any
    // post-removal maintenance. Strict-mode invalidated transactions are also
    // returned.
    // Filter 移除所有比提供的cost或者gasLimit的值更高的交易。 被移除的交易會返回以便進一步處理。 在嚴格模式下,所有無效的交易同樣被返回。
    //
    // This method uses the cached costcap and gascap to quickly decide if there's even
    // a point in calculating all the costs or if the balance covers all. If the threshold
    // is lower than the costgas cap, the caps will be reset to a new high after removing
    // the newly invalidated transactions.
    // 這個方法會使用快取的costcap和gascap以便快速的決定是否需要遍歷所有的交易。如果限制小於快取的costcap和gascap,那麼在移除不合法的交易之後會更新costcap和gascap的值。

    func (l *txList) Filter(costLimit, gasLimit *big.Int) (types.Transactions, types.Transactions) {
        // If all transactions are below the threshold, short circuit
        // 如果所有的交易都小於限制,那麼直接返回。
        if l.costcap.Cmp(costLimit) <= 0 && l.gascap.Cmp(gasLimit) <= 0 {
            return nil, nil
        }
        l.costcap = new(big.Int).Set(costLimit) // Lower the caps to the thresholds
        l.gascap = new(big.Int).Set(gasLimit)
    
        // Filter out all the transactions above the account's funds
        removed := l.txs.Filter(func(tx *types.Transaction) bool { return tx.Cost().Cmp(costLimit) > 0 || tx.Gas().Cmp(gasLimit) > 0 })
    
        // If the list was strict, filter anything above the lowest nonce
        var invalids types.Transactions
    
        if l.strict && len(removed) > 0 {
            // 所有的nonce大於 最小的被移除的nonce的交易都被任務是無效的。
            // 在嚴格模式下,這種交易也被移除。
            lowest := uint64(math.MaxUint64)
            for _, tx := range removed {
                if nonce := tx.Nonce(); lowest > nonce {
                    lowest = nonce
                }
            }
            invalids = l.txs.Filter(func(tx *types.Transaction) bool { return tx.Nonce() > lowest })
        }
        return removed, invalids
    }

Cap函式用來返回超過數量的交易。 如果交易的數量超過threshold,那麼把之後的交易移除並返回。
    
    // Cap places a hard limit on the number of items, returning all transactions
    // exceeding that limit.
    func (l *txList) Cap(threshold int) types.Transactions {
        return l.txs.Cap(threshold)
    }

Remove,刪除給定Nonce的交易,如果在嚴格模式下,還刪除所有nonce大於給定Nonce的交易,並返回。
    
    // Remove deletes a transaction from the maintained list, returning whether the
    // transaction was found, and also returning any transaction invalidated due to
    // the deletion (strict mode only).
    func (l *txList) Remove(tx *types.Transaction) (bool, types.Transactions) {
        // Remove the transaction from the set
        nonce := tx.Nonce()
        if removed := l.txs.Remove(nonce); !removed {
            return false, nil
        }
        // In strict mode, filter out non-executable transactions
        if l.strict {
            return true, l.txs.Filter(func(tx *types.Transaction) bool { return tx.Nonce() > nonce })
        }
        return true, nil
    }

Ready, len, Empty, Flatten 直接呼叫了txSortedMap的對應方法。

    // Ready retrieves a sequentially increasing list of transactions starting at the
    // provided nonce that is ready for processing. The returned transactions will be
    // removed from the list.
    //
    // Note, all transactions with nonces lower than start will also be returned to
    // prevent getting into and invalid state. This is not something that should ever
    // happen but better to be self correcting than failing!
    func (l *txList) Ready(start uint64) types.Transactions {
        return l.txs.Ready(start)
    }

    // Len returns the length of the transaction list.
    func (l *txList) Len() int {
        return l.txs.Len()
    }

    // Empty returns whether the list of transactions is empty or not.
    func (l *txList) Empty() bool {
        return l.Len() == 0
    }

    // Flatten creates a nonce-sorted slice of transactions based on the loosely
    // sorted internal representation. The result of the sorting is cached in case
    // it's requested again before any modifications are made to the contents.
    func (l *txList) Flatten() types.Transactions {
        return l.txs.Flatten()
    }


## priceHeap
priceHeap是一個最小堆, 按照價格的大小來建堆。
    
    // priceHeap is a heap.Interface implementation over transactions for retrieving
    // price-sorted transactions to discard when the pool fills up.
    type priceHeap []*types.Transaction
    
    func (h priceHeap) Len() int { return len(h) }
    func (h priceHeap) Less(i, j int) bool { return h[i].GasPrice().Cmp(h[j].GasPrice()) < 0 }
    func (h priceHeap) Swap(i, j int) { h[i], h[j] = h[j], h[i] }
    
    func (h *priceHeap) Push(x interface{}) {
        *h = append(*h, x.(*types.Transaction))
    }
    
    func (h *priceHeap) Pop() interface{} {
        old := *h
        n := len(old)
        x := old[n-1]
        *h = old[0 : n-1]
        return x
    }


## txPricedList
資料結構和構建,txPricedList 是基於價格排序的堆,允許按照價格遞增的方式處理交易。

    
    // txPricedList is a price-sorted heap to allow operating on transactions pool
    // contents in a price-incrementing way.
    type txPricedList struct {
        all *map[common.Hash]*types.Transaction // Pointer to the map of all transactions 這是一個指標,指向了所有交易的map
        items *priceHeap // Heap of prices of all the stored transactions
        stales int // Number of stale price points to (re-heap trigger)
    }
    
    // newTxPricedList creates a new price-sorted transaction heap.
    func newTxPricedList(all *map[common.Hash]*types.Transaction) *txPricedList {
        return &txPricedList{
            all: all,
            items: new(priceHeap),
        }
    }

Put

    // Put inserts a new transaction into the heap.
    func (l *txPricedList) Put(tx *types.Transaction) {
        heap.Push(l.items, tx)
    }

Removed

    // Removed notifies the prices transaction list that an old transaction dropped
    // from the pool. The list will just keep a counter of stale objects and update
    // the heap if a large enough ratio of transactions go stale.
    // Removed 用來通知txPricedList有一個老的交易被刪除. txPricedList使用一個計數器來決定何時更新堆資訊.
    func (l *txPricedList) Removed() {
        // Bump the stale counter, but exit if still too low (< 25%)
        l.stales++
        if l.stales <= len(*l.items)/4 {
            return
        }
        // Seems we've reached a critical number of stale transactions, reheap
        reheap := make(priceHeap, 0, len(*l.all))
    
        l.stales, l.items = 0, &reheap
        for _, tx := range *l.all {
            *l.items = append(*l.items, tx)
        }
        heap.Init(l.items)
    }

Cap 用來找到所有低於給定價格閾值的交易. 把他們從priceList刪除並返回.
    
    // Cap finds all the transactions below the given price threshold, drops them
    // from the priced list and returs them for further removal from the entire pool.
    func (l *txPricedList) Cap(threshold *big.Int, local *accountSet) types.Transactions {
        drop := make(types.Transactions, 0, 128) // Remote underpriced transactions to drop
        save := make(types.Transactions, 0, 64) // Local underpriced transactions to keep
    
        for len(*l.items) > 0 {
            // Discard stale transactions if found during cleanup
            tx := heap.Pop(l.items).(*types.Transaction)
            if _, ok := (*l.all)[tx.Hash()]; !ok {
                // 如果發現一個已經刪除的,那麼更新states計數器
                l.stales--
                continue
            }
            // Stop the discards if we've reached the threshold
            if tx.GasPrice().Cmp(threshold) >= 0 {
                // 如果價格不小於閾值, 那麼退出
                save = append(save, tx)
                break
            }
            // Non stale transaction found, discard unless local
            if local.containsTx(tx) { //本地的交易不會刪除
                save = append(save, tx)
            } else {
                drop = append(drop, tx)
            }
        }
        for _, tx := range save {
            heap.Push(l.items, tx)
        }
        return drop
    }


Underpriced, 檢查 tx是否比 當前txPricedList裡面最便宜的交易還要便宜或者是同樣便宜.
    
    // Underpriced checks whether a transaction is cheaper than (or as cheap as) the
    // lowest priced transaction currently being tracked.
    func (l *txPricedList) Underpriced(tx *types.Transaction, local *accountSet) bool {
        // Local transactions cannot be underpriced
        if local.containsTx(tx) {
            return false
        }
        // Discard stale price points if found at the heap start
        for len(*l.items) > 0 {
            head := []*types.Transaction(*l.items)[0]
            if _, ok := (*l.all)[head.Hash()]; !ok {
                l.stales--
                heap.Pop(l.items)
                continue
            }
            break
        }
        // Check if the transaction is underpriced or not
        if len(*l.items) == 0 {
            log.Error("Pricing query for empty pool") // This cannot happen, print to catch programming errors
            return false
        }
        cheapest := []*types.Transaction(*l.items)[0]
        return cheapest.GasPrice().Cmp(tx.GasPrice()) >= 0
    }

Discard,查詢一定數量的最便宜的交易,把他們從當前的列表刪除並返回.
    
    // Discard finds a number of most underpriced transactions, removes them from the
    // priced list and returns them for further removal from the entire pool.
    func (l *txPricedList) Discard(count int, local *accountSet) types.Transactions {
        drop := make(types.Transactions, 0, count) // Remote underpriced transactions to drop
        save := make(types.Transactions, 0, 64) // Local underpriced transactions to keep
    
        for len(*l.items) > 0 && count > 0 {
            // Discard stale transactions if found during cleanup
            tx := heap.Pop(l.items).(*types.Transaction)
            if _, ok := (*l.all)[tx.Hash()]; !ok {
                l.stales--
                continue
            }
            // Non stale transaction found, discard unless local
            if local.containsTx(tx) {
                save = append(save, tx)
            } else {
                drop = append(drop, tx)
                count--
            }
        }
        for _, tx := range save {
            heap.Push(l.items, tx)
        }
        return drop
    }


## accountSet
accountSet 就是一個賬號的集合和一個處理簽名的物件.
    
    // accountSet is simply a set of addresses to check for existence, and a signer
    // capable of deriving addresses from transactions.
    type accountSet struct {
        accounts map[common.Address]struct{}
        signer types.Signer
    }
    
    // newAccountSet creates a new address set with an associated signer for sender
    // derivations.
    func newAccountSet(signer types.Signer) *accountSet {
        return &accountSet{
            accounts: make(map[common.Address]struct{}),
            signer: signer,
        }
    }
    
    // contains checks if a given address is contained within the set.
    func (as *accountSet) contains(addr common.Address) bool {
        _, exist := as.accounts[addr]
        return exist
    }
    
    // containsTx checks if the sender of a given tx is within the set. If the sender
    // cannot be derived, this method returns false.
    // containsTx檢查給定tx的傳送者是否在集合內。 如果發件人無法被計算出,則此方法返回false。
    func (as *accountSet) containsTx(tx *types.Transaction) bool {
        if addr, err := types.Sender(as.signer, tx); err == nil {
            return as.contains(addr)
        }
        return false
    }
    
    // add inserts a new address into the set to track.
    func (as *accountSet) add(addr common.Address) {
        as.accounts[addr] = struct{}{}
    }


## txJournal

txJournal是交易的一個迴圈日誌,其目的是儲存本地建立的事務,以允許未執行的事務在節點重新啟動後繼續執行。
結構
    

    // txJournal is a rotating log of transactions with the aim of storing locally
    // created transactions to allow non-executed ones to survive node restarts.
    type txJournal struct {
        path string // Filesystem path to store the transactions at 用來儲存交易的檔案系統路徑.
        writer io.WriteCloser // Output stream to write new transactions into 用來寫入新交易的輸出流.
    }

newTxJournal,用來建立新的交易日誌.

    // newTxJournal creates a new transaction journal to
    func newTxJournal(path string) *txJournal {
        return &txJournal{
            path: path,
        }
    }

load方法從磁碟解析交易,然後呼叫add回撥方法.  
    
    // load parses a transaction journal dump from disk, loading its contents into
    // the specified pool.
    func (journal *txJournal) load(add func(*types.Transaction) error) error {
        // Skip the parsing if the journal file doens't exist at all
        if _, err := os.Stat(journal.path); os.IsNotExist(err) {
            return nil
        }
        // Open the journal for loading any past transactions
        input, err := os.Open(journal.path)
        if err != nil {
            return err
        }
        defer input.Close()
    
        // Inject all transactions from the journal into the pool
        stream := rlp.NewStream(input, 0)
        total, dropped := 0, 0
    
        var failure error
        for {
            // Parse the next transaction and terminate on error
            tx := new(types.Transaction)
            if err = stream.Decode(tx); err != nil {
                if err != io.EOF {
                    failure = err
                }
                break
            }
            // Import the transaction and bump the appropriate progress counters
            total++
            if err = add(tx); err != nil {
                log.Debug("Failed to add journaled transaction", "err", err)
                dropped++
                continue
            }
        }
        log.Info("Loaded local transaction journal", "transactions", total, "dropped", dropped)
    
        return failure
    }
insert方法,呼叫rlp.Encode寫入writer
    
    // insert adds the specified transaction to the local disk journal.
    func (journal *txJournal) insert(tx *types.Transaction) error {
        if journal.writer == nil {
            return errNoActiveJournal
        }
        if err := rlp.Encode(journal.writer, tx); err != nil {
            return err
        }
        return nil
    }

rotate方法基於當前的交易池重新生成交易,

    // rotate regenerates the transaction journal based on the current contents of
    // the transaction pool.
    func (journal *txJournal) rotate(all map[common.Address]types.Transactions) error {
        // Close the current journal (if any is open)
        if journal.writer != nil {
            if err := journal.writer.Close(); err != nil {
                return err
            }
            journal.writer = nil
        }
        // Generate a new journal with the contents of the current pool
        replacement, err := os.OpenFile(journal.path+".new", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0755)
        if err != nil {
            return err
        }
        journaled := 0
        for _, txs := range all {
            for _, tx := range txs {
                if err = rlp.Encode(replacement, tx); err != nil {
                    replacement.Close()
                    return err
                }
            }
            journaled += len(txs)
        }
        replacement.Close()
    
        // Replace the live journal with the newly generated one
        if err = os.Rename(journal.path+".new", journal.path); err != nil {
            return err
        }
        sink, err := os.OpenFile(journal.path, os.O_WRONLY|os.O_APPEND, 0755)
        if err != nil {
            return err
        }
        journal.writer = sink
        log.Info("Regenerated local transaction journal", "transactions", journaled, "accounts", len(all))
    
        return nil
    }

close

    // close flushes the transaction journal contents to disk and closes the file.
    func (journal *txJournal) close() error {
        var err error
    
        if journal.writer != nil {
            err = journal.writer.Close()
            journal.writer = nil
        }
        return err
    }




網址:http://www.qukuailianxueyuan.io/



欲領取造幣技術與全套虛擬機器資料

區塊鏈技術交流QQ群:756146052  備註:CSDN

尹成學院微信:備註:CSDN



相關文章