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