github.com/onflow/flow-go@v0.33.17/engine/execution/computation/manager.go (about)

     1  package computation
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  
     7  	"github.com/onflow/cadence/runtime"
     8  	"github.com/rs/zerolog"
     9  
    10  	"github.com/onflow/flow-go/engine/execution"
    11  	"github.com/onflow/flow-go/engine/execution/computation/computer"
    12  	"github.com/onflow/flow-go/engine/execution/computation/query"
    13  	"github.com/onflow/flow-go/fvm"
    14  	reusableRuntime "github.com/onflow/flow-go/fvm/runtime"
    15  	"github.com/onflow/flow-go/fvm/storage/derived"
    16  	"github.com/onflow/flow-go/fvm/storage/snapshot"
    17  	"github.com/onflow/flow-go/model/flow"
    18  	"github.com/onflow/flow-go/module"
    19  	"github.com/onflow/flow-go/module/executiondatasync/provider"
    20  	"github.com/onflow/flow-go/module/mempool/entity"
    21  	"github.com/onflow/flow-go/state/protocol"
    22  	"github.com/onflow/flow-go/utils/logging"
    23  )
    24  
    25  const (
    26  	ReusableCadenceRuntimePoolSize = 1000
    27  )
    28  
    29  type ComputationManager interface {
    30  	ExecuteScript(
    31  		ctx context.Context,
    32  		script []byte,
    33  		arguments [][]byte,
    34  		blockHeader *flow.Header,
    35  		snapshot snapshot.StorageSnapshot,
    36  	) (
    37  		[]byte,
    38  		error,
    39  	)
    40  
    41  	ComputeBlock(
    42  		ctx context.Context,
    43  		parentBlockExecutionResultID flow.Identifier,
    44  		block *entity.ExecutableBlock,
    45  		snapshot snapshot.StorageSnapshot,
    46  	) (
    47  		*execution.ComputationResult,
    48  		error,
    49  	)
    50  
    51  	GetAccount(
    52  		ctx context.Context,
    53  		addr flow.Address,
    54  		header *flow.Header,
    55  		snapshot snapshot.StorageSnapshot,
    56  	) (
    57  		*flow.Account,
    58  		error,
    59  	)
    60  }
    61  
    62  type ComputationConfig struct {
    63  	query.QueryConfig
    64  	CadenceTracing       bool
    65  	ExtensiveTracing     bool
    66  	DerivedDataCacheSize uint
    67  	MaxConcurrency       int
    68  
    69  	// When NewCustomVirtualMachine is nil, the manager will create a standard
    70  	// fvm virtual machine via fvm.NewVirtualMachine.  Otherwise, the manager
    71  	// will create a virtual machine using this function.
    72  	//
    73  	// Note that this is primarily used for testing.
    74  	NewCustomVirtualMachine func() fvm.VM
    75  }
    76  
    77  // Manager manages computation and execution
    78  type Manager struct {
    79  	log              zerolog.Logger
    80  	vm               fvm.VM
    81  	blockComputer    computer.BlockComputer
    82  	queryExecutor    query.Executor
    83  	derivedChainData *derived.DerivedChainData
    84  }
    85  
    86  var _ ComputationManager = &Manager{}
    87  
    88  func New(
    89  	logger zerolog.Logger,
    90  	metrics module.ExecutionMetrics,
    91  	tracer module.Tracer,
    92  	me module.Local,
    93  	protoState protocol.State,
    94  	vmCtx fvm.Context,
    95  	committer computer.ViewCommitter,
    96  	executionDataProvider provider.Provider,
    97  	params ComputationConfig,
    98  ) (*Manager, error) {
    99  	log := logger.With().Str("engine", "computation").Logger()
   100  
   101  	var vm fvm.VM
   102  	if params.NewCustomVirtualMachine != nil {
   103  		vm = params.NewCustomVirtualMachine()
   104  	} else {
   105  		vm = fvm.NewVirtualMachine()
   106  	}
   107  
   108  	chainID := vmCtx.Chain.ChainID()
   109  	options := DefaultFVMOptions(chainID, params.CadenceTracing, params.ExtensiveTracing)
   110  	vmCtx = fvm.NewContextFromParent(vmCtx, options...)
   111  
   112  	blockComputer, err := computer.NewBlockComputer(
   113  		vm,
   114  		vmCtx,
   115  		metrics,
   116  		tracer,
   117  		log.With().Str("component", "block_computer").Logger(),
   118  		committer,
   119  		me,
   120  		executionDataProvider,
   121  		nil, // TODO(ramtin): update me with proper consumers
   122  		protoState,
   123  		params.MaxConcurrency,
   124  	)
   125  
   126  	if err != nil {
   127  		return nil, fmt.Errorf("cannot create block computer: %w", err)
   128  	}
   129  
   130  	derivedChainData, err := derived.NewDerivedChainData(params.DerivedDataCacheSize)
   131  	if err != nil {
   132  		return nil, fmt.Errorf("cannot create derived data cache: %w", err)
   133  	}
   134  
   135  	queryExecutor := query.NewQueryExecutor(
   136  		params.QueryConfig,
   137  		logger,
   138  		metrics,
   139  		vm,
   140  		vmCtx,
   141  		derivedChainData,
   142  		query.NewProtocolStateWrapper(protoState),
   143  	)
   144  
   145  	e := Manager{
   146  		log:              log,
   147  		vm:               vm,
   148  		blockComputer:    blockComputer,
   149  		queryExecutor:    queryExecutor,
   150  		derivedChainData: derivedChainData,
   151  	}
   152  
   153  	return &e, nil
   154  }
   155  
   156  func (e *Manager) VM() fvm.VM {
   157  	return e.vm
   158  }
   159  
   160  func (e *Manager) ComputeBlock(
   161  	ctx context.Context,
   162  	parentBlockExecutionResultID flow.Identifier,
   163  	block *entity.ExecutableBlock,
   164  	snapshot snapshot.StorageSnapshot,
   165  ) (*execution.ComputationResult, error) {
   166  
   167  	e.log.Debug().
   168  		Hex("block_id", logging.Entity(block.Block)).
   169  		Msg("received complete block")
   170  
   171  	derivedBlockData := e.derivedChainData.GetOrCreateDerivedBlockData(
   172  		block.ID(),
   173  		block.ParentID())
   174  
   175  	result, err := e.blockComputer.ExecuteBlock(
   176  		ctx,
   177  		parentBlockExecutionResultID,
   178  		block,
   179  		snapshot,
   180  		derivedBlockData)
   181  	if err != nil {
   182  		return nil, fmt.Errorf("failed to execute block: %w", err)
   183  	}
   184  
   185  	e.log.Debug().
   186  		Hex("block_id", logging.Entity(result.ExecutableBlock.Block)).
   187  		Msg("computed block result")
   188  
   189  	return result, nil
   190  }
   191  
   192  func (e *Manager) ExecuteScript(
   193  	ctx context.Context,
   194  	code []byte,
   195  	arguments [][]byte,
   196  	blockHeader *flow.Header,
   197  	snapshot snapshot.StorageSnapshot,
   198  ) ([]byte, error) {
   199  	return e.queryExecutor.ExecuteScript(ctx,
   200  		code,
   201  		arguments,
   202  		blockHeader,
   203  		snapshot)
   204  }
   205  
   206  func (e *Manager) GetAccount(
   207  	ctx context.Context,
   208  	address flow.Address,
   209  	blockHeader *flow.Header,
   210  	snapshot snapshot.StorageSnapshot,
   211  ) (
   212  	*flow.Account,
   213  	error,
   214  ) {
   215  	return e.queryExecutor.GetAccount(
   216  		ctx,
   217  		address,
   218  		blockHeader,
   219  		snapshot)
   220  }
   221  
   222  func (e *Manager) QueryExecutor() query.Executor {
   223  	return e.queryExecutor
   224  }
   225  
   226  func DefaultFVMOptions(chainID flow.ChainID, cadenceTracing bool, extensiveTracing bool) []fvm.Option {
   227  	options := []fvm.Option{
   228  		fvm.WithChain(chainID.Chain()),
   229  		fvm.WithReusableCadenceRuntimePool(
   230  			reusableRuntime.NewReusableCadenceRuntimePool(
   231  				ReusableCadenceRuntimePoolSize,
   232  				runtime.Config{
   233  					TracingEnabled:        cadenceTracing,
   234  					AccountLinkingEnabled: true,
   235  					// Attachments are enabled everywhere except for Mainnet
   236  					AttachmentsEnabled: chainID != flow.Mainnet,
   237  					// Capability Controllers are enabled everywhere except for Mainnet
   238  					CapabilityControllersEnabled: chainID != flow.Mainnet,
   239  				},
   240  			)),
   241  		fvm.WithEVMEnabled(true),
   242  	}
   243  
   244  	if extensiveTracing {
   245  		options = append(options, fvm.WithExtensiveTracing())
   246  	}
   247  
   248  	return options
   249  }