github.com/sberex/go-sberex@v1.8.2-0.20181113200658-ed96ac38f7d7/core/state/managed_state.go (about)

     1  // This file is part of the go-sberex library. The go-sberex library is 
     2  // free software: you can redistribute it and/or modify it under the terms 
     3  // of the GNU Lesser General Public License as published by the Free 
     4  // Software Foundation, either version 3 of the License, or (at your option)
     5  // any later version.
     6  //
     7  // The go-sberex library is distributed in the hope that it will be useful, 
     8  // but WITHOUT ANY WARRANTY; without even the implied warranty of
     9  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 
    10  // General Public License <http://www.gnu.org/licenses/> for more details.
    11  
    12  package state
    13  
    14  import (
    15  	"sync"
    16  
    17  	"github.com/Sberex/go-sberex/common"
    18  )
    19  
    20  type account struct {
    21  	stateObject *stateObject
    22  	nstart      uint64
    23  	nonces      []bool
    24  }
    25  
    26  type ManagedState struct {
    27  	*StateDB
    28  
    29  	mu sync.RWMutex
    30  
    31  	accounts map[common.Address]*account
    32  }
    33  
    34  // ManagedState returns a new managed state with the statedb as it's backing layer
    35  func ManageState(statedb *StateDB) *ManagedState {
    36  	return &ManagedState{
    37  		StateDB:  statedb.Copy(),
    38  		accounts: make(map[common.Address]*account),
    39  	}
    40  }
    41  
    42  // SetState sets the backing layer of the managed state
    43  func (ms *ManagedState) SetState(statedb *StateDB) {
    44  	ms.mu.Lock()
    45  	defer ms.mu.Unlock()
    46  	ms.StateDB = statedb
    47  }
    48  
    49  // RemoveNonce removed the nonce from the managed state and all future pending nonces
    50  func (ms *ManagedState) RemoveNonce(addr common.Address, n uint64) {
    51  	if ms.hasAccount(addr) {
    52  		ms.mu.Lock()
    53  		defer ms.mu.Unlock()
    54  
    55  		account := ms.getAccount(addr)
    56  		if n-account.nstart <= uint64(len(account.nonces)) {
    57  			reslice := make([]bool, n-account.nstart)
    58  			copy(reslice, account.nonces[:n-account.nstart])
    59  			account.nonces = reslice
    60  		}
    61  	}
    62  }
    63  
    64  // NewNonce returns the new canonical nonce for the managed account
    65  func (ms *ManagedState) NewNonce(addr common.Address) uint64 {
    66  	ms.mu.Lock()
    67  	defer ms.mu.Unlock()
    68  
    69  	account := ms.getAccount(addr)
    70  	for i, nonce := range account.nonces {
    71  		if !nonce {
    72  			return account.nstart + uint64(i)
    73  		}
    74  	}
    75  	account.nonces = append(account.nonces, true)
    76  
    77  	return uint64(len(account.nonces)-1) + account.nstart
    78  }
    79  
    80  // GetNonce returns the canonical nonce for the managed or unmanaged account.
    81  //
    82  // Because GetNonce mutates the DB, we must take a write lock.
    83  func (ms *ManagedState) GetNonce(addr common.Address) uint64 {
    84  	ms.mu.Lock()
    85  	defer ms.mu.Unlock()
    86  
    87  	if ms.hasAccount(addr) {
    88  		account := ms.getAccount(addr)
    89  		return uint64(len(account.nonces)) + account.nstart
    90  	} else {
    91  		return ms.StateDB.GetNonce(addr)
    92  	}
    93  }
    94  
    95  // SetNonce sets the new canonical nonce for the managed state
    96  func (ms *ManagedState) SetNonce(addr common.Address, nonce uint64) {
    97  	ms.mu.Lock()
    98  	defer ms.mu.Unlock()
    99  
   100  	so := ms.GetOrNewStateObject(addr)
   101  	so.SetNonce(nonce)
   102  
   103  	ms.accounts[addr] = newAccount(so)
   104  }
   105  
   106  // HasAccount returns whether the given address is managed or not
   107  func (ms *ManagedState) HasAccount(addr common.Address) bool {
   108  	ms.mu.RLock()
   109  	defer ms.mu.RUnlock()
   110  	return ms.hasAccount(addr)
   111  }
   112  
   113  func (ms *ManagedState) hasAccount(addr common.Address) bool {
   114  	_, ok := ms.accounts[addr]
   115  	return ok
   116  }
   117  
   118  // populate the managed state
   119  func (ms *ManagedState) getAccount(addr common.Address) *account {
   120  	if account, ok := ms.accounts[addr]; !ok {
   121  		so := ms.GetOrNewStateObject(addr)
   122  		ms.accounts[addr] = newAccount(so)
   123  	} else {
   124  		// Always make sure the state account nonce isn't actually higher
   125  		// than the tracked one.
   126  		so := ms.StateDB.getStateObject(addr)
   127  		if so != nil && uint64(len(account.nonces))+account.nstart < so.Nonce() {
   128  			ms.accounts[addr] = newAccount(so)
   129  		}
   130  
   131  	}
   132  
   133  	return ms.accounts[addr]
   134  }
   135  
   136  func newAccount(so *stateObject) *account {
   137  	return &account{so, so.Nonce(), nil}
   138  }