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

TestOnlyProcessingNode - part 1 #5552

Merged
merged 2 commits into from
Sep 4, 2023
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
60 changes: 60 additions & 0 deletions node/processingOnlyNode/configLoaders.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package processingOnlyNode

import (
"os"
"path"
"strconv"
"strings"

"github.com/pelletier/go-toml"
)

// LoadConfigFromFile will try to load the config from the specified file
func LoadConfigFromFile(filename string, config interface{}) error {
data, err := os.ReadFile(filename)
if err != nil {
return err
}

err = toml.Unmarshal(data, config)

return err
Comment on lines +19 to +21
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
err = toml.Unmarshal(data, config)
return err
return toml.Unmarshal(data, config)

}

// GetLatestGasScheduleFilename will parse the provided path and get the latest gas schedule filename
func GetLatestGasScheduleFilename(directory string) (string, error) {
entries, err := os.ReadDir(directory)
if err != nil {
return "", err
}

extension := ".toml"
versionMarker := "V"

highestVersion := 0
filename := ""
for _, entry := range entries {
if entry.IsDir() {
continue
}

name := entry.Name()
splt := strings.Split(name, versionMarker)
if len(splt) != 2 {
continue
}

versionAsString := splt[1][:len(splt[1])-len(extension)]
number, errConversion := strconv.Atoi(versionAsString)
if errConversion != nil {
continue
}

if number > highestVersion {
highestVersion = number
filename = name
}
}

return path.Join(directory, filename), nil
}
19 changes: 19 additions & 0 deletions node/processingOnlyNode/memoryComponents.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package processingOnlyNode

import (
"github.com/multiversx/mx-chain-go/storage"
"github.com/multiversx/mx-chain-go/storage/database"
"github.com/multiversx/mx-chain-go/storage/storageunit"
)

// CreateMemUnit creates a new in-memory storage unit
func CreateMemUnit() storage.Storer {
capacity := uint32(10)
shards := uint32(1)
sizeInBytes := uint64(0)
cache, _ := storageunit.NewCache(storageunit.CacheConfig{Type: storageunit.LRUCache, Capacity: capacity, Shards: shards, SizeInBytes: sizeInBytes})
persist, _ := database.NewlruDB(100000)
unit, _ := storageunit.NewStorageUnit(cache, persist)

return unit
}
214 changes: 214 additions & 0 deletions node/processingOnlyNode/testOnlyProcessingNode.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,214 @@
package processingOnlyNode

import (
"sync"

"github.com/multiversx/mx-chain-core-go/core"
"github.com/multiversx/mx-chain-core-go/core/versioning"
coreData "github.com/multiversx/mx-chain-core-go/data"
hashingFactory "github.com/multiversx/mx-chain-core-go/hashing/factory"
"github.com/multiversx/mx-chain-core-go/marshal"
marshalFactory "github.com/multiversx/mx-chain-core-go/marshal/factory"
"github.com/multiversx/mx-chain-go/common"
"github.com/multiversx/mx-chain-go/common/enablers"
"github.com/multiversx/mx-chain-go/common/factory"
"github.com/multiversx/mx-chain-go/common/forking"
"github.com/multiversx/mx-chain-go/config"
"github.com/multiversx/mx-chain-go/dataRetriever"
dataRetrieverFactory "github.com/multiversx/mx-chain-go/dataRetriever/factory"
"github.com/multiversx/mx-chain-go/process"
"github.com/multiversx/mx-chain-go/process/block/postprocess"
"github.com/multiversx/mx-chain-go/process/economics"
"github.com/multiversx/mx-chain-go/process/smartContract"
"github.com/multiversx/mx-chain-go/sharding"
"github.com/multiversx/mx-chain-go/storage"
storageFactory "github.com/multiversx/mx-chain-go/storage/factory"
)

// ArgsTestOnlyProcessingNode represents the DTO struct for the NewTestOnlyProcessingNode constructor function
type ArgsTestOnlyProcessingNode struct {
Config config.Config
EnableEpochsConfig config.EnableEpochs
EconomicsConfig config.EconomicsConfig
GasScheduleFilename string
WorkingDir string
NumShards uint32
ShardID uint32
}

type testOnlyProcessingNode struct {
RoundNotifier process.RoundNotifier
EpochNotifier process.EpochNotifier
WasmerChangeLocker common.Locker
ArgumentsParser process.ArgumentsParser
TxVersionChecker process.TxVersionCheckerHandler

Marshaller marshal.Marshalizer
Hasher coreData.Hasher
ShardCoordinator sharding.Coordinator
TransactionFeeHandler process.TransactionFeeHandler
AddressPubKeyConverter core.PubkeyConverter
ValidatorPubKeyConverter core.PubkeyConverter
EnableEpochsHandler common.EnableEpochsHandler
PathHandler storage.PathManagerHandler

GasScheduleNotifier core.GasScheduleNotifier
BuiltinFunctionsCostHandler economics.BuiltInFunctionsCostHandler
EconomicsData process.EconomicsDataHandler
DataPool dataRetriever.PoolsHolder
}

// NewTestOnlyProcessingNode creates a new instance of a node that is able to only process transactions
func NewTestOnlyProcessingNode(args ArgsTestOnlyProcessingNode) (*testOnlyProcessingNode, error) {
instance := &testOnlyProcessingNode{
RoundNotifier: forking.NewGenericRoundNotifier(),
EpochNotifier: forking.NewGenericEpochNotifier(),
WasmerChangeLocker: &sync.RWMutex{},
ArgumentsParser: smartContract.NewArgumentParser(),
TxVersionChecker: versioning.NewTxVersionChecker(args.Config.GeneralSettings.MinTransactionVersion),
}

err := instance.createBasicComponents(args)
if err != nil {
return nil, err
}

err = instance.createGasScheduleNotifier(args)
if err != nil {
return nil, err
}

err = instance.createBuiltinFunctionsCostHandler()
if err != nil {
return nil, err
}

err = instance.createEconomicsHandler(args)
if err != nil {
return nil, err
}

err = instance.createDataPool(args)
if err != nil {
return nil, err
}

return instance, nil
}

func (node *testOnlyProcessingNode) createBasicComponents(args ArgsTestOnlyProcessingNode) error {
var err error

node.Marshaller, err = marshalFactory.NewMarshalizer(args.Config.Marshalizer.Type)
if err != nil {
return err
}

node.Hasher, err = hashingFactory.NewHasher(args.Config.Hasher.Type)
if err != nil {
return err
}

node.ShardCoordinator, err = sharding.NewMultiShardCoordinator(args.ShardID, args.NumShards)
if err != nil {
return err
}

node.TransactionFeeHandler, err = postprocess.NewFeeAccumulator()
if err != nil {
return err
}

node.ValidatorPubKeyConverter, err = factory.NewPubkeyConverter(args.Config.ValidatorPubkeyConverter)
if err != nil {
return err
}

node.AddressPubKeyConverter, err = factory.NewPubkeyConverter(args.Config.AddressPubkeyConverter)
if err != nil {
return err
}

node.EnableEpochsHandler, err = enablers.NewEnableEpochsHandler(args.EnableEpochsConfig, node.EpochNotifier)
if err != nil {
return err
}

node.PathHandler, err = storageFactory.CreatePathManager(
storageFactory.ArgCreatePathManager{
WorkingDir: args.WorkingDir,
ChainID: args.Config.GeneralSettings.ChainID,
},
)
if err != nil {
return err
}

return nil
}

func (node *testOnlyProcessingNode) createGasScheduleNotifier(args ArgsTestOnlyProcessingNode) error {
var err error

argsGasSchedule := forking.ArgsNewGasScheduleNotifier{
GasScheduleConfig: config.GasScheduleConfig{
GasScheduleByEpochs: []config.GasScheduleByEpochs{
{
StartEpoch: 0,
FileName: args.GasScheduleFilename,
},
},
},
ConfigDir: "",
EpochNotifier: node.EpochNotifier,
WasmVMChangeLocker: node.WasmerChangeLocker,
}
node.GasScheduleNotifier, err = forking.NewGasScheduleNotifier(argsGasSchedule)

return err
}

func (node *testOnlyProcessingNode) createBuiltinFunctionsCostHandler() error {
var err error

args := &economics.ArgsBuiltInFunctionCost{
GasSchedule: node.GasScheduleNotifier,
ArgsParser: node.ArgumentsParser,
}

node.BuiltinFunctionsCostHandler, err = economics.NewBuiltInFunctionsCost(args)

return err
}

func (node *testOnlyProcessingNode) createEconomicsHandler(args ArgsTestOnlyProcessingNode) error {
var err error

argsEconomicsHandler := economics.ArgsNewEconomicsData{
TxVersionChecker: node.TxVersionChecker,
BuiltInFunctionsCostHandler: node.BuiltinFunctionsCostHandler,
Economics: &args.EconomicsConfig,
EpochNotifier: node.EpochNotifier,
EnableEpochsHandler: node.EnableEpochsHandler,
}

node.EconomicsData, err = economics.NewEconomicsData(argsEconomicsHandler)

return err
}

func (node *testOnlyProcessingNode) createDataPool(args ArgsTestOnlyProcessingNode) error {
var err error

argsDataPool := dataRetrieverFactory.ArgsDataPool{
Config: &args.Config,
EconomicsData: node.EconomicsData,
ShardCoordinator: node.ShardCoordinator,
Marshalizer: node.Marshaller,
PathManager: node.PathHandler,
}

node.DataPool, err = dataRetrieverFactory.NewDataPoolFromConfig(argsDataPool)

return err
}
56 changes: 56 additions & 0 deletions node/processingOnlyNode/testOnlyProcessingNode_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package processingOnlyNode

import (
"testing"

"github.com/multiversx/mx-chain-go/config"
"github.com/stretchr/testify/assert"
)

const pathForMainConfig = "../../cmd/node/config/config.toml"
const pathForEconomicsConfig = "../../cmd/node/config/economics.toml"
const pathForGasSchedules = "../../cmd/node/config/gasSchedules"

func createMockArgsTestOnlyProcessingNode(t *testing.T) ArgsTestOnlyProcessingNode {
mainConfig := config.Config{}
err := LoadConfigFromFile(pathForMainConfig, &mainConfig)
assert.Nil(t, err)

economicsConfig := config.EconomicsConfig{}
err = LoadConfigFromFile(pathForEconomicsConfig, &economicsConfig)
assert.Nil(t, err)

gasScheduleName, err := GetLatestGasScheduleFilename(pathForGasSchedules)
assert.Nil(t, err)

return ArgsTestOnlyProcessingNode{
Config: mainConfig,
EnableEpochsConfig: config.EnableEpochs{},
EconomicsConfig: economicsConfig,
GasScheduleFilename: gasScheduleName,
NumShards: 0,
ShardID: 3,
}
}

func TestNewTestOnlyProcessingNode(t *testing.T) {
t.Parallel()

t.Run("invalid shard configuration should error", func(t *testing.T) {
t.Parallel()

args := createMockArgsTestOnlyProcessingNode(t)
args.ShardID = args.NumShards
node, err := NewTestOnlyProcessingNode(args)
assert.NotNil(t, err)
assert.Nil(t, node)
})
t.Run("should work", func(t *testing.T) {
t.Parallel()

args := createMockArgsTestOnlyProcessingNode(t)
node, err := NewTestOnlyProcessingNode(args)
assert.Nil(t, err)
assert.NotNil(t, node)
})
}