mirror of
https://github.com/luxfi/oraclevm.git
synced 2026-10-30 15:23:15 +00:00
230 lines
6.0 KiB
Go
230 lines
6.0 KiB
Go
// Copyright (C) 2023, Ava Labs, Inc. All rights reserved.
|
|
// See the file LICENSE for licensing terms.
|
|
|
|
package controller
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"time"
|
|
|
|
ametrics "github.com/ava-labs/avalanchego/api/metrics"
|
|
"github.com/ava-labs/avalanchego/database"
|
|
"github.com/ava-labs/avalanchego/snow"
|
|
"github.com/ava-labs/avalanchego/snow/engine/common"
|
|
"github.com/ava-labs/hypersdk/builder"
|
|
"github.com/ava-labs/hypersdk/chain"
|
|
"github.com/ava-labs/hypersdk/gossiper"
|
|
hrpc "github.com/ava-labs/hypersdk/rpc"
|
|
hstorage "github.com/ava-labs/hypersdk/storage"
|
|
"github.com/ava-labs/hypersdk/vm"
|
|
"go.uber.org/zap"
|
|
|
|
"github.com/bianyuanop/oraclevm/actions"
|
|
"github.com/bianyuanop/oraclevm/config"
|
|
"github.com/bianyuanop/oraclevm/consts"
|
|
"github.com/bianyuanop/oraclevm/genesis"
|
|
"github.com/bianyuanop/oraclevm/oracle"
|
|
"github.com/bianyuanop/oraclevm/rpc"
|
|
"github.com/bianyuanop/oraclevm/storage"
|
|
"github.com/bianyuanop/oraclevm/version"
|
|
)
|
|
|
|
var _ vm.Controller = (*Controller)(nil)
|
|
|
|
type Controller struct {
|
|
inner *vm.VM
|
|
|
|
snowCtx *snow.Context
|
|
genesis *genesis.Genesis
|
|
config *config.Config
|
|
stateManager *storage.StateManager
|
|
|
|
metrics *metrics
|
|
|
|
metaDB database.Database
|
|
|
|
oracle *oracle.Oracle
|
|
}
|
|
|
|
func New() *vm.VM {
|
|
return vm.New(&Controller{}, version.Version)
|
|
}
|
|
|
|
func (c *Controller) Initialize(
|
|
inner *vm.VM,
|
|
snowCtx *snow.Context,
|
|
gatherer ametrics.MultiGatherer,
|
|
genesisBytes []byte,
|
|
upgradeBytes []byte, // subnets to allow for AWM
|
|
configBytes []byte,
|
|
) (
|
|
vm.Config,
|
|
vm.Genesis,
|
|
builder.Builder,
|
|
gossiper.Gossiper,
|
|
database.Database,
|
|
database.Database,
|
|
vm.Handlers,
|
|
chain.ActionRegistry,
|
|
chain.AuthRegistry,
|
|
error,
|
|
) {
|
|
c.inner = inner
|
|
c.snowCtx = snowCtx
|
|
c.stateManager = &storage.StateManager{}
|
|
|
|
// Instantiate metrics
|
|
var err error
|
|
c.metrics, err = newMetrics(gatherer)
|
|
if err != nil {
|
|
return nil, nil, nil, nil, nil, nil, nil, nil, nil, err
|
|
}
|
|
|
|
// Load config and genesis
|
|
c.config, err = config.New(c.snowCtx.NodeID, configBytes)
|
|
if err != nil {
|
|
return nil, nil, nil, nil, nil, nil, nil, nil, nil, err
|
|
}
|
|
c.snowCtx.Log.SetLevel(c.config.GetLogLevel())
|
|
snowCtx.Log.Info("initialized config", zap.Bool("loaded", c.config.Loaded()), zap.Any("contents", c.config))
|
|
|
|
c.genesis, err = genesis.New(genesisBytes, upgradeBytes)
|
|
if err != nil {
|
|
return nil, nil, nil, nil, nil, nil, nil, nil, nil, fmt.Errorf(
|
|
"unable to read genesis: %w",
|
|
err,
|
|
)
|
|
}
|
|
snowCtx.Log.Info("loaded genesis", zap.Any("genesis", c.genesis))
|
|
|
|
// Create DBs
|
|
blockDB, stateDB, metaDB, err := hstorage.New(snowCtx.ChainDataDir, gatherer)
|
|
if err != nil {
|
|
return nil, nil, nil, nil, nil, nil, nil, nil, nil, err
|
|
}
|
|
c.metaDB = metaDB
|
|
|
|
// Create handlers
|
|
//
|
|
// hypersdk handler are initiatlized automatically, you just need to
|
|
// initialize custom handlers here.
|
|
apis := map[string]*common.HTTPHandler{}
|
|
jsonRPCHandler, err := hrpc.NewJSONRPCHandler(
|
|
consts.Name,
|
|
rpc.NewJSONRPCServer(c),
|
|
common.NoLock,
|
|
)
|
|
if err != nil {
|
|
return nil, nil, nil, nil, nil, nil, nil, nil, nil, err
|
|
}
|
|
apis[rpc.JSONRPCEndpoint] = jsonRPCHandler
|
|
|
|
// Create builder and gossiper
|
|
var (
|
|
build builder.Builder
|
|
gossip gossiper.Gossiper
|
|
)
|
|
if c.config.TestMode {
|
|
c.inner.Logger().Info("running build and gossip in test mode")
|
|
build = builder.NewManual(inner)
|
|
gossip = gossiper.NewManual(inner)
|
|
} else {
|
|
build = builder.NewTime(inner)
|
|
gcfg := gossiper.DefaultProposerConfig()
|
|
gossip = gossiper.NewProposer(inner, gcfg)
|
|
}
|
|
|
|
// TODO: not sure if `time.Now().Unix()` is safe to be used here
|
|
c.oracle = oracle.NewOracle(c, time.Now().Unix(), c.config.TrackedStocks)
|
|
|
|
return c.config, c.genesis, build, gossip, blockDB, stateDB, apis, consts.ActionRegistry, consts.AuthRegistry, nil
|
|
}
|
|
|
|
func (c *Controller) Rules(t int64) chain.Rules {
|
|
// TODO: extend with [UpgradeBytes]
|
|
return c.genesis.Rules(t, c.snowCtx.NetworkID, c.snowCtx.ChainID)
|
|
}
|
|
|
|
func (c *Controller) StateManager() chain.StateManager {
|
|
return c.stateManager
|
|
}
|
|
|
|
func (c *Controller) Accepted(ctx context.Context, blk *chain.StatelessBlock) error {
|
|
batch := c.metaDB.NewBatch()
|
|
defer batch.Reset()
|
|
|
|
results := blk.Results()
|
|
for i, tx := range blk.Txs {
|
|
result := results[i]
|
|
if c.config.GetStoreTransactions() {
|
|
err := storage.StoreTransaction(
|
|
ctx,
|
|
batch,
|
|
tx.ID(),
|
|
blk.GetTimestamp(),
|
|
result.Success,
|
|
result.Units,
|
|
)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
if result.Success {
|
|
switch tx.Action.(type) { //nolint:gocritic
|
|
case *actions.Transfer:
|
|
c.metrics.transfer.Inc()
|
|
case *actions.UploadEntity:
|
|
c.metrics.upload.Inc()
|
|
entityWithMeta, err := oracle.UnmarshalEntityWithMeta(result.Output)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
c.Logger().Debug("UploadEntity Triggered")
|
|
c.Logger().Debug(string(result.Output))
|
|
c.oracle.InsertEntity(entityWithMeta.ID, entityWithMeta.Type, entityWithMeta.Entity)
|
|
|
|
case *actions.Query:
|
|
c.metrics.query.Inc()
|
|
}
|
|
}
|
|
}
|
|
|
|
// store aggregation result
|
|
for i := 0; i < int(c.oracle.Counter()); i++ {
|
|
aggretationResult, err := c.oracle.GetAggregatedResult(uint64(i))
|
|
if err != nil {
|
|
c.Logger().Debug(fmt.Sprintf("entity %d has an emtpy record for this block: %+v", i, err))
|
|
continue
|
|
}
|
|
|
|
entityIndex, entityType, err := c.oracle.GetEntityMeta(uint64(i))
|
|
// should never happen
|
|
if err != nil {
|
|
continue
|
|
}
|
|
c.Logger().Debug(fmt.Sprintf("%+v", aggretationResult))
|
|
storage.StoreAggregationResult(ctx, batch, entityType, entityIndex, blk.GetTimestamp(), aggretationResult.Marshal())
|
|
storage.CacheAggregationResult(ctx, batch, entityType, entityIndex, blk.GetTimestamp(), aggretationResult.Marshal())
|
|
}
|
|
|
|
// c.oracle.ClearEntityCollection()
|
|
c.oracle.ClearOracleNSaveHistory()
|
|
|
|
count, _ := c.oracle.GetEntityCollectionCount(0)
|
|
c.Logger().Debug(fmt.Sprintf("%+d", count))
|
|
|
|
return batch.Write()
|
|
}
|
|
|
|
func (*Controller) Rejected(context.Context, *chain.StatelessBlock) error {
|
|
return nil
|
|
}
|
|
|
|
func (*Controller) Shutdown(context.Context) error {
|
|
// Do not close any databases provided during initialization. The VM will
|
|
// close any databases your provided.
|
|
return nil
|
|
}
|