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

     1  package fvm
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  
     7  	"github.com/onflow/cadence"
     8  	"github.com/onflow/cadence/runtime"
     9  	"github.com/onflow/cadence/runtime/common"
    10  
    11  	"github.com/koko1123/flow-go-1/fvm/derived"
    12  	"github.com/koko1123/flow-go-1/fvm/environment"
    13  	"github.com/koko1123/flow-go-1/fvm/errors"
    14  	"github.com/koko1123/flow-go-1/fvm/state"
    15  	"github.com/koko1123/flow-go-1/model/flow"
    16  	"github.com/koko1123/flow-go-1/model/hash"
    17  )
    18  
    19  type ScriptProcedure struct {
    20  	ID             flow.Identifier
    21  	Script         []byte
    22  	Arguments      [][]byte
    23  	RequestContext context.Context
    24  	Value          cadence.Value
    25  	Logs           []string
    26  	Events         []flow.Event
    27  	GasUsed        uint64
    28  	MemoryEstimate uint64
    29  	Err            errors.CodedError
    30  }
    31  
    32  func Script(code []byte) *ScriptProcedure {
    33  	scriptHash := hash.DefaultHasher.ComputeHash(code)
    34  
    35  	return &ScriptProcedure{
    36  		Script:         code,
    37  		ID:             flow.HashToID(scriptHash),
    38  		RequestContext: context.Background(),
    39  	}
    40  }
    41  
    42  func (proc *ScriptProcedure) WithArguments(args ...[]byte) *ScriptProcedure {
    43  	return &ScriptProcedure{
    44  		ID:             proc.ID,
    45  		Script:         proc.Script,
    46  		RequestContext: proc.RequestContext,
    47  		Arguments:      args,
    48  	}
    49  }
    50  
    51  func (proc *ScriptProcedure) WithRequestContext(
    52  	reqContext context.Context,
    53  ) *ScriptProcedure {
    54  	return &ScriptProcedure{
    55  		ID:             proc.ID,
    56  		Script:         proc.Script,
    57  		RequestContext: reqContext,
    58  		Arguments:      proc.Arguments,
    59  	}
    60  }
    61  
    62  func NewScriptWithContextAndArgs(
    63  	code []byte,
    64  	reqContext context.Context,
    65  	args ...[]byte,
    66  ) *ScriptProcedure {
    67  	scriptHash := hash.DefaultHasher.ComputeHash(code)
    68  	return &ScriptProcedure{
    69  		ID:             flow.HashToID(scriptHash),
    70  		Script:         code,
    71  		RequestContext: reqContext,
    72  		Arguments:      args,
    73  	}
    74  }
    75  
    76  func (proc *ScriptProcedure) NewExecutor(
    77  	ctx Context,
    78  	txnState *state.TransactionState,
    79  	derivedTxnData *derived.DerivedTransactionData,
    80  ) ProcedureExecutor {
    81  	return newScriptExecutor(ctx, proc, txnState, derivedTxnData)
    82  }
    83  
    84  func (proc *ScriptProcedure) ComputationLimit(ctx Context) uint64 {
    85  	computationLimit := ctx.ComputationLimit
    86  	// if ctx.ComputationLimit is also zero, fallback to the default computation limit
    87  	if computationLimit == 0 {
    88  		computationLimit = DefaultComputationLimit
    89  	}
    90  	return computationLimit
    91  }
    92  
    93  func (proc *ScriptProcedure) MemoryLimit(ctx Context) uint64 {
    94  	memoryLimit := ctx.MemoryLimit
    95  	// if ctx.MemoryLimit is also zero, fallback to the default memory limit
    96  	if memoryLimit == 0 {
    97  		memoryLimit = DefaultMemoryLimit
    98  	}
    99  	return memoryLimit
   100  }
   101  
   102  func (proc *ScriptProcedure) ShouldDisableMemoryAndInteractionLimits(
   103  	ctx Context,
   104  ) bool {
   105  	return ctx.DisableMemoryAndInteractionLimits
   106  }
   107  
   108  func (ScriptProcedure) Type() ProcedureType {
   109  	return ScriptProcedureType
   110  }
   111  
   112  func (proc *ScriptProcedure) InitialSnapshotTime() derived.LogicalTime {
   113  	return derived.EndOfBlockExecutionTime
   114  }
   115  
   116  func (proc *ScriptProcedure) ExecutionTime() derived.LogicalTime {
   117  	return derived.EndOfBlockExecutionTime
   118  }
   119  
   120  type scriptExecutor struct {
   121  	ctx            Context
   122  	proc           *ScriptProcedure
   123  	txnState       *state.TransactionState
   124  	derivedTxnData *derived.DerivedTransactionData
   125  
   126  	env environment.Environment
   127  }
   128  
   129  func newScriptExecutor(
   130  	ctx Context,
   131  	proc *ScriptProcedure,
   132  	txnState *state.TransactionState,
   133  	derivedTxnData *derived.DerivedTransactionData,
   134  ) *scriptExecutor {
   135  	return &scriptExecutor{
   136  		ctx:            ctx,
   137  		proc:           proc,
   138  		txnState:       txnState,
   139  		derivedTxnData: derivedTxnData,
   140  		env: environment.NewScriptEnvironment(
   141  			proc.RequestContext,
   142  			ctx.TracerSpan,
   143  			ctx.EnvironmentParams,
   144  			txnState,
   145  			derivedTxnData),
   146  	}
   147  }
   148  
   149  func (executor *scriptExecutor) Cleanup() {
   150  	// Do nothing.
   151  }
   152  
   153  func (executor *scriptExecutor) Preprocess() error {
   154  	// Do nothing.
   155  	return nil
   156  }
   157  
   158  func (executor *scriptExecutor) Execute() error {
   159  	err := executor.execute()
   160  	txError, failure := errors.SplitErrorTypes(err)
   161  	if failure != nil {
   162  		if errors.IsLedgerFailure(failure) {
   163  			return fmt.Errorf(
   164  				"cannot execute the script, this error usually happens if "+
   165  					"the reference block for this script is not set to a "+
   166  					"recent block: %w",
   167  				failure)
   168  		}
   169  		return failure
   170  	}
   171  	if txError != nil {
   172  		executor.proc.Err = txError
   173  	}
   174  
   175  	return nil
   176  }
   177  
   178  func (executor *scriptExecutor) execute() error {
   179  	meterParams, err := getBodyMeterParameters(
   180  		executor.ctx,
   181  		executor.proc,
   182  		executor.txnState,
   183  		executor.derivedTxnData)
   184  	if err != nil {
   185  		return fmt.Errorf("error gettng meter parameters: %w", err)
   186  	}
   187  
   188  	txnId, err := executor.txnState.BeginNestedTransactionWithMeterParams(
   189  		meterParams)
   190  	if err != nil {
   191  		return err
   192  	}
   193  
   194  	rt := executor.env.BorrowCadenceRuntime()
   195  	defer executor.env.ReturnCadenceRuntime(rt)
   196  
   197  	value, err := rt.ExecuteScript(
   198  		runtime.Script{
   199  			Source:    executor.proc.Script,
   200  			Arguments: executor.proc.Arguments,
   201  		},
   202  		common.ScriptLocation(executor.proc.ID))
   203  
   204  	if err != nil {
   205  		return err
   206  	}
   207  
   208  	executor.proc.Value = value
   209  	executor.proc.Logs = executor.env.Logs()
   210  	executor.proc.Events = executor.env.Events()
   211  	executor.proc.GasUsed = executor.env.ComputationUsed()
   212  	executor.proc.MemoryEstimate = executor.env.MemoryEstimate()
   213  
   214  	_, err = executor.txnState.Commit(txnId)
   215  	return err
   216  }