github.com/datachainlab/burrow@v0.25.0/execution/evm/state.go (about)

     1  package evm
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/hyperledger/burrow/acm"
     7  	"github.com/hyperledger/burrow/acm/acmstate"
     8  	"github.com/hyperledger/burrow/binary"
     9  	"github.com/hyperledger/burrow/crypto"
    10  	"github.com/hyperledger/burrow/execution/errors"
    11  	"github.com/hyperledger/burrow/permission"
    12  )
    13  
    14  type Interface interface {
    15  	Reader
    16  	Writer
    17  	// Capture any errors when accessing or writing state - will return nil if no errors have occurred so far
    18  	errors.Provider
    19  	errors.Sink
    20  	// Create a new cached state over this one inheriting any cache options
    21  	NewCache(cacheOptions ...acmstate.CacheOption) Interface
    22  	// Sync this state cache to into its originator
    23  	Sync() errors.CodedError
    24  }
    25  
    26  type Reader interface {
    27  	GetStorage(address crypto.Address, key binary.Word256) binary.Word256
    28  	GetBalance(address crypto.Address) uint64
    29  	GetPermissions(address crypto.Address) permission.AccountPermissions
    30  	GetCode(address crypto.Address) acm.Bytecode
    31  	GetSequence(address crypto.Address) uint64
    32  	Exists(address crypto.Address) bool
    33  	// GetBlockHash returns	hash of the specific block
    34  	GetBlockHash(blockNumber uint64) (binary.Word256, error)
    35  }
    36  
    37  type Writer interface {
    38  	CreateAccount(address crypto.Address)
    39  	InitCode(address crypto.Address, code []byte)
    40  	RemoveAccount(address crypto.Address)
    41  	SetStorage(address crypto.Address, key, value binary.Word256)
    42  	AddToBalance(address crypto.Address, amount uint64)
    43  	SubtractFromBalance(address crypto.Address, amount uint64)
    44  	SetPermission(address crypto.Address, permFlag permission.PermFlag, value bool)
    45  	UnsetPermission(address crypto.Address, permFlag permission.PermFlag)
    46  	AddRole(address crypto.Address, role string) bool
    47  	RemoveRole(address crypto.Address, role string) bool
    48  }
    49  
    50  type State struct {
    51  	// Where we sync
    52  	backend acmstate.ReaderWriter
    53  	// Block chain info
    54  	blockHashGetter func(height uint64) []byte
    55  	// Cache this State wraps
    56  	cache *acmstate.Cache
    57  	// Any error that may have occurred
    58  	error errors.CodedError
    59  	// In order for nested cache to inherit any options
    60  	cacheOptions []acmstate.CacheOption
    61  }
    62  
    63  func NewState(st acmstate.ReaderWriter, blockHashGetter func(height uint64) []byte, cacheOptions ...acmstate.CacheOption) *State {
    64  	return &State{
    65  		backend:         st,
    66  		blockHashGetter: blockHashGetter,
    67  		cache:           acmstate.NewCache(st, cacheOptions...),
    68  		cacheOptions:    cacheOptions,
    69  	}
    70  }
    71  
    72  func (st *State) NewCache(cacheOptions ...acmstate.CacheOption) Interface {
    73  	return NewState(st.cache, st.blockHashGetter, append(st.cacheOptions, cacheOptions...)...)
    74  }
    75  
    76  func (st *State) Sync() errors.CodedError {
    77  	// Do not sync if we have erred
    78  	if st.error != nil {
    79  		return st.error
    80  	}
    81  	err := st.cache.Sync(st.backend)
    82  	if err != nil {
    83  		return errors.AsException(err)
    84  	}
    85  	return nil
    86  }
    87  
    88  func (st *State) Error() errors.CodedError {
    89  	if st.error == nil {
    90  		return nil
    91  	}
    92  	return st.error
    93  }
    94  
    95  // Errors pushed to state may end up in TxExecutions and therefore the merkle state so it is essential that errors are
    96  // deterministic and independent of the code path taken to execution (e.g. replay takes a different path to that of
    97  // normal consensus reactor so stack traces may differ - as they may across architectures)
    98  func (st *State) PushError(err error) {
    99  	if st.error == nil {
   100  		// Make sure we are not wrapping a known nil value
   101  		ex := errors.AsException(err)
   102  		if ex != nil {
   103  			st.error = ex
   104  		}
   105  	}
   106  }
   107  
   108  // Reader
   109  
   110  func (st *State) GetStorage(address crypto.Address, key binary.Word256) binary.Word256 {
   111  	value, err := st.cache.GetStorage(address, key)
   112  	if err != nil {
   113  		st.PushError(err)
   114  		return binary.Zero256
   115  	}
   116  	return value
   117  }
   118  
   119  func (st *State) GetBalance(address crypto.Address) uint64 {
   120  	acc := st.account(address)
   121  	if acc == nil {
   122  		return 0
   123  	}
   124  	return acc.Balance
   125  }
   126  
   127  func (st *State) GetPermissions(address crypto.Address) permission.AccountPermissions {
   128  	acc := st.account(address)
   129  	if acc == nil {
   130  		return permission.AccountPermissions{}
   131  	}
   132  	return acc.Permissions
   133  }
   134  
   135  func (st *State) GetCode(address crypto.Address) acm.Bytecode {
   136  	acc := st.account(address)
   137  	if acc == nil {
   138  		return nil
   139  	}
   140  	return acc.Code
   141  }
   142  
   143  func (st *State) Exists(address crypto.Address) bool {
   144  	acc, err := st.cache.GetAccount(address)
   145  	if err != nil {
   146  		st.PushError(err)
   147  		return false
   148  	}
   149  	if acc == nil {
   150  		return false
   151  	}
   152  	return true
   153  }
   154  
   155  func (st *State) GetSequence(address crypto.Address) uint64 {
   156  	acc := st.account(address)
   157  	if acc == nil {
   158  		return 0
   159  	}
   160  	return acc.Sequence
   161  }
   162  
   163  // Writer
   164  
   165  func (st *State) CreateAccount(address crypto.Address) {
   166  	if st.Exists(address) {
   167  		st.PushError(errors.ErrorCodef(errors.ErrorCodeDuplicateAddress,
   168  			"tried to create an account at an address that already exists: %v", address))
   169  		return
   170  	}
   171  	st.updateAccount(&acm.Account{Address: address})
   172  }
   173  
   174  func (st *State) InitCode(address crypto.Address, code []byte) {
   175  	acc := st.mustAccount(address)
   176  	if acc == nil {
   177  		st.PushError(errors.ErrorCodef(errors.ErrorCodeInvalidAddress,
   178  			"tried to initialise code for an account that does not exist: %v", address))
   179  		return
   180  	}
   181  	if acc.Code != nil {
   182  		st.PushError(errors.ErrorCodef(errors.ErrorCodeIllegalWrite,
   183  			"tried to initialise code for a contract that already exists: %v", address))
   184  		return
   185  	}
   186  	acc.Code = code
   187  	st.updateAccount(acc)
   188  }
   189  
   190  func (st *State) RemoveAccount(address crypto.Address) {
   191  	if !st.Exists(address) {
   192  		st.PushError(errors.ErrorCodef(errors.ErrorCodeDuplicateAddress,
   193  			"tried to remove an account at an address that does not exist: %v", address))
   194  		return
   195  	}
   196  	st.removeAccount(address)
   197  }
   198  
   199  func (st *State) SetStorage(address crypto.Address, key, value binary.Word256) {
   200  	err := st.cache.SetStorage(address, key, value)
   201  	if err != nil {
   202  		st.PushError(err)
   203  	}
   204  }
   205  
   206  func (st *State) AddToBalance(address crypto.Address, amount uint64) {
   207  	acc := st.mustAccount(address)
   208  	if acc == nil {
   209  		return
   210  	}
   211  	st.PushError(acc.AddToBalance(amount))
   212  	st.updateAccount(acc)
   213  }
   214  
   215  func (st *State) SubtractFromBalance(address crypto.Address, amount uint64) {
   216  	acc := st.mustAccount(address)
   217  	if acc == nil {
   218  		return
   219  	}
   220  	st.PushError(acc.SubtractFromBalance(amount))
   221  	st.updateAccount(acc)
   222  }
   223  
   224  func (st *State) SetPermission(address crypto.Address, permFlag permission.PermFlag, value bool) {
   225  	acc := st.mustAccount(address)
   226  	if acc == nil {
   227  		return
   228  	}
   229  	st.PushError(acc.Permissions.Base.Set(permFlag, value))
   230  	st.updateAccount(acc)
   231  }
   232  
   233  func (st *State) UnsetPermission(address crypto.Address, permFlag permission.PermFlag) {
   234  	acc := st.mustAccount(address)
   235  	if acc == nil {
   236  		return
   237  	}
   238  	st.PushError(acc.Permissions.Base.Unset(permFlag))
   239  	st.updateAccount(acc)
   240  }
   241  
   242  func (st *State) AddRole(address crypto.Address, role string) bool {
   243  	acc := st.mustAccount(address)
   244  	if acc == nil {
   245  		return false
   246  	}
   247  	added := acc.Permissions.AddRole(role)
   248  	st.updateAccount(acc)
   249  	return added
   250  }
   251  
   252  func (st *State) RemoveRole(address crypto.Address, role string) bool {
   253  	acc := st.mustAccount(address)
   254  	if acc == nil {
   255  		return false
   256  	}
   257  	removed := acc.Permissions.RemoveRole(role)
   258  	st.updateAccount(acc)
   259  	return removed
   260  }
   261  
   262  func (st *State) GetBlockHash(height uint64) (binary.Word256, error) {
   263  	hash := st.blockHashGetter(height)
   264  	if len(hash) == 0 {
   265  		st.PushError(fmt.Errorf("got empty BlockHash from blockHashGetter"))
   266  	}
   267  	return binary.LeftPadWord256(hash), nil
   268  }
   269  
   270  // Helpers
   271  
   272  func (st *State) account(address crypto.Address) *acm.Account {
   273  	acc, err := st.cache.GetAccount(address)
   274  	if err != nil {
   275  		st.PushError(err)
   276  	}
   277  	return acc
   278  }
   279  
   280  func (st *State) mustAccount(address crypto.Address) *acm.Account {
   281  	acc := st.account(address)
   282  	if acc == nil {
   283  		st.PushError(errors.ErrorCodef(errors.ErrorCodeIllegalWrite,
   284  			"attempted to modify non-existent account: %v", address))
   285  	}
   286  	return acc
   287  }
   288  
   289  func (st *State) updateAccount(account *acm.Account) {
   290  	err := st.cache.UpdateAccount(account)
   291  	if err != nil {
   292  		st.PushError(err)
   293  	}
   294  }
   295  
   296  func (st *State) removeAccount(address crypto.Address) {
   297  	err := st.cache.RemoveAccount(address)
   298  	if err != nil {
   299  		st.PushError(err)
   300  	}
   301  }