github.com/hyperledger/burrow@v0.34.5-0.20220512172541-77f09336001d/execution/native/state.go (about)

     1  package native
     2  
     3  import (
     4  	"github.com/hyperledger/burrow/acm"
     5  	"github.com/hyperledger/burrow/acm/acmstate"
     6  	"github.com/hyperledger/burrow/binary"
     7  	"github.com/hyperledger/burrow/crypto"
     8  	"github.com/hyperledger/burrow/execution/engine"
     9  	"github.com/hyperledger/burrow/execution/errors"
    10  )
    11  
    12  // This wrapper provides a state that behaves 'as if' the natives were stored directly in state.
    13  // TODO: we may want to actually store native account sentinel values (and their metadata) in on-disk state down the line
    14  type State struct {
    15  	natives engine.Natives
    16  	backend acmstate.ReaderWriter
    17  }
    18  
    19  // Get a new state that wraps the backend but intercepts any calls to natives returning appropriate errors message
    20  // or an Account sentinel for the particular native
    21  func NewState(natives engine.Natives, backend acmstate.ReaderWriter) *State {
    22  	return &State{
    23  		natives: natives,
    24  		backend: backend,
    25  	}
    26  }
    27  
    28  func (s *State) UpdateAccount(updatedAccount *acm.Account) error {
    29  	err := s.ensureNonNative(updatedAccount.Address, "update account")
    30  	if err != nil {
    31  		return err
    32  	}
    33  	return s.backend.UpdateAccount(updatedAccount)
    34  }
    35  
    36  func (s *State) GetAccount(address crypto.Address) (*acm.Account, error) {
    37  	contract := s.natives.GetByAddress(address)
    38  	if contract != nil {
    39  		return account(contract), nil
    40  	}
    41  	return s.backend.GetAccount(address)
    42  }
    43  
    44  func (s *State) RemoveAccount(address crypto.Address) error {
    45  	err := s.ensureNonNative(address, "remove account")
    46  	if err != nil {
    47  		return err
    48  	}
    49  	return s.backend.RemoveAccount(address)
    50  }
    51  
    52  func (s *State) GetStorage(address crypto.Address, key binary.Word256) ([]byte, error) {
    53  	err := s.ensureNonNative(address, "get storage")
    54  	if err != nil {
    55  		return nil, err
    56  	}
    57  	return s.backend.GetStorage(address, key)
    58  }
    59  
    60  func (s *State) SetStorage(address crypto.Address, key binary.Word256, value []byte) error {
    61  	err := s.ensureNonNative(address, "set storage")
    62  	if err != nil {
    63  		return err
    64  	}
    65  	return s.backend.SetStorage(address, key, value)
    66  }
    67  
    68  func (s *State) ensureNonNative(address crypto.Address, action string) error {
    69  	contract := s.natives.GetByAddress(address)
    70  	if contract != nil {
    71  		return errors.Errorf(errors.Codes.ReservedAddress,
    72  			"cannot %s at %v because that address is reserved for a native contract '%s'",
    73  			action, address, contract.FullName())
    74  	}
    75  	return nil
    76  }
    77  
    78  func account(callable engine.Native) *acm.Account {
    79  	return &acm.Account{
    80  		Address:    callable.Address(),
    81  		NativeName: callable.FullName(),
    82  		// TODO: this is not populated yet, see FIXME note on native.Contract
    83  		ContractMeta: callable.ContractMeta(),
    84  	}
    85  }