Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor api vm options #1750

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion api/dependencies.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import (
)

type VM interface {
GetDataDir() string
GetDataDir(namespace string) string
GetGenesisBytes() []byte
Genesis() genesis.Genesis
ChainID() ids.ID
Expand Down
20 changes: 8 additions & 12 deletions api/indexer/option.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,9 @@
package indexer

import (
"path/filepath"

"github.com/ava-labs/hypersdk/api"
"github.com/ava-labs/hypersdk/chain"
"github.com/ava-labs/hypersdk/event"
"github.com/ava-labs/hypersdk/vm"
)

const (
Expand All @@ -31,16 +28,15 @@ func NewDefaultConfig() Config {
}
}

func With() vm.Option {
return vm.NewOption(Namespace, NewDefaultConfig(), OptionFunc)
func With() api.Option {
return api.NewOption(Namespace, NewDefaultConfig(), OptionFunc)
}

func OptionFunc(v api.VM, config Config) (vm.Opt, error) {
func OptionFunc(v api.VM, config Config) (api.Opt, error) {
if !config.Enabled {
return vm.NewOpt(), nil
return api.NewOpt(), nil
}
indexerPath := filepath.Join(v.GetDataDir(), Namespace)
indexer, err := NewIndexer(indexerPath, v, config.BlockWindow)
indexer, err := NewIndexer(v.GetDataDir(Namespace), v, config.BlockWindow)
if err != nil {
return nil, err
}
Expand All @@ -55,9 +51,9 @@ func OptionFunc(v api.VM, config Config) (vm.Opt, error) {
indexer: indexer,
}

return vm.NewOpt(
vm.WithBlockSubscriptions(subscriptionFactory),
vm.WithVMAPIs(apiFactory),
return api.NewOpt(
api.WithBlockSubscriptions(subscriptionFactory),
api.WithVMAPIs(apiFactory),
), nil
}

Expand Down
9 changes: 4 additions & 5 deletions api/jsonrpc/option.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ package jsonrpc

import (
"github.com/ava-labs/hypersdk/api"
"github.com/ava-labs/hypersdk/vm"
)

const Namespace = "core"
Expand All @@ -20,11 +19,11 @@ func NewDefaultConfig() Config {
}
}

func With() vm.Option {
return vm.NewOption(Namespace, NewDefaultConfig(), func(_ api.VM, config Config) (vm.Opt, error) {
func With() api.Option {
return api.NewOption(Namespace, NewDefaultConfig(), func(_ api.VM, config Config) (api.Opt, error) {
if !config.Enabled {
return vm.NewOpt(), nil
return api.NewOpt(), nil
}
return vm.WithVMAPIs(JSONRPCServerFactory{}), nil
return api.WithVMAPIs(JSONRPCServerFactory{}), nil
})
}
47 changes: 23 additions & 24 deletions vm/option.go → api/option.go
Original file line number Diff line number Diff line change
@@ -1,37 +1,36 @@
// Copyright (C) 2024, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.

package vm
package api

import (
"encoding/json"
"fmt"

"github.com/ava-labs/hypersdk/api"
"github.com/ava-labs/hypersdk/chain"
"github.com/ava-labs/hypersdk/event"
)

type Options struct {
builder bool
gossiper bool
blockSubscriptionFactories []event.SubscriptionFactory[*chain.ExecutedBlock]
vmAPIHandlerFactories []api.HandlerFactory[api.VM]
Builder bool
Gossiper bool
BlockSubscriptionFactories []event.SubscriptionFactory[*chain.ExecutedBlock]
VMAPIHandlerFactories []HandlerFactory[VM]
}

type optionFunc func(vm api.VM, configBytes []byte) (Opt, error)
type optionFunc func(vm VM, configBytes []byte) (Opt, error)

type OptionFunc[T any] func(vm api.VM, config T) (Opt, error)
type OptionFunc[T any] func(vm VM, config T) (Opt, error)

type Option struct {
Namespace string
optionFunc optionFunc
OptionFunc optionFunc
}

func newOptionWithBytes(namespace string, optionFunc optionFunc) Option {
return Option{
Namespace: namespace,
optionFunc: optionFunc,
OptionFunc: optionFunc,
}
}

Expand All @@ -41,7 +40,7 @@ func newOptionWithBytes(namespace string, optionFunc optionFunc) Option {
// 3) An option function that takes the VM and resulting config value as arguments
func NewOption[T any](namespace string, defaultConfig T, optionFunc OptionFunc[T]) Option {
config := defaultConfig
configOptionFunc := func(vm api.VM, configBytes []byte) (Opt, error) {
configOptionFunc := func(vm VM, configBytes []byte) (Opt, error) {
if len(configBytes) > 0 {
if err := json.Unmarshal(configBytes, &config); err != nil {
return nil, fmt.Errorf("failed to unmarshal %q config %q: %w", namespace, string(configBytes), err)
Expand All @@ -53,52 +52,52 @@ func NewOption[T any](namespace string, defaultConfig T, optionFunc OptionFunc[T
return newOptionWithBytes(namespace, configOptionFunc)
}

func WithBuilder() Opt {
func withBuilder() Opt {
return newFuncOption(func(o *Options) {
o.builder = true
o.Builder = true
})
}

func WithGossiper() Opt {
func withGossiper() Opt {
return newFuncOption(func(o *Options) {
o.gossiper = true
o.Gossiper = true
})
}

func WithManual() Option {
return NewOption[struct{}](
"manual",
struct{}{},
func(_ api.VM, _ struct{}) (Opt, error) {
func(_ VM, _ struct{}) (Opt, error) {
return newFuncOption(func(o *Options) {
WithBuilder().apply(o)
WithGossiper().apply(o)
withBuilder().Apply(o)
withGossiper().Apply(o)
}), nil
},
)
}

func WithBlockSubscriptions(subscriptions ...event.SubscriptionFactory[*chain.ExecutedBlock]) Opt {
return newFuncOption(func(o *Options) {
o.blockSubscriptionFactories = append(o.blockSubscriptionFactories, subscriptions...)
o.BlockSubscriptionFactories = append(o.BlockSubscriptionFactories, subscriptions...)
})
}

func WithVMAPIs(apiHandlerFactories ...api.HandlerFactory[api.VM]) Opt {
func WithVMAPIs(apiHandlerFactories ...HandlerFactory[VM]) Opt {
return newFuncOption(func(o *Options) {
o.vmAPIHandlerFactories = append(o.vmAPIHandlerFactories, apiHandlerFactories...)
o.VMAPIHandlerFactories = append(o.VMAPIHandlerFactories, apiHandlerFactories...)
})
}

type Opt interface {
apply(*Options)
Apply(*Options)
}

// NewOpt mixes a list of Opt in a new one Opt.
func NewOpt(opts ...Opt) Opt {
return newFuncOption(func(o *Options) {
for _, opt := range opts {
opt.apply(o)
opt.Apply(o)
}
})
}
Expand All @@ -107,7 +106,7 @@ type funcOption struct {
f func(*Options)
}

func (fdo *funcOption) apply(do *Options) {
func (fdo *funcOption) Apply(do *Options) {
fdo.f(do)
}

Expand Down
9 changes: 4 additions & 5 deletions api/state/option.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ package state

import (
"github.com/ava-labs/hypersdk/api"
"github.com/ava-labs/hypersdk/vm"
)

const Namespace = "corestate"
Expand All @@ -20,11 +19,11 @@ func NewDefaultConfig() Config {
}
}

func With() vm.Option {
return vm.NewOption(Namespace, NewDefaultConfig(), func(_ api.VM, config Config) (vm.Opt, error) {
func With() api.Option {
return api.NewOption(Namespace, NewDefaultConfig(), func(_ api.VM, config Config) (api.Opt, error) {
if !config.Enabled {
return vm.NewOpt(), nil
return api.NewOpt(), nil
}
return vm.WithVMAPIs(JSONRPCStateServerFactory{}), nil
return api.WithVMAPIs(JSONRPCStateServerFactory{}), nil
})
}
6 changes: 6 additions & 0 deletions api/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ package api
import (
"net/http"

"github.com/ava-labs/avalanchego/ids"
"github.com/ava-labs/avalanchego/utils/json"
"github.com/gorilla/rpc/v2"
)
Expand All @@ -19,3 +20,8 @@ func NewJSONRPCHandler(
server.RegisterCodec(json.NewCodec(), "application/json;charset=UTF-8")
return server, server.RegisterService(service, name)
}

type TxRemovedEvent struct {
TxID ids.ID
Err error
}
15 changes: 7 additions & 8 deletions api/ws/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ import (
"github.com/ava-labs/hypersdk/event"
"github.com/ava-labs/hypersdk/internal/emap"
"github.com/ava-labs/hypersdk/pubsub"
"github.com/ava-labs/hypersdk/vm"
)

const (
Expand All @@ -46,13 +45,13 @@ func NewDefaultConfig() Config {
}
}

func With() vm.Option {
return vm.NewOption(Namespace, NewDefaultConfig(), OptionFunc)
func With() api.Option {
return api.NewOption(Namespace, NewDefaultConfig(), OptionFunc)
}

func OptionFunc(v api.VM, config Config) (vm.Opt, error) {
func OptionFunc(v api.VM, config Config) (api.Opt, error) {
if !config.Enabled {
return vm.NewOpt(), nil
return api.NewOpt(), nil
}

actionCodec, authCodec := v.ActionCodec(), v.AuthCodec()
Expand All @@ -73,9 +72,9 @@ func OptionFunc(v api.VM, config Config) (vm.Opt, error) {
},
}

return vm.NewOpt(
vm.WithBlockSubscriptions(blockSubscription),
vm.WithVMAPIs(webSocketFactory),
return api.NewOpt(
api.WithBlockSubscriptions(blockSubscription),
api.WithVMAPIs(webSocketFactory),
), nil
}

Expand Down
6 changes: 3 additions & 3 deletions docs/tutorials/morpheusvm/3_options.md
Original file line number Diff line number Diff line change
Expand Up @@ -320,12 +320,12 @@ VM or not. Finally, we implement a `NewDefaultConfig()` function which returns a
default config. We now implement the option itself:

```golang
func With() vm.Option {
return vm.NewOption(Namespace, NewDefaultConfig(), func(v *vm.VM, config Config) error {
func With() api.Option {
return api.NewOption(Namespace, NewDefaultConfig(), func(v *api.VM, config Config) error {
if !config.Enabled {
return nil
}
vm.WithVMAPIs(jsonRPCServerFactory{})(v)
api.WithVMAPIs(jsonRPCServerFactory{})(v)
return nil
})
}
Expand Down
9 changes: 4 additions & 5 deletions examples/morpheusvm/vm/option.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ package vm

import (
"github.com/ava-labs/hypersdk/api"
"github.com/ava-labs/hypersdk/vm"
)

const Namespace = "controller"
Expand All @@ -20,11 +19,11 @@ func NewDefaultConfig() Config {
}
}

func With() vm.Option {
return vm.NewOption(Namespace, NewDefaultConfig(), func(v api.VM, config Config) (vm.Opt, error) {
func With() api.Option {
return api.NewOption(Namespace, NewDefaultConfig(), func(v api.VM, config Config) (api.Opt, error) {
if !config.Enabled {
return vm.NewOpt(), nil
return api.NewOpt(), nil
}
return vm.WithVMAPIs(jsonRPCServerFactory{}), nil
return api.WithVMAPIs(jsonRPCServerFactory{}), nil
})
}
3 changes: 2 additions & 1 deletion examples/morpheusvm/vm/vm.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ package vm
import (
"github.com/ava-labs/avalanchego/utils/wrappers"

"github.com/ava-labs/hypersdk/api"
"github.com/ava-labs/hypersdk/auth"
"github.com/ava-labs/hypersdk/chain"
"github.com/ava-labs/hypersdk/codec"
Expand Down Expand Up @@ -56,7 +57,7 @@ func init() {
}

// NewWithOptions returns a VM with the specified options
func New(options ...vm.Option) (*vm.VM, error) {
func New(options ...api.Option) (*vm.VM, error) {
options = append(options, With()) // Add MorpheusVM API
return defaultvm.New(
consts.Version,
Expand Down
11 changes: 5 additions & 6 deletions extension/externalsubscriber/option.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import (
"github.com/ava-labs/hypersdk/api"
"github.com/ava-labs/hypersdk/chain"
"github.com/ava-labs/hypersdk/event"
"github.com/ava-labs/hypersdk/vm"
)

const (
Expand All @@ -25,13 +24,13 @@ func NewDefaultConfig() Config {
return Config{}
}

func With() vm.Option {
return vm.NewOption(Namespace, NewDefaultConfig(), OptionFunc)
func With() api.Option {
return api.NewOption(Namespace, NewDefaultConfig(), OptionFunc)
}

func OptionFunc(v api.VM, config Config) (vm.Opt, error) {
func OptionFunc(v api.VM, config Config) (api.Opt, error) {
if !config.Enabled {
return vm.NewOpt(), nil
return api.NewOpt(), nil
}
server, err := NewExternalSubscriberClient(
context.TODO(),
Expand All @@ -49,5 +48,5 @@ func OptionFunc(v api.VM, config Config) (vm.Opt, error) {
},
}

return vm.WithBlockSubscriptions(blockSubscription), nil
return api.WithBlockSubscriptions(blockSubscription), nil
}
Loading