diff --git a/go/enclave/enclave.go b/go/enclave/enclave.go index 9f49959ba..6846cc419 100644 --- a/go/enclave/enclave.go +++ b/go/enclave/enclave.go @@ -7,7 +7,6 @@ import ( "fmt" "math/big" - "github.com/ten-protocol/go-ten/go/common/compression" enclaveconfig "github.com/ten-protocol/go-ten/go/enclave/config" "github.com/ten-protocol/go-ten/go/enclave/evm/ethchainadapter" "github.com/ten-protocol/go-ten/go/enclave/gas" @@ -16,9 +15,6 @@ import ( "github.com/ten-protocol/go-ten/go/enclave/txpool" "github.com/ten-protocol/go-ten/go/enclave/components" - "github.com/ten-protocol/go-ten/go/enclave/nodetype" - - "github.com/ten-protocol/go-ten/go/enclave/l2chain" "github.com/ten-protocol/go-ten/go/responses" "github.com/ten-protocol/go-ten/go/enclave/genesis" @@ -26,18 +22,14 @@ import ( "github.com/ten-protocol/go-ten/go/common/errutil" "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/crypto/ecies" "github.com/ten-protocol/go-ten/go/common" "github.com/ten-protocol/go-ten/go/common/gethencoding" "github.com/ten-protocol/go-ten/go/common/log" "github.com/ten-protocol/go-ten/go/common/stopcontrol" "github.com/ten-protocol/go-ten/go/common/tracers" "github.com/ten-protocol/go-ten/go/enclave/crosschain" - "github.com/ten-protocol/go-ten/go/enclave/crypto" - "github.com/ten-protocol/go-ten/go/enclave/debugger" "github.com/ten-protocol/go-ten/go/enclave/events" - "github.com/ten-protocol/go-ten/go/enclave/rpc" "github.com/ten-protocol/go-ten/go/ethadapter/mgmtcontractlib" _ "github.com/ten-protocol/go-ten/go/common/tracers/native" // make sure the tracers are loaded @@ -62,141 +54,66 @@ func NewEnclave(config *enclaveconfig.EnclaveConfig, genesis *genesis.Genesis, m jsonConfig, _ := json.MarshalIndent(config, "", " ") logger.Info("Creating enclave service with following config", log.CfgKey, string(jsonConfig)) - // todo (#1053) - add the delay: N hashes + chainConfig := ethchainadapter.ChainParams(big.NewInt(config.ObscuroChainID)) // Initialise the database cachingService := storage.NewCacheService(logger, config.UseInMemoryDB) - chainConfig := ethchainadapter.ChainParams(big.NewInt(config.ObscuroChainID)) storage := storage.NewStorageFromConfig(config, cachingService, chainConfig, logger) - // todo (#1474) - make sure the enclave cannot be started in production with WillAttest=false - var attestationProvider components.AttestationProvider - if config.WillAttest { - attestationProvider = &components.EgoAttestationProvider{} - } else { - logger.Info("WARNING - Attestation is not enabled, enclave will not create a verified attestation report.") - attestationProvider = &components.DummyAttestationProvider{} - } - - enclaveKeyService := components.NewEnclaveKeyService(storage, logger) // attempt to fetch the enclave key from the database // the enclave key is part of the attestation and identifies the current enclave + enclaveKeyService := components.NewEnclaveKeyService(storage, logger) err := enclaveKeyService.LoadOrCreateEnclaveKey() if err != nil { logger.Crit("Failed to load or create enclave key", "err", err) } gethEncodingService := gethencoding.NewGethEncodingService(storage, cachingService, logger) - dataEncryptionService := crypto.NewDataEncryptionService(logger) - dataCompressionService := compression.NewBrotliDataCompressionService() crossChainProcessors := crosschain.New(&config.MessageBusAddress, storage, big.NewInt(config.ObscuroChainID), logger) + + // initialise system contracts scb := system.NewSystemContractCallbacks(storage, &config.SystemContractOwner, logger) + err = scb.Load() + if err != nil && !errors.Is(err, errutil.ErrNotFound) { + logger.Crit("failed to load system contracts", log.ErrKey, err) + } gasOracle := gas.NewGasOracle() blockProcessor := components.NewBlockProcessor(storage, crossChainProcessors, gasOracle, logger) - registry := components.NewBatchRegistry(storage, config, gethEncodingService, logger) - batchExecutor := components.NewBatchExecutor(storage, registry, *config, gethEncodingService, crossChainProcessors, genesis, gasOracle, chainConfig, config.GasBatchExecutionLimit, scb, logger) - sigVerifier, err := components.NewSignatureValidator(storage) - rProducer := components.NewRollupProducer(enclaveKeyService.EnclaveID(), storage, registry, logger) + batchRegistry := components.NewBatchRegistry(storage, config, gethEncodingService, logger) + batchExecutor := components.NewBatchExecutor(storage, batchRegistry, *config, gethEncodingService, crossChainProcessors, genesis, gasOracle, chainConfig, config.GasBatchExecutionLimit, scb, logger) + + // ensure cached chain state data is up-to-date using the persisted batch data + err = restoreStateDBCache(context.Background(), storage, batchRegistry, batchExecutor, genesis, logger) if err != nil { - logger.Crit("Could not initialise the signature validator", log.ErrKey, err) + logger.Crit("failed to resync L2 chain state DB after restart", log.ErrKey, err) } - // start all mempools in validate only - mempool, err := txpool.NewTxPool(registry.EthChain(), config.MinGasPrice, true, logger) + // start the mempool in validate only. Based on the config, it might become sequencer + mempool, err := txpool.NewTxPool(batchRegistry.EthChain(), config.MinGasPrice, true, logger) if err != nil { logger.Crit("unable to init eth tx pool", log.ErrKey, err) } - rollupCompression := components.NewRollupCompression(registry, batchExecutor, dataEncryptionService, dataCompressionService, storage, gethEncodingService, chainConfig, logger) - rConsumer := components.NewRollupConsumer(mgmtContractLib, registry, rollupCompression, storage, logger, sigVerifier) - sharedSecretProcessor := components.NewSharedSecretProcessor(mgmtContractLib, attestationProvider, enclaveKeyService.EnclaveID(), storage, logger) - - var service nodetype.NodeType - if config.NodeType == common.ActiveSequencer { - mempool.SetValidateMode(false) - // Todo - this is temporary - until the host calls `AddSequencer` - err := storage.StoreNewEnclave(context.Background(), enclaveKeyService.EnclaveID(), enclaveKeyService.PublicKey()) - if err != nil { - logger.Crit("Failed to store enclave key", log.ErrKey, err) - return nil - } - err = storage.StoreNodeType(context.Background(), enclaveKeyService.EnclaveID(), common.ActiveSequencer) - if err != nil { - logger.Crit("Failed to store node type", log.ErrKey, err) - return nil - } - - // todo - next PR - update the service logic to be swappable - service = nodetype.NewSequencer( - blockProcessor, - batchExecutor, - registry, - rProducer, - rollupCompression, - gethEncodingService, - logger, - chainConfig, - enclaveKeyService, - mempool, - storage, - dataEncryptionService, - dataCompressionService, - nodetype.SequencerSettings{ - MaxBatchSize: config.MaxBatchSize, - MaxRollupSize: config.MaxRollupSize, - GasPaymentAddress: config.GasPaymentAddress, - BatchGasLimit: config.GasBatchExecutionLimit, - BaseFee: config.BaseFee, - }, - ) + subscriptionManager := events.NewSubscriptionManager(storage, batchRegistry, config.ObscuroChainID, logger) + + // todo (#1474) - make sure the enclave cannot be started in production with WillAttest=false + var attestationProvider components.AttestationProvider + if config.WillAttest { + attestationProvider = &components.EgoAttestationProvider{} } else { - service = nodetype.NewValidator( - blockProcessor, - batchExecutor, - registry, - chainConfig, - storage, - sigVerifier, - mempool, - logger, - ) + logger.Info("WARNING - Attestation is not enabled, enclave will not create a verified attestation report.") + attestationProvider = &components.DummyAttestationProvider{} } - chain := l2chain.NewChain( - storage, - *config, - gethEncodingService, - chainConfig, - genesis, - logger, - registry, - config.GasLocalExecutionCapFlag, - ) - // todo - security - obscuroKey := crypto.GetObscuroKey(logger) - - rpcEncryptionManager := rpc.NewEncryptionManager(ecies.ImportECDSA(obscuroKey), storage, cachingService, registry, mempool, crossChainProcessors, config, gasOracle, storage, blockProcessor, chain, logger) - subscriptionManager := events.NewSubscriptionManager(storage, registry, config.ObscuroChainID, logger) - - // ensure cached chain state data is up-to-date using the persisted batch data - err = restoreStateDBCache(context.Background(), storage, registry, batchExecutor, genesis, logger) - if err != nil { - logger.Crit("failed to resync L2 chain state DB after restart", log.ErrKey, err) - } + // signal to stop the enclave + stopControl := stopcontrol.New() - err = scb.Load() - if err != nil && !errors.Is(err, errutil.ErrNotFound) { - logger.Crit("failed to load system contracts", log.ErrKey, err) - } + initService := NewEnclaveInitService(config, storage, logger, blockProcessor, enclaveKeyService, attestationProvider) + adminService := NewEnclaveAdminService(config, storage, logger, blockProcessor, batchRegistry, batchExecutor, gethEncodingService, stopControl, subscriptionManager, enclaveKeyService, mempool, chainConfig, mgmtContractLib, attestationProvider) + rpcService := NewEnclaveRPCService(config, storage, logger, blockProcessor, batchRegistry, gethEncodingService, cachingService, mempool, chainConfig, crossChainProcessors, scb, subscriptionManager, genesis, gasOracle) - // TODO ensure debug is allowed/disallowed - debug := debugger.New(chain, storage, chainConfig) - stopControl := stopcontrol.New() - initService := NewEnclaveInitService(config, storage, blockProcessor, logger, enclaveKeyService, attestationProvider) - adminService := NewEnclaveAdminService(config, logger, blockProcessor, service, sharedSecretProcessor, rConsumer, registry, dataEncryptionService, dataCompressionService, storage, gethEncodingService, stopControl, subscriptionManager, enclaveKeyService, mempool) - rpcService := NewEnclaveRPCService(rpcEncryptionManager, registry, subscriptionManager, config, debug, storage, crossChainProcessors, scb) logger.Info("Enclave service created successfully.", log.EnclaveIDKey, enclaveKeyService.EnclaveID()) return &enclaveImpl{ initService: initService, diff --git a/go/enclave/enclave_admin_service.go b/go/enclave/enclave_admin_service.go index aa97b2f0d..8c53d5fbd 100644 --- a/go/enclave/enclave_admin_service.go +++ b/go/enclave/enclave_admin_service.go @@ -8,6 +8,9 @@ import ( "sync" "time" + "github.com/ethereum/go-ethereum/params" + "github.com/ten-protocol/go-ten/go/ethadapter/mgmtcontractlib" + "github.com/ten-protocol/go-ten/go/enclave/txpool" gethcommon "github.com/ethereum/go-ethereum/common" @@ -37,6 +40,8 @@ type enclaveAdminService struct { mainMutex sync.Mutex // serialises all data ingestion or creation to avoid weird races logger gethlog.Logger l1BlockProcessor components.L1BlockProcessor + validatorService nodetype.Validator + sequencerService nodetype.ActiveSequencer service nodetype.NodeType sharedSecretProcessor *components.SharedSecretProcessor rollupConsumer components.RollupConsumer @@ -52,7 +57,7 @@ type enclaveAdminService struct { mempool *txpool.TxPool } -func NewEnclaveAdminService(config *enclaveconfig.EnclaveConfig, logger gethlog.Logger, l1BlockProcessor components.L1BlockProcessor, service nodetype.NodeType, sharedSecretProcessor *components.SharedSecretProcessor, rollupConsumer components.RollupConsumer, registry components.BatchRegistry, dataEncryptionService crypto.DataEncryptionService, dataCompressionService compression.DataCompressionService, storage storage.Storage, gethEncodingService gethencoding.EncodingService, stopControl *stopcontrol.StopControl, subscriptionManager *events.SubscriptionManager, enclaveKeyService *components.EnclaveKeyService, mempool *txpool.TxPool) common.EnclaveAdmin { +func NewEnclaveAdminService(config *enclaveconfig.EnclaveConfig, storage storage.Storage, logger gethlog.Logger, blockProcessor components.L1BlockProcessor, registry components.BatchRegistry, batchExecutor components.BatchExecutor, gethEncodingService gethencoding.EncodingService, stopControl *stopcontrol.StopControl, subscriptionManager *events.SubscriptionManager, enclaveKeyService *components.EnclaveKeyService, mempool *txpool.TxPool, chainConfig *params.ChainConfig, mgmtContractLib mgmtcontractlib.MgmtContractLib, attestationProvider components.AttestationProvider) common.EnclaveAdmin { var prof *profiler.Profiler // don't run a profiler on an attested enclave if !config.WillAttest && config.ProfilerEnabled { @@ -62,13 +67,77 @@ func NewEnclaveAdminService(config *enclaveconfig.EnclaveConfig, logger gethlog. logger.Crit("unable to start the profiler", log.ErrKey, err) } } + sharedSecretProcessor := components.NewSharedSecretProcessor(mgmtContractLib, attestationProvider, enclaveKeyService.EnclaveID(), storage, logger) + + dataEncryptionService := crypto.NewDataEncryptionService(logger) + dataCompressionService := compression.NewBrotliDataCompressionService() + rProducer := components.NewRollupProducer(enclaveKeyService.EnclaveID(), storage, registry, logger) + rollupCompression := components.NewRollupCompression(registry, batchExecutor, dataEncryptionService, dataCompressionService, storage, gethEncodingService, chainConfig, logger) + sigVerifier, err := components.NewSignatureValidator(storage) + if err != nil { + logger.Crit("Could not initialise the signature validator", log.ErrKey, err) + } + rollupConsumer := components.NewRollupConsumer(mgmtContractLib, registry, rollupCompression, storage, logger, sigVerifier) + + sequencerService := nodetype.NewSequencer( + blockProcessor, + batchExecutor, + registry, + rProducer, + rollupCompression, + gethEncodingService, + logger, + chainConfig, + enclaveKeyService, + mempool, + storage, + dataEncryptionService, + dataCompressionService, + nodetype.SequencerSettings{ + MaxBatchSize: config.MaxBatchSize, + MaxRollupSize: config.MaxRollupSize, + GasPaymentAddress: config.GasPaymentAddress, + BatchGasLimit: config.GasBatchExecutionLimit, + BaseFee: config.BaseFee, + }, + ) + + validatorService := nodetype.NewValidator( + blockProcessor, + batchExecutor, + registry, + chainConfig, + storage, + sigVerifier, + mempool, + logger, + ) + + var service nodetype.NodeType = validatorService + if config.NodeType == common.ActiveSequencer { + mempool.SetValidateMode(false) + // Todo - this is temporary - until the host calls `AddSequencer` + err := storage.StoreNewEnclave(context.Background(), enclaveKeyService.EnclaveID(), enclaveKeyService.PublicKey()) + if err != nil { + logger.Crit("Failed to store enclave key", log.ErrKey, err) + return nil + } + err = storage.StoreNodeType(context.Background(), enclaveKeyService.EnclaveID(), common.ActiveSequencer) + if err != nil { + logger.Crit("Failed to store node type", log.ErrKey, err) + return nil + } + service = sequencerService + } return &enclaveAdminService{ config: config, mainMutex: sync.Mutex{}, logger: logger, - l1BlockProcessor: l1BlockProcessor, + l1BlockProcessor: blockProcessor, service: service, + sequencerService: sequencerService, + validatorService: validatorService, sharedSecretProcessor: sharedSecretProcessor, rollupConsumer: rollupConsumer, registry: registry, diff --git a/go/enclave/enclave_init_service.go b/go/enclave/enclave_init_service.go index 9f540783d..e4c5941f6 100644 --- a/go/enclave/enclave_init_service.go +++ b/go/enclave/enclave_init_service.go @@ -33,7 +33,7 @@ type enclaveInitService struct { attestationProvider components.AttestationProvider // interface for producing attestation reports and verifying them } -func NewEnclaveInitService(config *enclaveconfig.EnclaveConfig, storage storage.Storage, l1BlockProcessor components.L1BlockProcessor, logger gethlog.Logger, enclaveKeyService *components.EnclaveKeyService, attestationProvider components.AttestationProvider) common.EnclaveInit { +func NewEnclaveInitService(config *enclaveconfig.EnclaveConfig, storage storage.Storage, logger gethlog.Logger, l1BlockProcessor components.L1BlockProcessor, enclaveKeyService *components.EnclaveKeyService, attestationProvider components.AttestationProvider) common.EnclaveInit { return &enclaveInitService{ config: config, storage: storage, diff --git a/go/enclave/enclave_rpc_service.go b/go/enclave/enclave_rpc_service.go index 52480be54..77cb191eb 100644 --- a/go/enclave/enclave_rpc_service.go +++ b/go/enclave/enclave_rpc_service.go @@ -7,6 +7,16 @@ import ( "fmt" "math/big" + "github.com/ethereum/go-ethereum/crypto/ecies" + gethlog "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/params" + "github.com/ten-protocol/go-ten/go/common/gethencoding" + "github.com/ten-protocol/go-ten/go/enclave/crypto" + "github.com/ten-protocol/go-ten/go/enclave/gas" + "github.com/ten-protocol/go-ten/go/enclave/genesis" + "github.com/ten-protocol/go-ten/go/enclave/l2chain" + "github.com/ten-protocol/go-ten/go/enclave/txpool" + gethcommon "github.com/ethereum/go-ethereum/common" "github.com/ten-protocol/go-ten/go/common" "github.com/ten-protocol/go-ten/go/common/syserr" @@ -32,18 +42,38 @@ type enclaveRPCService struct { storage storage.Storage crossChainProcessors *crosschain.Processors scb system.SystemContractCallbacks + logger gethlog.Logger } -func NewEnclaveRPCService(rpcEncryptionManager *rpc.EncryptionManager, registry components.BatchRegistry, subscriptionManager *events.SubscriptionManager, config *enclaveconfig.EnclaveConfig, debugger *debugger.Debugger, storage storage.Storage, crossChainProcessors *crosschain.Processors, scb system.SystemContractCallbacks) common.EnclaveClientRPC { +func NewEnclaveRPCService(config *enclaveconfig.EnclaveConfig, storage storage.Storage, logger gethlog.Logger, blockProcessor components.L1BlockProcessor, batchRegistry components.BatchRegistry, gethEncodingService gethencoding.EncodingService, cachingService *storage.CacheService, mempool *txpool.TxPool, chainConfig *params.ChainConfig, crossChainProcessors *crosschain.Processors, scb system.SystemContractCallbacks, subscriptionManager *events.SubscriptionManager, genesis *genesis.Genesis, gasOracle gas.Oracle) common.EnclaveClientRPC { + // TODO ensure debug is allowed/disallowed + chain := l2chain.NewChain( + storage, + *config, + gethEncodingService, + chainConfig, + genesis, + logger, + batchRegistry, + config.GasLocalExecutionCapFlag, + ) + debug := debugger.New(chain, storage, chainConfig) + + // todo - security + obscuroKey := crypto.GetObscuroKey(logger) + + rpcEncryptionManager := rpc.NewEncryptionManager(ecies.ImportECDSA(obscuroKey), storage, cachingService, batchRegistry, mempool, crossChainProcessors, config, gasOracle, storage, blockProcessor, chain, logger) + return &enclaveRPCService{ rpcEncryptionManager: rpcEncryptionManager, - registry: registry, + registry: batchRegistry, subscriptionManager: subscriptionManager, config: config, - debugger: debugger, + debugger: debug, storage: storage, crossChainProcessors: crossChainProcessors, scb: scb, + logger: logger, } } diff --git a/go/enclave/nodetype/interfaces.go b/go/enclave/nodetype/interfaces.go index 699e87dbb..3eacd1bef 100644 --- a/go/enclave/nodetype/interfaces.go +++ b/go/enclave/nodetype/interfaces.go @@ -33,15 +33,6 @@ type ActiveSequencer interface { NodeType } -type BackupSequencer interface { - // ExecuteStoredBatches - try to execute all stored by unexecuted batches - ExecuteStoredBatches(context.Context) error - - VerifySequencerSignature(*core.Batch) error - - NodeType -} - type Validator interface { // ExecuteStoredBatches - try to execute all stored by unexecuted batches ExecuteStoredBatches(context.Context) error