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