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

     1  package runtime
     2  
     3  import (
     4  	"github.com/onflow/cadence"
     5  	"github.com/onflow/cadence/runtime"
     6  	"github.com/onflow/cadence/runtime/common"
     7  	"github.com/onflow/cadence/runtime/interpreter"
     8  	"github.com/onflow/cadence/runtime/sema"
     9  	"github.com/onflow/cadence/runtime/stdlib"
    10  
    11  	"github.com/koko1123/flow-go-1/fvm/errors"
    12  )
    13  
    14  // Note: this is a subset of environment.Environment, redeclared to handle
    15  // circular dependency.
    16  type Environment interface {
    17  	runtime.Interface
    18  
    19  	SetAccountFrozen(address common.Address, frozen bool) error
    20  }
    21  
    22  var setAccountFrozenFunctionType = &sema.FunctionType{
    23  	Parameters: []sema.Parameter{
    24  		{
    25  			Label:          sema.ArgumentLabelNotRequired,
    26  			Identifier:     "account",
    27  			TypeAnnotation: sema.NewTypeAnnotation(sema.TheAddressType),
    28  		},
    29  		{
    30  			Label:          sema.ArgumentLabelNotRequired,
    31  			Identifier:     "frozen",
    32  			TypeAnnotation: sema.NewTypeAnnotation(sema.BoolType),
    33  		},
    34  	},
    35  	ReturnTypeAnnotation: sema.TypeAnnotation{
    36  		Type: sema.VoidType,
    37  	},
    38  }
    39  
    40  type ReusableCadenceRuntime struct {
    41  	runtime.Runtime
    42  	runtime.Environment
    43  
    44  	fvmEnv Environment
    45  }
    46  
    47  func NewReusableCadenceRuntime(rt runtime.Runtime, config runtime.Config) *ReusableCadenceRuntime {
    48  	reusable := &ReusableCadenceRuntime{
    49  		Runtime:     rt,
    50  		Environment: runtime.NewBaseInterpreterEnvironment(config),
    51  	}
    52  
    53  	setAccountFrozen := stdlib.StandardLibraryValue{
    54  		Name: "setAccountFrozen",
    55  		Type: setAccountFrozenFunctionType,
    56  		Kind: common.DeclarationKindFunction,
    57  		Value: interpreter.NewUnmeteredHostFunctionValue(
    58  			func(invocation interpreter.Invocation) interpreter.Value {
    59  				address, ok := invocation.Arguments[0].(interpreter.AddressValue)
    60  				if !ok {
    61  					panic(errors.NewValueErrorf(invocation.Arguments[0].String(),
    62  						"first argument of setAccountFrozen must be an address"))
    63  				}
    64  
    65  				frozen, ok := invocation.Arguments[1].(interpreter.BoolValue)
    66  				if !ok {
    67  					panic(errors.NewValueErrorf(invocation.Arguments[0].String(),
    68  						"second argument of setAccountFrozen must be a boolean"))
    69  				}
    70  
    71  				var err error
    72  				if reusable.fvmEnv != nil {
    73  					err = reusable.fvmEnv.SetAccountFrozen(
    74  						common.Address(address),
    75  						bool(frozen))
    76  				} else {
    77  					err = errors.NewOperationNotSupportedError("SetAccountFrozen")
    78  				}
    79  
    80  				if err != nil {
    81  					panic(err)
    82  				}
    83  
    84  				return interpreter.VoidValue{}
    85  			},
    86  			setAccountFrozenFunctionType,
    87  		),
    88  	}
    89  
    90  	reusable.Declare(setAccountFrozen)
    91  	return reusable
    92  }
    93  
    94  func (reusable *ReusableCadenceRuntime) SetFvmEnvironment(fvmEnv Environment) {
    95  	reusable.fvmEnv = fvmEnv
    96  }
    97  
    98  func (reusable *ReusableCadenceRuntime) ReadStored(
    99  	address common.Address,
   100  	path cadence.Path,
   101  ) (
   102  	cadence.Value,
   103  	error,
   104  ) {
   105  	return reusable.Runtime.ReadStored(
   106  		address,
   107  		path,
   108  		runtime.Context{
   109  			Interface:   reusable.fvmEnv,
   110  			Environment: reusable.Environment,
   111  		},
   112  	)
   113  }
   114  
   115  func (reusable *ReusableCadenceRuntime) InvokeContractFunction(
   116  	contractLocation common.AddressLocation,
   117  	functionName string,
   118  	arguments []cadence.Value,
   119  	argumentTypes []sema.Type,
   120  ) (
   121  	cadence.Value,
   122  	error,
   123  ) {
   124  	return reusable.Runtime.InvokeContractFunction(
   125  		contractLocation,
   126  		functionName,
   127  		arguments,
   128  		argumentTypes,
   129  		runtime.Context{
   130  			Interface:   reusable.fvmEnv,
   131  			Environment: reusable.Environment,
   132  		},
   133  	)
   134  }
   135  
   136  func (reusable *ReusableCadenceRuntime) NewTransactionExecutor(
   137  	script runtime.Script,
   138  	location common.Location,
   139  ) runtime.Executor {
   140  	return reusable.Runtime.NewTransactionExecutor(
   141  		script,
   142  		runtime.Context{
   143  			Interface:   reusable.fvmEnv,
   144  			Location:    location,
   145  			Environment: reusable.Environment,
   146  		},
   147  	)
   148  }
   149  
   150  func (reusable *ReusableCadenceRuntime) ExecuteScript(
   151  	script runtime.Script,
   152  	location common.Location,
   153  ) (
   154  	cadence.Value,
   155  	error,
   156  ) {
   157  	return reusable.Runtime.ExecuteScript(
   158  		script,
   159  		runtime.Context{
   160  			Interface: reusable.fvmEnv,
   161  			Location:  location,
   162  		},
   163  	)
   164  }
   165  
   166  type CadenceRuntimeConstructor func(config runtime.Config) runtime.Runtime
   167  
   168  type ReusableCadenceRuntimePool struct {
   169  	pool chan *ReusableCadenceRuntime
   170  
   171  	config runtime.Config
   172  
   173  	// When newCustomRuntime is nil, the pool will create standard cadence
   174  	// interpreter runtimes via runtime.NewInterpreterRuntime.  Otherwise, the
   175  	// pool will create runtimes using this function.
   176  	//
   177  	// Note that this is primarily used for testing.
   178  	newCustomRuntime CadenceRuntimeConstructor
   179  }
   180  
   181  func newReusableCadenceRuntimePool(
   182  	poolSize int,
   183  	config runtime.Config,
   184  	newCustomRuntime CadenceRuntimeConstructor,
   185  ) ReusableCadenceRuntimePool {
   186  	var pool chan *ReusableCadenceRuntime
   187  	if poolSize > 0 {
   188  		pool = make(chan *ReusableCadenceRuntime, poolSize)
   189  	}
   190  
   191  	return ReusableCadenceRuntimePool{
   192  		pool:             pool,
   193  		config:           config,
   194  		newCustomRuntime: newCustomRuntime,
   195  	}
   196  }
   197  
   198  func NewReusableCadenceRuntimePool(
   199  	poolSize int,
   200  	config runtime.Config,
   201  ) ReusableCadenceRuntimePool {
   202  	return newReusableCadenceRuntimePool(poolSize, config, nil)
   203  }
   204  
   205  func NewCustomReusableCadenceRuntimePool(
   206  	poolSize int,
   207  	newCustomRuntime CadenceRuntimeConstructor,
   208  ) ReusableCadenceRuntimePool {
   209  	return newReusableCadenceRuntimePool(
   210  		poolSize,
   211  		runtime.Config{},
   212  		newCustomRuntime,
   213  	)
   214  }
   215  
   216  func (pool ReusableCadenceRuntimePool) newRuntime() runtime.Runtime {
   217  	if pool.newCustomRuntime != nil {
   218  		return pool.newCustomRuntime(pool.config)
   219  	}
   220  	return runtime.NewInterpreterRuntime(pool.config)
   221  }
   222  
   223  func (pool ReusableCadenceRuntimePool) Borrow(
   224  	fvmEnv Environment,
   225  ) *ReusableCadenceRuntime {
   226  	var reusable *ReusableCadenceRuntime
   227  	select {
   228  	case reusable = <-pool.pool:
   229  		// Do nothing.
   230  	default:
   231  		reusable = NewReusableCadenceRuntime(
   232  			WrappedCadenceRuntime{
   233  				pool.newRuntime(),
   234  			},
   235  			pool.config,
   236  		)
   237  	}
   238  
   239  	reusable.SetFvmEnvironment(fvmEnv)
   240  	return reusable
   241  }
   242  
   243  func (pool ReusableCadenceRuntimePool) Return(
   244  	reusable *ReusableCadenceRuntime,
   245  ) {
   246  	reusable.SetFvmEnvironment(nil)
   247  	select {
   248  	case pool.pool <- reusable:
   249  		// Do nothing.
   250  	default:
   251  		// Do nothing.  Discard the overflow entry.
   252  	}
   253  }