github.com/bcskill/bcschain/v3@v3.4.9-beta2/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/bcskill/bcschain/v3/common"
    23  	"github.com/bcskill/bcschain/v3/log"
    24  )
    25  
    26  type account struct {
    27  	stateObject *stateObject
    28  	nstart      uint64
    29  	nonces      []bool
    30  }
    31  
    32  type ManagedState struct {
    33  	*StateDB
    34  
    35  	mu sync.RWMutex
    36  
    37  	accounts map[common.Address]*account
    38  }
    39  
    40  // ManagedState returns a new managed state with the statedb as it's backing layer
    41  func ManageState(statedb *StateDB) *ManagedState {
    42  	return &ManagedState{
    43  		StateDB:  statedb.Copy(),
    44  		accounts: make(map[common.Address]*account),
    45  	}
    46  }
    47  
    48  // SetState sets the backing layer of the managed state
    49  func (ms *ManagedState) SetState(statedb *StateDB) {
    50  	ms.mu.Lock()
    51  	defer ms.mu.Unlock()
    52  	ms.StateDB = statedb
    53  }
    54  
    55  // RemoveNonce removed the nonce from the managed state and all future pending nonces
    56  func (ms *ManagedState) RemoveNonce(addr common.Address, n uint64) {
    57  	if ms.hasAccount(addr) {
    58  		ms.mu.Lock()
    59  		defer ms.mu.Unlock()
    60  
    61  		account := ms.getAccount(addr)
    62  		if n-account.nstart <= uint64(len(account.nonces)) {
    63  			reslice := make([]bool, n-account.nstart)
    64  			copy(reslice, account.nonces[:n-account.nstart])
    65  			account.nonces = reslice
    66  		}
    67  	}
    68  }
    69  
    70  // NewNonce returns the new canonical nonce for the managed account
    71  func (ms *ManagedState) NewNonce(addr common.Address) uint64 {
    72  	ms.mu.Lock()
    73  	defer ms.mu.Unlock()
    74  
    75  	account := ms.getAccount(addr)
    76  	for i, nonce := range account.nonces {
    77  		if !nonce {
    78  			return account.nstart + uint64(i)
    79  		}
    80  	}
    81  	account.nonces = append(account.nonces, true)
    82  
    83  	return uint64(len(account.nonces)-1) + account.nstart
    84  }
    85  
    86  // GetNonce returns the canonical nonce for the managed or unmanaged account.
    87  //
    88  // Because GetNonce mutates the DB, we must take a write lock.
    89  func (ms *ManagedState) GetNonce(addr common.Address) uint64 {
    90  	ms.mu.Lock()
    91  	defer ms.mu.Unlock()
    92  
    93  	if ms.hasAccount(addr) {
    94  		account := ms.getAccount(addr)
    95  		return uint64(len(account.nonces)) + account.nstart
    96  	} else {
    97  		return ms.StateDB.GetNonce(addr)
    98  	}
    99  }
   100  
   101  // SetNonce sets the new canonical nonce for the managed state
   102  func (ms *ManagedState) SetNonce(addr common.Address, nonce uint64) {
   103  	ms.mu.Lock()
   104  	defer ms.mu.Unlock()
   105  
   106  	so := ms.GetOrNewStateObject(addr)
   107  	so.SetNonce(nonce)
   108  
   109  	ms.accounts[addr] = newAccount(so)
   110  }
   111  
   112  // HasAccount returns whether the given address is managed or not
   113  func (ms *ManagedState) HasAccount(addr common.Address) bool {
   114  	ms.mu.RLock()
   115  	defer ms.mu.RUnlock()
   116  	return ms.hasAccount(addr)
   117  }
   118  
   119  func (ms *ManagedState) hasAccount(addr common.Address) bool {
   120  	_, ok := ms.accounts[addr]
   121  	return ok
   122  }
   123  
   124  // populate the managed state
   125  func (ms *ManagedState) getAccount(addr common.Address) *account {
   126  	if account, ok := ms.accounts[addr]; !ok {
   127  		so := ms.GetOrNewStateObject(addr)
   128  		ms.accounts[addr] = newAccount(so)
   129  	} else {
   130  		// Always make sure the state account nonce isn't actually higher
   131  		// than the tracked one.
   132  		so, err := ms.StateDB.getStateObject(addr)
   133  		if err != nil {
   134  			log.Error("Failed to get state object", "err", err)
   135  		}
   136  		if so != nil && uint64(len(account.nonces))+account.nstart < so.Nonce() {
   137  			ms.accounts[addr] = newAccount(so)
   138  		}
   139  	}
   140  
   141  	return ms.accounts[addr]
   142  }
   143  
   144  func newAccount(so *stateObject) *account {
   145  	return &account{so, so.Nonce(), nil}
   146  }