From ab3afd93a788230af13b17717d185bd29c29590c Mon Sep 17 00:00:00 2001 From: Arran Schlosberg Date: Thu, 21 Nov 2024 20:10:55 +0000 Subject: [PATCH] refactor: abstract `options` package --- core/vm/environment.libevm.go | 23 ++++++++----------- core/vm/options.libevm.go | 19 ++++++++-------- libevm/options/options.go | 42 +++++++++++++++++++++++++++++++++++ 3 files changed, 61 insertions(+), 23 deletions(-) create mode 100644 libevm/options/options.go diff --git a/core/vm/environment.libevm.go b/core/vm/environment.libevm.go index 1f87213e2ce6..afbb751b9acf 100644 --- a/core/vm/environment.libevm.go +++ b/core/vm/environment.libevm.go @@ -25,6 +25,7 @@ import ( "github.com/ava-labs/libevm/common" "github.com/ava-labs/libevm/core/types" "github.com/ava-labs/libevm/libevm" + "github.com/ava-labs/libevm/libevm/options" "github.com/ava-labs/libevm/params" ) @@ -105,20 +106,14 @@ func (e *environment) callContract(typ CallType, addr common.Address, input []by } var caller ContractRef = e.self - for _, o := range opts { - switch o := o.(type) { - case callOptUNSAFECallerAddressProxy: - // Note that, in addition to being unsafe, this breaks an EVM - // assumption that the caller ContractRef is always a *Contract. - caller = AccountRef(e.self.CallerAddress) - if e.callType == DelegateCall { - // self was created with AsDelegate(), which means that - // CallerAddress was inherited. - caller = AccountRef(e.self.Address()) - } - case nil: - default: - return nil, gas, fmt.Errorf("unsupported option %T", o) + if options.As[callConfig](opts...).unsafeCallerAddressProxying { + // Note that, in addition to being unsafe, this breaks an EVM + // assumption that the caller ContractRef is always a *Contract. + caller = AccountRef(e.self.CallerAddress) + if e.callType == DelegateCall { + // self was created with AsDelegate(), which means that + // CallerAddress was inherited. + caller = AccountRef(e.self.Address()) } } diff --git a/core/vm/options.libevm.go b/core/vm/options.libevm.go index 94ecdbb04574..d6cd7423e863 100644 --- a/core/vm/options.libevm.go +++ b/core/vm/options.libevm.go @@ -16,11 +16,15 @@ package vm -// A CallOption modifies the default behaviour of a contract call. -type CallOption interface { - libevmCallOption() // noop to only allow internally defined options +import "github.com/ava-labs/libevm/libevm/options" + +type callConfig struct { + unsafeCallerAddressProxying bool } +// A CallOption modifies the default behaviour of a contract call. +type CallOption = options.Option[callConfig] + // WithUNSAFECallerAddressProxying results in precompiles making contract calls // specifying their own caller's address as the caller. This is NOT SAFE for // regular use as callers of the precompile may not understand that they are @@ -29,10 +33,7 @@ type CallOption interface { // Deprecated: this option MUST NOT be used other than to allow migration to // libevm when backwards compatibility is required. func WithUNSAFECallerAddressProxying() CallOption { - return callOptUNSAFECallerAddressProxy{} + return options.Func[callConfig](func(c *callConfig) { + c.unsafeCallerAddressProxying = true + }) } - -// Deprecated: see [WithUNSAFECallerAddressProxying]. -type callOptUNSAFECallerAddressProxy struct{} - -func (callOptUNSAFECallerAddressProxy) libevmCallOption() {} diff --git a/libevm/options/options.go b/libevm/options/options.go new file mode 100644 index 000000000000..af7bc751a966 --- /dev/null +++ b/libevm/options/options.go @@ -0,0 +1,42 @@ +// Copyright 2024 the libevm authors. +// +// The libevm additions to go-ethereum are free software: you can redistribute +// them and/or modify them under the terms of the GNU Lesser General Public License +// as published by the Free Software Foundation, either version 3 of the License, +// or (at your option) any later version. +// +// The libevm additions are distributed in the hope that they will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser +// General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see +// . + +// Package options provides a generic mechanism for defining configuration of +// arbitrary types. +package options + +// An Option configures values of arbitrary type. +type Option[T any] interface { + Configure(*T) +} + +// As applies Options to a zero-value T, which it then returns. +func As[T any](opts ...Option[T]) *T { + var t T + for _, o := range opts { + o.Configure(&t) + } + return &t +} + +// A Func converts a function into an [Option], using itself as the Configure +// method. +type Func[T any] func(*T) + +var _ Option[struct{}] = Func[struct{}](nil) + +// Configure implements the [Option] interface. +func (f Func[T]) Configure(t *T) { f(t) }