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

     1  package derived
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/onflow/cadence/runtime/common"
     7  	"github.com/onflow/cadence/runtime/interpreter"
     8  
     9  	"github.com/onflow/flow-go/fvm/storage/logical"
    10  	"github.com/onflow/flow-go/fvm/storage/state"
    11  )
    12  
    13  type DerivedTransactionPreparer interface {
    14  	GetOrComputeProgram(
    15  		txState state.NestedTransactionPreparer,
    16  		addressLocation common.AddressLocation,
    17  		programComputer ValueComputer[common.AddressLocation, *Program],
    18  	) (
    19  		*Program,
    20  		error,
    21  	)
    22  	GetProgram(location common.AddressLocation) (*Program, bool)
    23  
    24  	GetMeterParamOverrides(
    25  		txnState state.NestedTransactionPreparer,
    26  		getMeterParamOverrides ValueComputer[struct{}, MeterParamOverrides],
    27  	) (
    28  		MeterParamOverrides,
    29  		error,
    30  	)
    31  
    32  	AddInvalidator(invalidator TransactionInvalidator)
    33  }
    34  
    35  type Program struct {
    36  	*interpreter.Program
    37  
    38  	Dependencies ProgramDependencies
    39  }
    40  
    41  // DerivedBlockData is a simple fork-aware OCC database for "caching" derived
    42  // data for a particular block.
    43  type DerivedBlockData struct {
    44  	programs *DerivedDataTable[common.AddressLocation, *Program]
    45  
    46  	meterParamOverrides *DerivedDataTable[struct{}, MeterParamOverrides]
    47  }
    48  
    49  // DerivedTransactionData is the derived data scratch space for a single
    50  // transaction.
    51  type DerivedTransactionData struct {
    52  	programs *TableTransaction[
    53  		common.AddressLocation,
    54  		*Program,
    55  	]
    56  
    57  	// There's only a single entry in this table.  For simplicity, we'll use
    58  	// struct{} as the entry's key.
    59  	meterParamOverrides *TableTransaction[struct{}, MeterParamOverrides]
    60  }
    61  
    62  func NewEmptyDerivedBlockData(
    63  	initialSnapshotTime logical.Time,
    64  ) *DerivedBlockData {
    65  	return &DerivedBlockData{
    66  		programs: NewEmptyTable[
    67  			common.AddressLocation,
    68  			*Program,
    69  		](initialSnapshotTime),
    70  		meterParamOverrides: NewEmptyTable[
    71  			struct{},
    72  			MeterParamOverrides,
    73  		](initialSnapshotTime),
    74  	}
    75  }
    76  
    77  func (block *DerivedBlockData) NewChildDerivedBlockData() *DerivedBlockData {
    78  	return &DerivedBlockData{
    79  		programs:            block.programs.NewChildTable(),
    80  		meterParamOverrides: block.meterParamOverrides.NewChildTable(),
    81  	}
    82  }
    83  
    84  func (block *DerivedBlockData) NewSnapshotReadDerivedTransactionData() *DerivedTransactionData {
    85  	return &DerivedTransactionData{
    86  		programs:            block.programs.NewSnapshotReadTableTransaction(),
    87  		meterParamOverrides: block.meterParamOverrides.NewSnapshotReadTableTransaction(),
    88  	}
    89  }
    90  
    91  func (block *DerivedBlockData) NewCachingSnapshotReadDerivedTransactionData() *DerivedTransactionData {
    92  	return &DerivedTransactionData{
    93  		programs:            block.programs.NewCachingSnapshotReadTableTransaction(),
    94  		meterParamOverrides: block.meterParamOverrides.NewCachingSnapshotReadTableTransaction(),
    95  	}
    96  }
    97  
    98  func (block *DerivedBlockData) NewDerivedTransactionData(
    99  	snapshotTime logical.Time,
   100  	executionTime logical.Time,
   101  ) (
   102  	*DerivedTransactionData,
   103  	error,
   104  ) {
   105  	txnPrograms, err := block.programs.NewTableTransaction(
   106  		snapshotTime,
   107  		executionTime)
   108  	if err != nil {
   109  		return nil, err
   110  	}
   111  
   112  	txnMeterParamOverrides, err := block.meterParamOverrides.NewTableTransaction(
   113  		snapshotTime,
   114  		executionTime)
   115  	if err != nil {
   116  		return nil, err
   117  	}
   118  
   119  	return &DerivedTransactionData{
   120  		programs:            txnPrograms,
   121  		meterParamOverrides: txnMeterParamOverrides,
   122  	}, nil
   123  }
   124  
   125  func (block *DerivedBlockData) NextTxIndexForTestingOnly() uint32 {
   126  	// NOTE: We can use next tx index from any table since they are identical.
   127  	return block.programs.NextTxIndexForTestingOnly()
   128  }
   129  
   130  func (block *DerivedBlockData) GetProgramForTestingOnly(
   131  	addressLocation common.AddressLocation,
   132  ) *invalidatableEntry[*Program] {
   133  	return block.programs.GetForTestingOnly(addressLocation)
   134  }
   135  
   136  // CachedPrograms returns the number of programs cached.
   137  // Note: this should only be called after calling commit, otherwise
   138  // the count will contain invalidated entries.
   139  func (block *DerivedBlockData) CachedPrograms() int {
   140  	return len(block.programs.items)
   141  }
   142  
   143  func (transaction *DerivedTransactionData) GetOrComputeProgram(
   144  	txState state.NestedTransactionPreparer,
   145  	addressLocation common.AddressLocation,
   146  	programComputer ValueComputer[common.AddressLocation, *Program],
   147  ) (
   148  	*Program,
   149  	error,
   150  ) {
   151  	return transaction.programs.GetOrCompute(
   152  		txState,
   153  		addressLocation,
   154  		programComputer)
   155  }
   156  
   157  // GetProgram returns the program for the given address location.
   158  // This does NOT apply reads/metering to any nested transaction.
   159  // Use with caution!
   160  func (transaction *DerivedTransactionData) GetProgram(
   161  	location common.AddressLocation,
   162  ) (
   163  	*Program,
   164  	bool,
   165  ) {
   166  	program, _, ok := transaction.programs.get(location)
   167  	return program, ok
   168  }
   169  
   170  func (transaction *DerivedTransactionData) AddInvalidator(
   171  	invalidator TransactionInvalidator,
   172  ) {
   173  	if invalidator == nil {
   174  		return
   175  	}
   176  
   177  	transaction.programs.AddInvalidator(invalidator.ProgramInvalidator())
   178  	transaction.meterParamOverrides.AddInvalidator(
   179  		invalidator.MeterParamOverridesInvalidator())
   180  }
   181  
   182  func (transaction *DerivedTransactionData) GetMeterParamOverrides(
   183  	txnState state.NestedTransactionPreparer,
   184  	getMeterParamOverrides ValueComputer[struct{}, MeterParamOverrides],
   185  ) (
   186  	MeterParamOverrides,
   187  	error,
   188  ) {
   189  	return transaction.meterParamOverrides.GetOrCompute(
   190  		txnState,
   191  		struct{}{},
   192  		getMeterParamOverrides)
   193  }
   194  
   195  func (transaction *DerivedTransactionData) Validate() error {
   196  	err := transaction.programs.Validate()
   197  	if err != nil {
   198  		return fmt.Errorf("programs validate failed: %w", err)
   199  	}
   200  
   201  	err = transaction.meterParamOverrides.Validate()
   202  	if err != nil {
   203  		return fmt.Errorf("meter param overrides validate failed: %w", err)
   204  	}
   205  
   206  	return nil
   207  }
   208  
   209  func (transaction *DerivedTransactionData) Commit() error {
   210  	err := transaction.programs.Commit()
   211  	if err != nil {
   212  		return fmt.Errorf("programs commit failed: %w", err)
   213  	}
   214  
   215  	err = transaction.meterParamOverrides.Commit()
   216  	if err != nil {
   217  		return fmt.Errorf("meter param overrides commit failed: %w", err)
   218  	}
   219  
   220  	return nil
   221  }