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

     1  package state
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/onflow/cadence/runtime/common"
     7  	"github.com/onflow/crypto/hash"
     8  
     9  	"github.com/onflow/flow-go/fvm/errors"
    10  	"github.com/onflow/flow-go/fvm/meter"
    11  	"github.com/onflow/flow-go/fvm/storage/snapshot"
    12  	"github.com/onflow/flow-go/model/flow"
    13  )
    14  
    15  const (
    16  	DefaultMaxKeySize   = 16_000      // ~16KB
    17  	DefaultMaxValueSize = 256_000_000 // ~256MB
    18  )
    19  
    20  // State represents the execution state
    21  // it holds draft of updates and captures
    22  // all register touches
    23  type ExecutionState struct {
    24  	// NOTE: A finalized state is no longer accessible.  It can however be
    25  	// re-attached to another transaction and be committed (for cached result
    26  	// bookkeeping purpose).
    27  	finalized bool
    28  
    29  	*spockState
    30  	meter *meter.Meter
    31  
    32  	// NOTE: parent and child state shares the same limits controller
    33  	*limitsController
    34  }
    35  
    36  type StateParameters struct {
    37  	meter.MeterParameters
    38  
    39  	maxKeySizeAllowed   uint64
    40  	maxValueSizeAllowed uint64
    41  }
    42  
    43  func DefaultParameters() StateParameters {
    44  	return StateParameters{
    45  		MeterParameters:     meter.DefaultParameters(),
    46  		maxKeySizeAllowed:   DefaultMaxKeySize,
    47  		maxValueSizeAllowed: DefaultMaxValueSize,
    48  	}
    49  }
    50  
    51  // WithMeterParameters sets the state's meter parameters
    52  func (params StateParameters) WithMeterParameters(
    53  	meterParams meter.MeterParameters,
    54  ) StateParameters {
    55  	newParams := params
    56  	newParams.MeterParameters = meterParams
    57  	return newParams
    58  }
    59  
    60  // WithMaxKeySizeAllowed sets limit on max key size
    61  func (params StateParameters) WithMaxKeySizeAllowed(
    62  	limit uint64,
    63  ) StateParameters {
    64  	newParams := params
    65  	newParams.maxKeySizeAllowed = limit
    66  	return newParams
    67  }
    68  
    69  // WithMaxValueSizeAllowed sets limit on max value size
    70  func (params StateParameters) WithMaxValueSizeAllowed(
    71  	limit uint64,
    72  ) StateParameters {
    73  	newParams := params
    74  	newParams.maxValueSizeAllowed = limit
    75  	return newParams
    76  }
    77  
    78  type limitsController struct {
    79  	enforceLimits       bool
    80  	maxKeySizeAllowed   uint64
    81  	maxValueSizeAllowed uint64
    82  }
    83  
    84  func newLimitsController(params StateParameters) *limitsController {
    85  	return &limitsController{
    86  		enforceLimits:       true,
    87  		maxKeySizeAllowed:   params.maxKeySizeAllowed,
    88  		maxValueSizeAllowed: params.maxValueSizeAllowed,
    89  	}
    90  }
    91  
    92  func (controller *limitsController) RunWithAllLimitsDisabled(f func()) {
    93  	if f == nil {
    94  		return
    95  	}
    96  	current := controller.enforceLimits
    97  	controller.enforceLimits = false
    98  	f()
    99  	controller.enforceLimits = current
   100  }
   101  
   102  // NewExecutionState constructs a new state
   103  func NewExecutionState(
   104  	snapshot snapshot.StorageSnapshot,
   105  	params StateParameters,
   106  ) *ExecutionState {
   107  	return NewExecutionStateWithSpockStateHasher(
   108  		snapshot,
   109  		params,
   110  		DefaultSpockSecretHasher,
   111  	)
   112  }
   113  
   114  // NewExecutionStateWithSpockStateHasher constructs a new state with a custom hasher
   115  func NewExecutionStateWithSpockStateHasher(
   116  	snapshot snapshot.StorageSnapshot,
   117  	params StateParameters,
   118  	getHasher func() hash.Hasher,
   119  ) *ExecutionState {
   120  	m := meter.NewMeter(params.MeterParameters)
   121  	return &ExecutionState{
   122  		finalized:        false,
   123  		spockState:       newSpockState(snapshot, getHasher),
   124  		meter:            m,
   125  		limitsController: newLimitsController(params),
   126  	}
   127  }
   128  
   129  // NewChildWithMeterParams generates a new child state using the provide meter
   130  // parameters.
   131  func (state *ExecutionState) NewChildWithMeterParams(
   132  	params meter.MeterParameters,
   133  ) *ExecutionState {
   134  	return &ExecutionState{
   135  		finalized:        false,
   136  		spockState:       state.spockState.NewChild(),
   137  		meter:            meter.NewMeter(params),
   138  		limitsController: state.limitsController,
   139  	}
   140  }
   141  
   142  // NewChild generates a new child state using the parent's meter parameters.
   143  func (state *ExecutionState) NewChild() *ExecutionState {
   144  	return state.NewChildWithMeterParams(state.meter.MeterParameters)
   145  }
   146  
   147  // InteractionUsed returns the amount of ledger interaction (total ledger byte read + total ledger byte written)
   148  func (state *ExecutionState) InteractionUsed() uint64 {
   149  	return state.meter.TotalBytesOfStorageInteractions()
   150  }
   151  
   152  // BytesWritten returns the amount of total ledger bytes written
   153  func (state *ExecutionState) BytesWritten() uint64 {
   154  	return state.meter.TotalBytesWrittenToStorage()
   155  }
   156  
   157  func (state *ExecutionState) DropChanges() error {
   158  	if state.finalized {
   159  		return fmt.Errorf("cannot DropChanges on a finalized state")
   160  	}
   161  
   162  	return state.spockState.DropChanges()
   163  }
   164  
   165  // Get returns a register value given owner and key
   166  func (state *ExecutionState) Get(id flow.RegisterID) (flow.RegisterValue, error) {
   167  	if state.finalized {
   168  		return nil, fmt.Errorf("cannot Get on a finalized state")
   169  	}
   170  
   171  	var value []byte
   172  	var err error
   173  
   174  	if state.enforceLimits {
   175  		if err = state.checkSize(id, []byte{}); err != nil {
   176  			return nil, err
   177  		}
   178  	}
   179  
   180  	if value, err = state.spockState.Get(id); err != nil {
   181  		// wrap error into a fatal error
   182  		getError := errors.NewLedgerFailure(err)
   183  		// wrap with more info
   184  		return nil, fmt.Errorf("failed to read %s: %w", id, getError)
   185  	}
   186  
   187  	err = state.meter.MeterStorageRead(id, value, state.enforceLimits)
   188  	return value, err
   189  }
   190  
   191  // Set updates state delta with a register update
   192  func (state *ExecutionState) Set(id flow.RegisterID, value flow.RegisterValue) error {
   193  	if state.finalized {
   194  		return fmt.Errorf("cannot Set on a finalized state")
   195  	}
   196  
   197  	if state.enforceLimits {
   198  		if err := state.checkSize(id, value); err != nil {
   199  			return err
   200  		}
   201  	}
   202  
   203  	if err := state.spockState.Set(id, value); err != nil {
   204  		// wrap error into a fatal error
   205  		setError := errors.NewLedgerFailure(err)
   206  		// wrap with more info
   207  		return fmt.Errorf("failed to update %s: %w", id, setError)
   208  	}
   209  
   210  	return state.meter.MeterStorageWrite(id, value, state.enforceLimits)
   211  }
   212  
   213  // MeterComputation meters computation usage
   214  func (state *ExecutionState) MeterComputation(kind common.ComputationKind, intensity uint) error {
   215  	if state.finalized {
   216  		return fmt.Errorf("cannot MeterComputation on a finalized state")
   217  	}
   218  
   219  	if state.enforceLimits {
   220  		return state.meter.MeterComputation(kind, intensity)
   221  	}
   222  	return nil
   223  }
   224  
   225  // ComputationAvailable checks if enough computation capacity is available without metering
   226  func (state *ExecutionState) ComputationAvailable(kind common.ComputationKind, intensity uint) bool {
   227  	if state.finalized {
   228  		// if state is finalized return false
   229  		return false
   230  	}
   231  
   232  	if state.enforceLimits {
   233  		return state.meter.ComputationAvailable(kind, intensity)
   234  	}
   235  	return true
   236  }
   237  
   238  // TotalComputationUsed returns total computation used
   239  func (state *ExecutionState) TotalComputationUsed() uint64 {
   240  	return state.meter.TotalComputationUsed()
   241  }
   242  
   243  // ComputationIntensities returns computation intensities
   244  func (state *ExecutionState) ComputationIntensities() meter.MeteredComputationIntensities {
   245  	return state.meter.ComputationIntensities()
   246  }
   247  
   248  // TotalComputationLimit returns total computation limit
   249  func (state *ExecutionState) TotalComputationLimit() uint {
   250  	return state.meter.TotalComputationLimit()
   251  }
   252  
   253  // MeterMemory meters memory usage
   254  func (state *ExecutionState) MeterMemory(kind common.MemoryKind, intensity uint) error {
   255  	if state.finalized {
   256  		return fmt.Errorf("cannot MeterMemory on a finalized state")
   257  	}
   258  
   259  	if state.enforceLimits {
   260  		return state.meter.MeterMemory(kind, intensity)
   261  	}
   262  
   263  	return nil
   264  }
   265  
   266  // MemoryIntensities returns computation intensities
   267  func (state *ExecutionState) MemoryIntensities() meter.MeteredMemoryIntensities {
   268  	return state.meter.MemoryIntensities()
   269  }
   270  
   271  // TotalMemoryEstimate returns total memory used
   272  func (state *ExecutionState) TotalMemoryEstimate() uint64 {
   273  	return state.meter.TotalMemoryEstimate()
   274  }
   275  
   276  // TotalMemoryLimit returns total memory limit
   277  func (state *ExecutionState) TotalMemoryLimit() uint {
   278  	return uint(state.meter.TotalMemoryLimit())
   279  }
   280  
   281  func (state *ExecutionState) MeterEmittedEvent(byteSize uint64) error {
   282  	if state.finalized {
   283  		return fmt.Errorf("cannot MeterEmittedEvent on a finalized state")
   284  	}
   285  
   286  	if state.enforceLimits {
   287  		return state.meter.MeterEmittedEvent(byteSize)
   288  	}
   289  
   290  	return nil
   291  }
   292  
   293  func (state *ExecutionState) TotalEmittedEventBytes() uint64 {
   294  	return state.meter.TotalEmittedEventBytes()
   295  }
   296  
   297  func (state *ExecutionState) Finalize() *snapshot.ExecutionSnapshot {
   298  	state.finalized = true
   299  	snapshot := state.spockState.Finalize()
   300  	snapshot.Meter = state.meter
   301  	return snapshot
   302  }
   303  
   304  // MergeState the changes from a the given execution snapshot to this state.
   305  func (state *ExecutionState) Merge(other *snapshot.ExecutionSnapshot) error {
   306  	if state.finalized {
   307  		return fmt.Errorf("cannot Merge on a finalized state")
   308  	}
   309  
   310  	err := state.spockState.Merge(other)
   311  	if err != nil {
   312  		return errors.NewStateMergeFailure(err)
   313  	}
   314  
   315  	state.meter.MergeMeter(other.Meter)
   316  	return nil
   317  }
   318  
   319  func (state *ExecutionState) checkSize(
   320  	id flow.RegisterID,
   321  	value flow.RegisterValue,
   322  ) error {
   323  	keySize := uint64(len(id.Owner) + len(id.Key))
   324  	valueSize := uint64(len(value))
   325  	if keySize > state.maxKeySizeAllowed {
   326  		return errors.NewStateKeySizeLimitError(
   327  			id,
   328  			keySize,
   329  			state.maxKeySizeAllowed)
   330  	}
   331  	if valueSize > state.maxValueSizeAllowed {
   332  		return errors.NewStateValueSizeLimitError(
   333  			value,
   334  			valueSize,
   335  			state.maxValueSizeAllowed)
   336  	}
   337  	return nil
   338  }
   339  
   340  func (state *ExecutionState) readSetSize() int {
   341  	return state.spockState.readSetSize()
   342  }
   343  
   344  func (state *ExecutionState) interimReadSet(
   345  	accumulator map[flow.RegisterID]struct{},
   346  ) {
   347  	state.spockState.interimReadSet(accumulator)
   348  }