github.com/Blockdaemon/celo-blockchain@v0.0.0-20200129231733-e667f6b08419/core/state/managed_state.go (about)

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