github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/fvm/environment/value_store.go (about)

     1  package environment
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/onflow/atree"
     7  
     8  	"github.com/onflow/flow-go/fvm/errors"
     9  	"github.com/onflow/flow-go/fvm/storage/state"
    10  	"github.com/onflow/flow-go/fvm/tracing"
    11  	"github.com/onflow/flow-go/model/flow"
    12  	"github.com/onflow/flow-go/module/trace"
    13  )
    14  
    15  // ValueStore provides read/write access to the account storage.
    16  type ValueStore interface {
    17  	GetValue(owner []byte, key []byte) ([]byte, error)
    18  
    19  	SetValue(owner, key, value []byte) error
    20  
    21  	ValueExists(owner []byte, key []byte) (bool, error)
    22  
    23  	AllocateSlabIndex(owner []byte) (atree.SlabIndex, error)
    24  }
    25  
    26  type ParseRestrictedValueStore struct {
    27  	txnState state.NestedTransactionPreparer
    28  	impl     ValueStore
    29  }
    30  
    31  func NewParseRestrictedValueStore(
    32  	txnState state.NestedTransactionPreparer,
    33  	impl ValueStore,
    34  ) ValueStore {
    35  	return ParseRestrictedValueStore{
    36  		txnState: txnState,
    37  		impl:     impl,
    38  	}
    39  }
    40  
    41  func (store ParseRestrictedValueStore) GetValue(
    42  	owner []byte,
    43  	key []byte,
    44  ) (
    45  	[]byte,
    46  	error,
    47  ) {
    48  	return parseRestrict2Arg1Ret(
    49  		store.txnState,
    50  		trace.FVMEnvGetValue,
    51  		store.impl.GetValue,
    52  		owner,
    53  		key)
    54  }
    55  
    56  func (store ParseRestrictedValueStore) SetValue(
    57  	owner []byte,
    58  	key []byte,
    59  	value []byte,
    60  ) error {
    61  	return parseRestrict3Arg(
    62  		store.txnState,
    63  		trace.FVMEnvSetValue,
    64  		store.impl.SetValue,
    65  		owner,
    66  		key,
    67  		value)
    68  }
    69  
    70  func (store ParseRestrictedValueStore) ValueExists(
    71  	owner []byte,
    72  	key []byte,
    73  ) (
    74  	bool,
    75  	error,
    76  ) {
    77  	return parseRestrict2Arg1Ret(
    78  		store.txnState,
    79  		trace.FVMEnvValueExists,
    80  		store.impl.ValueExists,
    81  		owner,
    82  		key)
    83  }
    84  
    85  func (store ParseRestrictedValueStore) AllocateSlabIndex(
    86  	owner []byte,
    87  ) (
    88  	atree.SlabIndex,
    89  	error,
    90  ) {
    91  	return parseRestrict1Arg1Ret(
    92  		store.txnState,
    93  		trace.FVMEnvAllocateStorageIndex,
    94  		store.impl.AllocateSlabIndex,
    95  		owner)
    96  }
    97  
    98  type valueStore struct {
    99  	tracer tracing.TracerSpan
   100  	meter  Meter
   101  
   102  	accounts Accounts
   103  }
   104  
   105  func NewValueStore(
   106  	tracer tracing.TracerSpan,
   107  	meter Meter,
   108  	accounts Accounts,
   109  ) ValueStore {
   110  	return &valueStore{
   111  		tracer:   tracer,
   112  		meter:    meter,
   113  		accounts: accounts,
   114  	}
   115  }
   116  
   117  func (store *valueStore) GetValue(
   118  	owner []byte,
   119  	keyBytes []byte,
   120  ) (
   121  	[]byte,
   122  	error,
   123  ) {
   124  	defer store.tracer.StartChildSpan(trace.FVMEnvGetValue).End()
   125  
   126  	id := flow.CadenceRegisterID(owner, keyBytes)
   127  	if id.IsInternalState() {
   128  		return nil, errors.NewInvalidInternalStateAccessError(id, "read")
   129  	}
   130  
   131  	v, err := store.accounts.GetValue(id)
   132  	if err != nil {
   133  		return nil, fmt.Errorf("get value failed: %w", err)
   134  	}
   135  
   136  	err = store.meter.MeterComputation(ComputationKindGetValue, uint(len(v)))
   137  	if err != nil {
   138  		return nil, fmt.Errorf("get value failed: %w", err)
   139  	}
   140  	return v, nil
   141  }
   142  
   143  // TODO disable SetValue for scripts, right now the view changes are discarded
   144  func (store *valueStore) SetValue(
   145  	owner []byte,
   146  	keyBytes []byte,
   147  	value []byte,
   148  ) error {
   149  	defer store.tracer.StartChildSpan(trace.FVMEnvSetValue).End()
   150  
   151  	id := flow.CadenceRegisterID(owner, keyBytes)
   152  	if id.IsInternalState() {
   153  		return errors.NewInvalidInternalStateAccessError(id, "modify")
   154  	}
   155  
   156  	err := store.meter.MeterComputation(
   157  		ComputationKindSetValue,
   158  		uint(len(value)))
   159  	if err != nil {
   160  		return fmt.Errorf("set value failed: %w", err)
   161  	}
   162  
   163  	err = store.accounts.SetValue(id, value)
   164  	if err != nil {
   165  		return fmt.Errorf("set value failed: %w", err)
   166  	}
   167  	return nil
   168  }
   169  
   170  func (store *valueStore) ValueExists(
   171  	owner []byte,
   172  	key []byte,
   173  ) (
   174  	exists bool,
   175  	err error,
   176  ) {
   177  	defer store.tracer.StartChildSpan(trace.FVMEnvValueExists).End()
   178  
   179  	err = store.meter.MeterComputation(ComputationKindValueExists, 1)
   180  	if err != nil {
   181  		return false, fmt.Errorf("check value existence failed: %w", err)
   182  	}
   183  
   184  	v, err := store.GetValue(owner, key)
   185  	if err != nil {
   186  		return false, fmt.Errorf("check value existence failed: %w", err)
   187  	}
   188  
   189  	return len(v) > 0, nil
   190  }
   191  
   192  // AllocateSlabIndex allocates new storage index under the owner accounts
   193  // to store a new register.
   194  func (store *valueStore) AllocateSlabIndex(
   195  	owner []byte,
   196  ) (
   197  	atree.SlabIndex,
   198  	error,
   199  ) {
   200  	defer store.tracer.StartChildSpan(trace.FVMEnvAllocateStorageIndex).End()
   201  
   202  	err := store.meter.MeterComputation(ComputationKindAllocateStorageIndex, 1)
   203  	if err != nil {
   204  		return atree.SlabIndex{}, fmt.Errorf(
   205  			"allocate storage index failed: %w",
   206  			err)
   207  	}
   208  
   209  	v, err := store.accounts.AllocateSlabIndex(flow.BytesToAddress(owner))
   210  	if err != nil {
   211  		return atree.SlabIndex{}, fmt.Errorf(
   212  			"storage address allocation failed: %w",
   213  			err)
   214  	}
   215  	return v, nil
   216  }