github.com/koko1123/flow-go-1@v0.29.6/fvm/state/state.go (about)

     1  package state
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/binary"
     6  	"encoding/hex"
     7  	"fmt"
     8  	"strings"
     9  
    10  	"github.com/onflow/cadence/runtime/common"
    11  	"golang.org/x/exp/slices"
    12  
    13  	"github.com/koko1123/flow-go-1/fvm/errors"
    14  	"github.com/koko1123/flow-go-1/fvm/meter"
    15  	"github.com/koko1123/flow-go-1/model/flow"
    16  )
    17  
    18  const (
    19  	DefaultMaxKeySize   = 16_000      // ~16KB
    20  	DefaultMaxValueSize = 256_000_000 // ~256MB
    21  
    22  	// Service level keys (owner is empty):
    23  	UUIDKey         = "uuid"
    24  	AddressStateKey = "account_address_state"
    25  
    26  	// Account level keys
    27  	AccountKeyPrefix   = "a."
    28  	AccountStatusKey   = AccountKeyPrefix + "s"
    29  	CodeKeyPrefix      = "code."
    30  	ContractNamesKey   = "contract_names"
    31  	PublicKeyKeyPrefix = "public_key_"
    32  )
    33  
    34  // State represents the execution state
    35  // it holds draft of updates and captures
    36  // all register touches
    37  type State struct {
    38  	// NOTE: A committed state is no longer accessible.  It can however be
    39  	// re-attached to another transaction and be committed (for cached result
    40  	// bookkeeping purpose).
    41  	committed bool
    42  
    43  	view             View
    44  	meter            *meter.Meter
    45  	updatedAddresses map[flow.Address]struct{}
    46  	stateLimits
    47  }
    48  
    49  type stateLimits struct {
    50  	maxKeySizeAllowed   uint64
    51  	maxValueSizeAllowed uint64
    52  }
    53  
    54  type StateParameters struct {
    55  	meter.MeterParameters
    56  
    57  	stateLimits
    58  }
    59  
    60  func DefaultParameters() StateParameters {
    61  	return StateParameters{
    62  		MeterParameters: meter.DefaultParameters(),
    63  		stateLimits: stateLimits{
    64  			maxKeySizeAllowed:   DefaultMaxKeySize,
    65  			maxValueSizeAllowed: DefaultMaxValueSize,
    66  		},
    67  	}
    68  }
    69  
    70  // WithMeterParameters sets the state's meter parameters
    71  func (params StateParameters) WithMeterParameters(
    72  	meterParams meter.MeterParameters,
    73  ) StateParameters {
    74  	newParams := params
    75  	newParams.MeterParameters = meterParams
    76  	return newParams
    77  }
    78  
    79  // WithMaxKeySizeAllowed sets limit on max key size
    80  func (params StateParameters) WithMaxKeySizeAllowed(limit uint64) StateParameters {
    81  	newParams := params
    82  	newParams.maxKeySizeAllowed = limit
    83  	return newParams
    84  }
    85  
    86  // WithMaxValueSizeAllowed sets limit on max value size
    87  func (params StateParameters) WithMaxValueSizeAllowed(limit uint64) StateParameters {
    88  	newParams := params
    89  	newParams.maxValueSizeAllowed = limit
    90  	return newParams
    91  }
    92  
    93  // TODO(patrick): rm once https://github.com/onflow/flow-emulator/pull/245
    94  // is integrated.
    95  //
    96  // WithMaxInteractionSizeAllowed sets limit on total byte interaction with ledger
    97  func (params StateParameters) WithMaxInteractionSizeAllowed(limit uint64) StateParameters {
    98  	newParams := params
    99  	newParams.MeterParameters = newParams.MeterParameters.WithStorageInteractionLimit(limit)
   100  	return newParams
   101  }
   102  
   103  func (s *State) View() View {
   104  	return s.view
   105  }
   106  
   107  func (s *State) Meter() *meter.Meter {
   108  	return s.meter
   109  }
   110  
   111  type StateOption func(st *State) *State
   112  
   113  // NewState constructs a new state
   114  func NewState(view View, params StateParameters) *State {
   115  	m := meter.NewMeter(params.MeterParameters)
   116  	return &State{
   117  		committed:        false,
   118  		view:             view,
   119  		meter:            m,
   120  		updatedAddresses: make(map[flow.Address]struct{}),
   121  		stateLimits:      params.stateLimits,
   122  	}
   123  }
   124  
   125  // NewChildWithMeterParams generates a new child state using the provide meter
   126  // parameters.
   127  func (s *State) NewChildWithMeterParams(
   128  	params meter.MeterParameters,
   129  ) *State {
   130  	return &State{
   131  		committed:        false,
   132  		view:             s.view.NewChild(),
   133  		meter:            meter.NewMeter(params),
   134  		updatedAddresses: make(map[flow.Address]struct{}),
   135  		stateLimits:      s.stateLimits,
   136  	}
   137  }
   138  
   139  // NewChild generates a new child state using the parent's meter parameters.
   140  func (s *State) NewChild() *State {
   141  	return s.NewChildWithMeterParams(s.meter.MeterParameters)
   142  }
   143  
   144  // InteractionUsed returns the amount of ledger interaction (total ledger byte read + total ledger byte written)
   145  func (s *State) InteractionUsed() uint64 {
   146  	return s.meter.TotalBytesOfStorageInteractions()
   147  }
   148  
   149  // RegisterUpdates returns the lists of register id / value that were updated.
   150  func (s *State) RegisterUpdates() ([]flow.RegisterID, []flow.RegisterValue) {
   151  	return s.view.RegisterUpdates()
   152  }
   153  
   154  // Get returns a register value given owner and key
   155  func (s *State) Get(owner, key string, enforceLimit bool) (flow.RegisterValue, error) {
   156  	if s.committed {
   157  		return nil, fmt.Errorf("cannot Get on a committed state")
   158  	}
   159  
   160  	var value []byte
   161  	var err error
   162  
   163  	if enforceLimit {
   164  		if err = s.checkSize(owner, key, []byte{}); err != nil {
   165  			return nil, err
   166  		}
   167  	}
   168  
   169  	if value, err = s.view.Get(owner, key); err != nil {
   170  		// wrap error into a fatal error
   171  		getError := errors.NewLedgerFailure(err)
   172  		// wrap with more info
   173  		return nil, fmt.Errorf("failed to read key %s on account %s: %w", PrintableKey(key), hex.EncodeToString([]byte(owner)), getError)
   174  	}
   175  
   176  	err = s.meter.MeterStorageRead(
   177  		meter.StorageInteractionKey{Owner: owner, Key: key},
   178  		value,
   179  		enforceLimit)
   180  
   181  	return value, err
   182  }
   183  
   184  // Set updates state delta with a register update
   185  func (s *State) Set(owner, key string, value flow.RegisterValue, enforceLimit bool) error {
   186  	if s.committed {
   187  		return fmt.Errorf("cannot Set on a committed state")
   188  	}
   189  
   190  	if enforceLimit {
   191  		if err := s.checkSize(owner, key, value); err != nil {
   192  			return err
   193  		}
   194  	}
   195  
   196  	if err := s.view.Set(owner, key, value); err != nil {
   197  		// wrap error into a fatal error
   198  		setError := errors.NewLedgerFailure(err)
   199  		// wrap with more info
   200  		return fmt.Errorf("failed to update key %s on account %s: %w", PrintableKey(key), hex.EncodeToString([]byte(owner)), setError)
   201  	}
   202  
   203  	err := s.meter.MeterStorageWrite(
   204  		meter.StorageInteractionKey{Owner: owner, Key: key},
   205  		value,
   206  		enforceLimit,
   207  	)
   208  	if err != nil {
   209  		return err
   210  	}
   211  
   212  	if address, isAddress := addressFromOwner(owner); isAddress {
   213  		s.updatedAddresses[address] = struct{}{}
   214  	}
   215  
   216  	return nil
   217  }
   218  
   219  // MeterComputation meters computation usage
   220  func (s *State) MeterComputation(kind common.ComputationKind, intensity uint) error {
   221  	if s.committed {
   222  		return fmt.Errorf("cannot MeterComputation on a committed state")
   223  	}
   224  
   225  	return s.meter.MeterComputation(kind, intensity)
   226  }
   227  
   228  // TotalComputationUsed returns total computation used
   229  func (s *State) TotalComputationUsed() uint64 {
   230  	return s.meter.TotalComputationUsed()
   231  }
   232  
   233  // ComputationIntensities returns computation intensities
   234  func (s *State) ComputationIntensities() meter.MeteredComputationIntensities {
   235  	return s.meter.ComputationIntensities()
   236  }
   237  
   238  // TotalComputationLimit returns total computation limit
   239  func (s *State) TotalComputationLimit() uint {
   240  	return s.meter.TotalComputationLimit()
   241  }
   242  
   243  // MeterMemory meters memory usage
   244  func (s *State) MeterMemory(kind common.MemoryKind, intensity uint) error {
   245  	if s.committed {
   246  		return fmt.Errorf("cannot MeterMemory on a committed state")
   247  	}
   248  
   249  	return s.meter.MeterMemory(kind, intensity)
   250  }
   251  
   252  // MemoryIntensities returns computation intensities
   253  func (s *State) MemoryIntensities() meter.MeteredMemoryIntensities {
   254  	return s.meter.MemoryIntensities()
   255  }
   256  
   257  // TotalMemoryEstimate returns total memory used
   258  func (s *State) TotalMemoryEstimate() uint64 {
   259  	return s.meter.TotalMemoryEstimate()
   260  }
   261  
   262  // TotalMemoryLimit returns total memory limit
   263  func (s *State) TotalMemoryLimit() uint {
   264  	return uint(s.meter.TotalMemoryLimit())
   265  }
   266  
   267  func (s *State) MeterEmittedEvent(byteSize uint64) error {
   268  	if s.committed {
   269  		return fmt.Errorf("cannot MeterEmittedEvent on a committed state")
   270  	}
   271  
   272  	return s.meter.MeterEmittedEvent(byteSize)
   273  }
   274  
   275  func (s *State) TotalEmittedEventBytes() uint64 {
   276  	return s.meter.TotalEmittedEventBytes()
   277  }
   278  
   279  // MergeState applies the changes from a the given view to this view.
   280  func (s *State) MergeState(other *State) error {
   281  	if s.committed {
   282  		return fmt.Errorf("cannot MergeState on a committed state")
   283  	}
   284  
   285  	err := s.view.MergeView(other.view)
   286  	if err != nil {
   287  		return errors.NewStateMergeFailure(err)
   288  	}
   289  
   290  	s.meter.MergeMeter(other.meter)
   291  
   292  	// apply address updates
   293  	for k, v := range other.updatedAddresses {
   294  		s.updatedAddresses[k] = v
   295  	}
   296  
   297  	return nil
   298  }
   299  
   300  // UpdatedAddresses returns a sorted list of addresses that were updated (at least 1 register update)
   301  func (s *State) UpdatedAddresses() []flow.Address {
   302  	addresses := make([]flow.Address, 0, len(s.updatedAddresses))
   303  
   304  	for k := range s.updatedAddresses {
   305  		addresses = append(addresses, k)
   306  	}
   307  
   308  	slices.SortFunc(addresses, func(a, b flow.Address) bool {
   309  		// reverse order to maintain compatibility with previous implementation.
   310  		return bytes.Compare(a[:], b[:]) >= 0
   311  	})
   312  
   313  	return addresses
   314  }
   315  
   316  func (s *State) checkSize(owner, key string, value flow.RegisterValue) error {
   317  	keySize := uint64(len(owner) + len(key))
   318  	valueSize := uint64(len(value))
   319  	if keySize > s.maxKeySizeAllowed {
   320  		return errors.NewStateKeySizeLimitError(owner, key, keySize, s.maxKeySizeAllowed)
   321  	}
   322  	if valueSize > s.maxValueSizeAllowed {
   323  		return errors.NewStateValueSizeLimitError(value, valueSize, s.maxValueSizeAllowed)
   324  	}
   325  	return nil
   326  }
   327  
   328  func addressFromOwner(owner string) (flow.Address, bool) {
   329  	ownerBytes := []byte(owner)
   330  	if len(ownerBytes) != flow.AddressLength {
   331  		// not an address
   332  		return flow.EmptyAddress, false
   333  	}
   334  	address := flow.BytesToAddress(ownerBytes)
   335  	return address, true
   336  }
   337  
   338  // IsFVMStateKey returns true if the key is controlled by the fvm env and
   339  // return false otherwise (key controlled by the cadence env)
   340  func IsFVMStateKey(owner string, key string) bool {
   341  	// check if is a service level key (owner is empty)
   342  	// cases:
   343  	// 		- "", "uuid"
   344  	// 		- "", "account_address_state"
   345  	if len(owner) == 0 && (key == UUIDKey || key == AddressStateKey) {
   346  		return true
   347  	}
   348  
   349  	// check account level keys
   350  	// cases:
   351  	// 		- address, "contract_names"
   352  	// 		- address, "code.%s" (contract name)
   353  	// 		- address, "public_key_%d" (index)
   354  	// 		- address, "a.s" (account status)
   355  	return strings.HasPrefix(key, PublicKeyKeyPrefix) ||
   356  		key == ContractNamesKey ||
   357  		strings.HasPrefix(key, CodeKeyPrefix) ||
   358  		key == AccountStatusKey
   359  }
   360  
   361  // This returns true if the key is a slab index for an account's ordered fields
   362  // map.
   363  //
   364  // In general, each account's regular fields are stored in ordered map known
   365  // only to cadence.  Cadence encodes this map into bytes and split the bytes
   366  // into slab chunks before storing the slabs into the ledger.
   367  func IsSlabIndex(key string) bool {
   368  	return len(key) == 9 && key[0] == '$'
   369  }
   370  
   371  // PrintableKey formats slabs properly and avoids invalid utf8s
   372  func PrintableKey(key string) string {
   373  	// slab
   374  	if IsSlabIndex(key) {
   375  		i := uint64(binary.BigEndian.Uint64([]byte(key[1:])))
   376  		return fmt.Sprintf("$%d", i)
   377  	}
   378  	return fmt.Sprintf("#%x", []byte(key))
   379  }