diff --git a/sae/always.go b/sae/always.go new file mode 100644 index 0000000..d97ed08 --- /dev/null +++ b/sae/always.go @@ -0,0 +1,38 @@ +// Copyright (C) 2025, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package sae + +import ( + "context" + + "github.com/ava-labs/avalanchego/database" + "github.com/ava-labs/avalanchego/snow" + snowcommon "github.com/ava-labs/avalanchego/snow/engine/common" + + "github.com/ava-labs/strevm/adaptor" + "github.com/ava-labs/strevm/blocks" +) + +// SinceGenesis is a harness around a [VM], providing an `Initialize` method +// that treats the chain as being asynchronous since genesis. +type SinceGenesis struct { + *VM +} + +var _ adaptor.ChainVM[*blocks.Block] = (*SinceGenesis)(nil) + +// Initialize initializes the VM. +func (vm *SinceGenesis) Initialize( + ctx context.Context, + chainCtx *snow.Context, + db database.Database, + genesisBytes []byte, + upgradeBytes []byte, + configBytes []byte, + toEngine chan<- snowcommon.Message, + fxs []*snowcommon.Fx, + appSender snowcommon.AppSender, +) error { + return errUnimplemented +} diff --git a/sae/blocks.go b/sae/blocks.go new file mode 100644 index 0000000..433f7a4 --- /dev/null +++ b/sae/blocks.go @@ -0,0 +1,45 @@ +// Copyright (C) 2025, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package sae + +import ( + "context" + + "github.com/ava-labs/avalanchego/database" + "github.com/ava-labs/avalanchego/ids" + "github.com/ava-labs/libevm/core/types" + "github.com/ava-labs/libevm/rlp" + + "github.com/ava-labs/strevm/blocks" +) + +// ParseBlock parses the buffer as [rlp] encoding of a [types.Block]. +func (vm *VM) ParseBlock(context.Context, []byte) (*blocks.Block, error) { + ethB := new(types.Block) + _ = rlp.DecodeBytes(nil, ethB) + return nil, errUnimplemented +} + +// BuildBlock builds a new block, using the last block passed to +// [VM.SetPreference] as the parent. +func (vm *VM) BuildBlock(context.Context) (*blocks.Block, error) { + return nil, errUnimplemented +} + +// VerifyBlock validates the block. +func (vm *VM) VerifyBlock(context.Context, *blocks.Block) error { + return errUnimplemented +} + +// GetBlock returns the block with the given ID, or [database.ErrNotFound]. +func (vm *VM) GetBlock(context.Context, ids.ID) (*blocks.Block, error) { + _ = database.ErrNotFound + return nil, errUnimplemented +} + +// GetBlockIDAtHeight returns the accepted block at the given height, or +// [database.ErrNotFound]. +func (vm *VM) GetBlockIDAtHeight(context.Context, uint64) (ids.ID, error) { + return ids.Empty, errUnimplemented +} diff --git a/sae/consensus.go b/sae/consensus.go new file mode 100644 index 0000000..f871033 --- /dev/null +++ b/sae/consensus.go @@ -0,0 +1,41 @@ +// Copyright (C) 2025, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package sae + +import ( + "context" + + "github.com/ava-labs/avalanchego/ids" + + "github.com/ava-labs/strevm/blocks" + "github.com/ava-labs/strevm/saexec" +) + +// SetPreference updates the VM's currently [preferred block]. +// +// [preferred block]: https://github.com/ava-labs/avalanchego/tree/master/vms#set-preference +func (vm *VM) SetPreference(context.Context, ids.ID) error { + return errUnimplemented +} + +// AcceptBlock marks the block as [accepted], resulting in: +// - All blocks settled by this block having their [blocks.Block.MarkSettled] +// method called; and +// - The block being propagated to [saexec.Executor.Enqueue]. +// +// [accepted]: https://github.com/ava-labs/avalanchego/tree/master/vms#block-statuses +func (vm *VM) AcceptBlock(context.Context, *blocks.Block) error { + _ = (*saexec.Executor)(nil) + return errUnimplemented +} + +// LastAccepted returns the ID of the last block received by [VM.AcceptBlock]. +func (vm *VM) LastAccepted(context.Context) (ids.ID, error) { + return ids.Empty, errUnimplemented +} + +// RejectBlock is a no-op in SAE because execution only occurs after acceptance. +func (vm *VM) RejectBlock(context.Context, *blocks.Block) error { + return nil +} diff --git a/sae/health.go b/sae/health.go new file mode 100644 index 0000000..6e2afe7 --- /dev/null +++ b/sae/health.go @@ -0,0 +1,11 @@ +// Copyright (C) 2025, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package sae + +import "context" + +// HealthCheck returns the current health status of the VM. +func (vm *VM) HealthCheck(context.Context) (any, error) { + return nil, nil +} diff --git a/sae/http.go b/sae/http.go new file mode 100644 index 0000000..8d7b199 --- /dev/null +++ b/sae/http.go @@ -0,0 +1,20 @@ +// Copyright (C) 2025, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package sae + +import ( + "context" + "net/http" +) + +// CreateHandlers returns all VM-specific HTTP handlers to be exposed by the +// node, keyed by path. +func (vm *VM) CreateHandlers(context.Context) (map[string]http.Handler, error) { + return nil, errUnimplemented +} + +// CreateHTTP2Handler returns `(nil, nil)`. +func (vm *VM) CreateHTTP2Handler(ctx context.Context) (http.Handler, error) { + return nil, nil +} diff --git a/sae/p2p.go b/sae/p2p.go new file mode 100644 index 0000000..2e5032a --- /dev/null +++ b/sae/p2p.go @@ -0,0 +1,69 @@ +// Copyright (C) 2025, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package sae + +import ( + "context" + "time" + + "github.com/ava-labs/avalanchego/ids" + snowcommon "github.com/ava-labs/avalanchego/snow/engine/common" + "github.com/ava-labs/avalanchego/version" +) + +// Connected notifies the VM that a p2p connection has been established with the +// specified node. +func (vm *VM) Connected( + ctx context.Context, + nodeID ids.NodeID, + nodeVersion *version.Application, +) error { + return errUnimplemented +} + +// Disconnected notifies the VM that the p2p connection with the specified node +// has terminated. +func (vm *VM) Disconnected(ctx context.Context, nodeID ids.NodeID) error { + return errUnimplemented +} + +// AppRequest notifies the VM of an incoming request from the specified node. +func (vm *VM) AppRequest( + ctx context.Context, + nodeID ids.NodeID, + requestID uint32, + deadline time.Time, + request []byte, +) error { + return errUnimplemented +} + +// AppResponse notifies the VM of an incoming response from the specified node. +func (vm *VM) AppResponse( + ctx context.Context, + nodeID ids.NodeID, + requestID uint32, + response []byte, +) error { + return errUnimplemented +} + +// AppRequestFailed notifies the VM that an outgoing request failed. +func (vm *VM) AppRequestFailed( + ctx context.Context, + nodeID ids.NodeID, + requestID uint32, + appErr *snowcommon.AppError, +) error { + return errUnimplemented +} + +// AppGossip notifies the VM of gossip from the specified node. +func (vm *VM) AppGossip( + ctx context.Context, + nodeID ids.NodeID, + msg []byte, +) error { + return errUnimplemented +} diff --git a/sae/temporary.go b/sae/temporary.go new file mode 100644 index 0000000..b0bdd1f --- /dev/null +++ b/sae/temporary.go @@ -0,0 +1,11 @@ +// Copyright (C) 2025, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package sae + +// This file MUST be deleted before release. It is intended solely to house +// interim identifiers needed for development over multiple PRs. + +import "errors" + +var errUnimplemented = errors.New("unimplemented") diff --git a/sae/vm.go b/sae/vm.go new file mode 100644 index 0000000..c3566b8 --- /dev/null +++ b/sae/vm.go @@ -0,0 +1,34 @@ +// Copyright (C) 2025, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +// Package sae implements the [Streaming Asynchronous Execution] (SAE) virtual +// machine to be compatible with Avalanche consensus. +// +// [Streaming Asynchronous Execution]: https://github.com/avalanche-foundation/ACPs/tree/main/ACPs/194-streaming-asynchronous-execution +package sae + +import ( + "context" + + "github.com/ava-labs/avalanchego/snow" +) + +// VM implements all of [adaptor.ChainVM] except for the `Initialize` method, +// which needs to be provided by a harness. In all cases, the harness MUST +// provide a last-synchronous block, which MAY be the genesis. +type VM struct{} + +// SetState notifies the VM of a transition in the state lifecycle. +func (vm *VM) SetState(ctx context.Context, state snow.State) error { + return errUnimplemented +} + +// Shutdown gracefully closes the VM. +func (vm *VM) Shutdown(context.Context) error { + return errUnimplemented +} + +// Version reports the VM's version. +func (vm *VM) Version(context.Context) (string, error) { + return "", errUnimplemented +}