Skip to content
Merged
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
12 changes: 9 additions & 3 deletions vms/saevm/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@ load("//.bazel:defs.bzl", "go_test")
go_library(
name = "saevm",
srcs = [
"config.go",
"factory.go",
"vm.go",
],
importpath = "github.com/ava-labs/avalanchego/vms/saevm",
visibility = ["//visibility:public"],
deps = [
"//cache/lru",
"//database",
"//database/prefixdb",
"//graft/coreth/params",
Expand All @@ -30,12 +32,13 @@ go_library(
"//vms/components/gas",
"//vms/evm/acp226",
"//vms/evm/database",
"//vms/platformvm/warp",
"//vms/saevm/api",
"//vms/saevm/hook",
"//vms/saevm/hook/acp176",
"//vms/saevm/tx",
"//vms/saevm/txpool",
"//vms/saevm/warp/backend",
"//vms/saevm/warp",
"@com_github_ava_labs_libevm//common/hexutil",
"@com_github_ava_labs_libevm//core",
"@com_github_ava_labs_libevm//core/rawdb",
Expand All @@ -52,7 +55,10 @@ go_library(

go_test(
name = "saevm_test",
srcs = ["vm_warp_test.go"],
srcs = [
"config_test.go",
"vm_warp_test.go",
],
embed = [":saevm"],
deps = [
"//database/memdb",
Expand All @@ -62,7 +68,6 @@ go_test(
"//graft/coreth/plugin/evm/customheader",
"//graft/coreth/plugin/evm/vmtest",
"//graft/coreth/precompile/contracts/warp",
"//graft/coreth/warp",
"//ids",
"//snow",
"//snow/engine/common",
Expand All @@ -80,6 +85,7 @@ go_test(
"//vms/evm/predicate",
"//vms/platformvm/warp",
"//vms/platformvm/warp/payload",
"//vms/saevm/warp",
"@com_github_ava_labs_libevm//common",
"@com_github_ava_labs_libevm//core/txpool/legacypool",
"@com_github_ava_labs_libevm//core/types",
Expand Down
60 changes: 60 additions & 0 deletions vms/saevm/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// Copyright (C) 2019, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.

package saevm

import (
"encoding/json"
"errors"
"fmt"

"github.com/ava-labs/libevm/common/hexutil"

"github.com/ava-labs/avalanchego/vms/components/gas"

avawarp "github.com/ava-labs/avalanchego/vms/platformvm/warp"
)

type Config struct {
// GasTarget is the target gas per second that this node will attempt to use
// when creating blocks. If this config is not specified, the node will
// default to use the parent block's target gas per second.
GasTarget *gas.Gas `json:"gas-target,omitempty"`

// MinDelayTarget is the minimum delay between blocks (in milliseconds) that
// this node will attempt to use when creating blocks. If this config is not
// specified, the node will default to use the parent block's target delay
// per second.
MinDelayTarget *uint64 `json:"min-delay-target,omitempty"`

// WarpOffChainMessages encodes off-chain messages (unrelated to any
// on-chain event ie. block or AddressedCall) that the node should be
// willing to sign.
WarpOffChainMessages []hexutil.Bytes `json:"warp-off-chain-messages"`
}

func ParseConfig(b []byte) (Config, error) {
var c Config
if len(b) == 0 {
return c, nil
}

if err := json.Unmarshal(b, &c); err != nil {
return Config{}, fmt.Errorf("json.Unmarshal(%T): %w", c, err)
}
return c, nil
}

var errParsingWarpMessage = errors.New("parsing warp message")

func (c Config) WarpMessages() ([]*avawarp.UnsignedMessage, error) {
msgs := make([]*avawarp.UnsignedMessage, len(c.WarpOffChainMessages))
for i, bytes := range c.WarpOffChainMessages {
msg, err := avawarp.ParseUnsignedMessage(bytes)
if err != nil {
return nil, fmt.Errorf("%w: at index %d: %w", errParsingWarpMessage, i, err)
}
msgs[i] = msg
}
return msgs, nil
}
65 changes: 65 additions & 0 deletions vms/saevm/config_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
// Copyright (C) 2019, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.

package saevm

import (
"testing"

"github.com/stretchr/testify/require"

"github.com/ava-labs/avalanchego/ids"
"github.com/ava-labs/avalanchego/utils"
"github.com/ava-labs/avalanchego/vms/platformvm/warp"
"github.com/ava-labs/avalanchego/vms/platformvm/warp/payload"
)

func TestConfig_WarpMessages(t *testing.T) {
payload, err := payload.NewAddressedCall(
utils.RandomBytes(20),
[]byte("test"),
)
require.NoError(t, err)

msg, err := warp.NewUnsignedMessage(12345, ids.GenerateTestID(), payload.Bytes())
require.NoError(t, err)

tests := []struct {
name string
bytes [][]byte
want []*warp.UnsignedMessage
wantErr error
}{
{
name: "empty",
want: []*warp.UnsignedMessage{},
},
{
name: "single_message",
bytes: [][]byte{msg.Bytes()},
want: []*warp.UnsignedMessage{msg},
},
{
name: "multiple_messages",
bytes: [][]byte{msg.Bytes(), msg.Bytes()},
want: []*warp.UnsignedMessage{msg, msg},
},
{
name: "invalid_message",
bytes: [][]byte{{0xff}},
wantErr: errParsingWarpMessage,
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
var c Config
for _, msgBytes := range test.bytes {
c.WarpOffChainMessages = append(c.WarpOffChainMessages, msgBytes)
}

got, err := c.WarpMessages()
require.ErrorIs(t, err, test.wantErr)
require.Equal(t, test.want, got)
})
}
}
8 changes: 4 additions & 4 deletions vms/saevm/hook/points.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ var _ hook.PointsG[*txpool.Tx] = (*Points)(nil)
type Points struct {
blockBuilder
db database.Database
warpBackend precompileconfig.WarpMessageWriter
warpStorage *warp.Storage
}

func NewPoints(
Expand All @@ -53,7 +53,7 @@ func NewPoints(
desiredDelayExcess *acp226.DelayExcess,
desiredTargetExcess *acp176.TargetExcess,
pool *txpool.Txs,
warpBackend precompileconfig.WarpMessageWriter,
warpStorage *warp.Storage,
) *Points {
return &Points{
blockBuilder{
Expand All @@ -66,7 +66,7 @@ func NewPoints(
chainConfig: chainConfig,
},
db,
warpBackend,
warpStorage,
}
}

Expand Down Expand Up @@ -171,7 +171,7 @@ func (p *Points) AfterExecutingBlock(statedb *state.StateDB, b *types.Block, rec
rules := p.chainConfig.Rules(b.Number(), corethparams.IsMergeTODO, b.Time())
acceptCtx := &precompileconfig.AcceptContext{
SnowCtx: p.ctx,
Warp: p.warpBackend,
Warp: p.warpStorage,
}
if err := warp.HandlePrecompileAccept(rules, acceptCtx, receipts); err != nil {
return fmt.Errorf("failed to handle precompile accept for block %s (%d): %w", b.Hash(), b.NumberU64(), err)
Expand Down
69 changes: 22 additions & 47 deletions vms/saevm/vm.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import (
"sync/atomic"
"time"

"github.com/ava-labs/libevm/common/hexutil"
"github.com/ava-labs/libevm/core"
"github.com/ava-labs/libevm/core/rawdb"
"github.com/ava-labs/libevm/core/types"
Expand All @@ -24,6 +23,7 @@ import (
"github.com/ava-labs/strevm/sae"
"github.com/prometheus/client_golang/prometheus"

"github.com/ava-labs/avalanchego/cache/lru"
"github.com/ava-labs/avalanchego/database/prefixdb"
"github.com/ava-labs/avalanchego/graft/coreth/params/extras"
"github.com/ava-labs/avalanchego/graft/coreth/plugin/evm/customtypes"
Expand All @@ -36,7 +36,6 @@ import (
"github.com/ava-labs/avalanchego/snow/engine/common"
"github.com/ava-labs/avalanchego/snow/engine/snowman/block"
"github.com/ava-labs/avalanchego/utils"
"github.com/ava-labs/avalanchego/vms/components/gas"
"github.com/ava-labs/avalanchego/vms/evm/acp226"
"github.com/ava-labs/avalanchego/vms/evm/database"
"github.com/ava-labs/avalanchego/vms/saevm/api"
Expand All @@ -48,7 +47,7 @@ import (
avadb "github.com/ava-labs/avalanchego/database"
corethparams "github.com/ava-labs/avalanchego/graft/coreth/params"
warpcontract "github.com/ava-labs/avalanchego/graft/coreth/precompile/contracts/warp"
warpbackend "github.com/ava-labs/avalanchego/vms/saevm/warp/backend"
saewarp "github.com/ava-labs/avalanchego/vms/saevm/warp"
)

// SinceGenesis is a harness around an [sae.VM], providing an `Initialize`
Expand All @@ -61,7 +60,9 @@ type SinceGenesis struct {
db avadb.Database
mempool *txpool.Mempool
pushGossiper *gossip.PushGossiper[*tx.Tx]
warpBackend *warpbackend.Backend

// TODO(StephenButtolph): Remove. This is only used by the tests.
warpVerifier *saewarp.Verifier

// onClose are executed in reverse order during [SinceGenesis.Shutdown].
// If a resource depends on another resource, it MUST be added AFTER the
Expand All @@ -79,24 +80,7 @@ func NewSinceGenesis(c sae.Config) *SinceGenesis {
}
}

type Config struct {
// GasTarget is the target gas per second that this node will attempt to use
// when creating blocks. If this config is not specified, the node will
// default to use the parent block's target gas per second.
GasTarget *gas.Gas `json:"gas-target,omitempty"`

// MinDelayTarget is the minimum delay between blocks (in milliseconds) that
// this node will attempt to use when creating blocks. If this config is not
// specified, the node will default to use the parent block's target delay
// per second.
MinDelayTarget *uint64 `json:"min-delay-target,omitempty"`

// WarpOffChainMessages encodes off-chain messages (unrelated to any on-chain event ie. block or AddressedCall)
// that the node should be willing to sign.
// Note: only supports AddressedCall payloads as defined here:
// https://github.com/ava-labs/avalanchego/tree/7623ffd4be915a5185c9ed5e11fa9be15a6e1f00/vms/platformvm/warp/payload#addressedcall
WarpOffChainMessages []hexutil.Bytes `json:"warp-off-chain-messages"`
}
const warpSignatureCacheSize = 512

var ethDBPrefix = []byte("ethdb")

Expand Down Expand Up @@ -161,30 +145,15 @@ func (vm *SinceGenesis) Initialize(
return fmt.Errorf("core.SetupGenesisBlock(...): %w", err)
}

var userConfig Config
if len(configBytes) > 0 {
if err := json.Unmarshal(configBytes, &userConfig); err != nil {
return fmt.Errorf("json.Unmarshal(%T): %w", userConfig, err)
}
userConfig, err := ParseConfig(configBytes)
if err != nil {
return err
}

// Initialize warp backend
offchainWarpMessages := make([][]byte, len(userConfig.WarpOffChainMessages))
for i, hexMsg := range userConfig.WarpOffChainMessages {
offchainWarpMessages[i] = []byte(hexMsg)
}
warpBackend, warpSignatureCache, err := warpbackend.New(
snowCtx.NetworkID,
snowCtx.ChainID,
snowCtx.WarpSigner,
&blockClient{vm: vm},
avaDB,
offchainWarpMessages,
)
warpMessages, err := userConfig.WarpMessages()
if err != nil {
return fmt.Errorf("warp backend: %w", err)
return err
}
vm.warpBackend = warpBackend

var desiredDelayExcess *acp226.DelayExcess
if userConfig.MinDelayTarget != nil {
Expand All @@ -198,14 +167,15 @@ func (vm *SinceGenesis) Initialize(
}

txs := txpool.NewTxs()
warpStorage := saewarp.NewStorage(avaDB, warpMessages...)
hooks := hook.NewPoints(
snowCtx,
avaDB,
config,
desiredDelayExcess,
desiredTargetExcess,
txs,
vm.warpBackend,
warpStorage,
)
inner, err := sae.NewVM(ctx, hooks, vm.config, snowCtx, config, db, genesis.ToBlock(), appSender)
if err != nil {
Expand Down Expand Up @@ -270,7 +240,12 @@ func (vm *SinceGenesis) Initialize(
}

{ // ========== Warp Handler ==========
warpHandler := acp118.NewCachedHandler(warpSignatureCache, warpBackend, snowCtx.WarpSigner)
vm.warpVerifier = saewarp.NewVerifier(&blockClient{vm: inner}, warpStorage)
warpHandler := acp118.NewCachedHandler(
lru.NewCache[ids.ID, []byte](warpSignatureCacheSize),
vm.warpVerifier,
snowCtx.WarpSigner,
)
if err := inner.AddHandler(p2p.SignatureRequestHandlerID, warpHandler); err != nil {
return fmt.Errorf("network.AddHandler(warp): %w", err)
}
Expand Down Expand Up @@ -408,12 +383,12 @@ func (vm *SinceGenesis) Shutdown(ctx context.Context) error {
return vm.VM.Shutdown(ctx)
}

// blockClient adapts [SinceGenesis] to the [warpbackend.BlockClient] interface.
// blockClient adapts [sae.VM] to the [saewarp.BlockClient] interface.
type blockClient struct {
vm *SinceGenesis
vm *sae.VM
}

var _ warpbackend.BlockClient = (*blockClient)(nil)
var _ saewarp.BlockClient = (*blockClient)(nil)

func (c *blockClient) IsAccepted(ctx context.Context, blockID ids.ID) error {
b, err := c.vm.GetBlock(ctx, blockID)
Expand Down
Loading
Loading