github.com/onflow/flow-go@v0.33.17/fvm/storage/state/execution_state.go (about)

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