github.com/ava-labs/avalanchego@v1.11.11/vms/example/xsvm/vm.go (about)

     1  // Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved.
     2  // See the file LICENSE for licensing terms.
     3  
     4  package xsvm
     5  
     6  import (
     7  	"context"
     8  	"fmt"
     9  	"net/http"
    10  
    11  	"github.com/gorilla/rpc/v2"
    12  	"go.uber.org/zap"
    13  
    14  	"github.com/ava-labs/avalanchego/database"
    15  	"github.com/ava-labs/avalanchego/database/versiondb"
    16  	"github.com/ava-labs/avalanchego/ids"
    17  	"github.com/ava-labs/avalanchego/snow"
    18  	"github.com/ava-labs/avalanchego/snow/consensus/snowman"
    19  	"github.com/ava-labs/avalanchego/snow/engine/common"
    20  	"github.com/ava-labs/avalanchego/utils/constants"
    21  	"github.com/ava-labs/avalanchego/utils/json"
    22  	"github.com/ava-labs/avalanchego/version"
    23  	"github.com/ava-labs/avalanchego/vms/example/xsvm/api"
    24  	"github.com/ava-labs/avalanchego/vms/example/xsvm/builder"
    25  	"github.com/ava-labs/avalanchego/vms/example/xsvm/chain"
    26  	"github.com/ava-labs/avalanchego/vms/example/xsvm/execute"
    27  	"github.com/ava-labs/avalanchego/vms/example/xsvm/genesis"
    28  	"github.com/ava-labs/avalanchego/vms/example/xsvm/state"
    29  
    30  	smblock "github.com/ava-labs/avalanchego/snow/engine/snowman/block"
    31  	xsblock "github.com/ava-labs/avalanchego/vms/example/xsvm/block"
    32  )
    33  
    34  var (
    35  	_ smblock.ChainVM                      = (*VM)(nil)
    36  	_ smblock.BuildBlockWithContextChainVM = (*VM)(nil)
    37  )
    38  
    39  type VM struct {
    40  	common.AppHandler
    41  
    42  	chainContext *snow.Context
    43  	db           database.Database
    44  	genesis      *genesis.Genesis
    45  	engineChan   chan<- common.Message
    46  
    47  	chain   chain.Chain
    48  	builder builder.Builder
    49  }
    50  
    51  func (vm *VM) Initialize(
    52  	_ context.Context,
    53  	chainContext *snow.Context,
    54  	db database.Database,
    55  	genesisBytes []byte,
    56  	_ []byte,
    57  	_ []byte,
    58  	engineChan chan<- common.Message,
    59  	_ []*common.Fx,
    60  	_ common.AppSender,
    61  ) error {
    62  	vm.AppHandler = common.NewNoOpAppHandler(chainContext.Log)
    63  
    64  	chainContext.Log.Info("initializing xsvm",
    65  		zap.Stringer("version", Version),
    66  	)
    67  
    68  	vm.chainContext = chainContext
    69  	vm.db = db
    70  	g, err := genesis.Parse(genesisBytes)
    71  	if err != nil {
    72  		return fmt.Errorf("failed to parse genesis bytes: %w", err)
    73  	}
    74  
    75  	vdb := versiondb.New(vm.db)
    76  	if err := execute.Genesis(vdb, chainContext.ChainID, g); err != nil {
    77  		return fmt.Errorf("failed to initialize genesis state: %w", err)
    78  	}
    79  	if err := vdb.Commit(); err != nil {
    80  		return err
    81  	}
    82  
    83  	vm.genesis = g
    84  	vm.engineChan = engineChan
    85  
    86  	vm.chain, err = chain.New(chainContext, vm.db)
    87  	if err != nil {
    88  		return fmt.Errorf("failed to initialize chain manager: %w", err)
    89  	}
    90  
    91  	vm.builder = builder.New(chainContext, engineChan, vm.chain)
    92  
    93  	chainContext.Log.Info("initialized xsvm",
    94  		zap.Stringer("lastAcceptedID", vm.chain.LastAccepted()),
    95  	)
    96  	return nil
    97  }
    98  
    99  func (vm *VM) SetState(_ context.Context, state snow.State) error {
   100  	vm.chain.SetChainState(state)
   101  	return nil
   102  }
   103  
   104  func (vm *VM) Shutdown(context.Context) error {
   105  	if vm.chainContext == nil {
   106  		return nil
   107  	}
   108  	return vm.db.Close()
   109  }
   110  
   111  func (*VM) Version(context.Context) (string, error) {
   112  	return Version.String(), nil
   113  }
   114  
   115  func (vm *VM) CreateHandlers(context.Context) (map[string]http.Handler, error) {
   116  	server := rpc.NewServer()
   117  	server.RegisterCodec(json.NewCodec(), "application/json")
   118  	server.RegisterCodec(json.NewCodec(), "application/json;charset=UTF-8")
   119  	api := api.NewServer(
   120  		vm.chainContext,
   121  		vm.genesis,
   122  		vm.db,
   123  		vm.chain,
   124  		vm.builder,
   125  	)
   126  	return map[string]http.Handler{
   127  		"": server,
   128  	}, server.RegisterService(api, constants.XSVMName)
   129  }
   130  
   131  func (*VM) HealthCheck(context.Context) (interface{}, error) {
   132  	return http.StatusOK, nil
   133  }
   134  
   135  func (*VM) Connected(context.Context, ids.NodeID, *version.Application) error {
   136  	return nil
   137  }
   138  
   139  func (*VM) Disconnected(context.Context, ids.NodeID) error {
   140  	return nil
   141  }
   142  
   143  func (vm *VM) GetBlock(_ context.Context, blkID ids.ID) (snowman.Block, error) {
   144  	return vm.chain.GetBlock(blkID)
   145  }
   146  
   147  func (vm *VM) ParseBlock(_ context.Context, blkBytes []byte) (snowman.Block, error) {
   148  	blk, err := xsblock.Parse(blkBytes)
   149  	if err != nil {
   150  		return nil, err
   151  	}
   152  	return vm.chain.NewBlock(blk)
   153  }
   154  
   155  func (vm *VM) BuildBlock(ctx context.Context) (snowman.Block, error) {
   156  	return vm.builder.BuildBlock(ctx, nil)
   157  }
   158  
   159  func (vm *VM) SetPreference(_ context.Context, preferred ids.ID) error {
   160  	vm.builder.SetPreference(preferred)
   161  	return nil
   162  }
   163  
   164  func (vm *VM) LastAccepted(context.Context) (ids.ID, error) {
   165  	return vm.chain.LastAccepted(), nil
   166  }
   167  
   168  func (vm *VM) BuildBlockWithContext(ctx context.Context, blockContext *smblock.Context) (snowman.Block, error) {
   169  	return vm.builder.BuildBlock(ctx, blockContext)
   170  }
   171  
   172  func (vm *VM) GetBlockIDAtHeight(_ context.Context, height uint64) (ids.ID, error) {
   173  	return state.GetBlockIDByHeight(vm.db, height)
   174  }