Skip to content

Commit

Permalink
♻️ Implement initialization of fault detector
Browse files Browse the repository at this point in the history
  • Loading branch information
ishantiw committed Jan 24, 2024
1 parent 6a8fa43 commit 09749c8
Show file tree
Hide file tree
Showing 7 changed files with 332 additions and 11 deletions.
17 changes: 17 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.1.0",
"configurations": [
{
"name": "Run Fault Detector",
"type": "go",
"request": "launch",
"mode": "auto",
"program": "${workspaceRoot}/cmd",
"args": ["--config", "./config.yaml"],
"showLog": true
}
]
}
21 changes: 18 additions & 3 deletions cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,13 @@ import (

"github.com/LiskHQ/op-fault-detector/pkg/api"
"github.com/LiskHQ/op-fault-detector/pkg/config"
"github.com/LiskHQ/op-fault-detector/pkg/faultdetector"
"github.com/LiskHQ/op-fault-detector/pkg/log"
"github.com/spf13/viper"
)

var apiServer *api.HTTPServer
var faultDetector *faultdetector.FaultDetector

func main() {
ctx, cancel := context.WithCancel(context.Background())
Expand All @@ -42,12 +44,24 @@ func main() {
doneChan := make(chan struct{})
signalChan := make(chan os.Signal, 1)
signal.Notify(signalChan, os.Interrupt, syscall.SIGTERM)
errorChan := make(chan error, 1)

// Start Fault Detector
faultDetector, err = faultdetector.NewFaultDetector(
ctx,
logger,
errorChan,
&wg,
config,
)
if err != nil {
panic(err)
}
wg.Add(1)
go faultDetector.Start()

// Start API Server
serverChan := make(chan error, 1)
apiServer = api.NewHTTPServer(ctx, logger, &wg, config, serverChan)
apiServer = api.NewHTTPServer(ctx, logger, &wg, config, errorChan)
wg.Add(1)
go apiServer.Start()

Expand All @@ -66,7 +80,7 @@ func main() {
performCleanup(logger)
return

case err := <-serverChan:
case err := <-errorChan:
logger.Errorf("Received error of %v", err)
return
}
Expand Down Expand Up @@ -106,6 +120,7 @@ func getAppConfig(logger log.Logger, configFilepath string) (*config.Config, err
}

func performCleanup(logger log.Logger) {
faultDetector.Stop()
err := apiServer.Stop()
if err != nil {
logger.Error("Server shutdown not successful: %w", err)
Expand Down
4 changes: 4 additions & 0 deletions config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,7 @@ api:

# Faultdetector configurations
fault_detector:
l1_rpc_endpoint: "https://rpc.notadegen.com/eth"
l2_rpc_endpoint: "https://mainnet.optimism.io/"
start_batch_index: 0
l2_output_oracle_contract_address: "0x0000000000000000000000000000000000000000"
27 changes: 26 additions & 1 deletion pkg/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ import (
"go.uber.org/multierr"
)

const (
ProviderRegex = `^(http|https|ws|wss)://`
AddressRegex = `(\b0x[a-f0-9]{40}\b)`
)

// Config struct is used to store the contents of the parsed config file.
// The properties (sub-properties) should map on-to-one with the config file.
type Config struct {
Expand Down Expand Up @@ -40,6 +45,10 @@ type Server struct {

// FaultDetector struct is used to store the contents of the 'fault_detector' property from the parsed config file.
type FaultDetector struct {
L1RPCEndpoint string `mapstructure:"l1_rpc_endpoint"`
L2RPCEndpoint string `mapstructure:"l2_rpc_endpoint"`
Startbatchindex int64 `mapstructure:"start_batch_index"`
L2OutputOracleContractAddress string `mapstructure:"l2_output_oracle_contract_address"`
}

func formatError(validationErrors error) error {
Expand Down Expand Up @@ -128,5 +137,21 @@ func (c *Server) Validate() error {

// Validate runs validations against an instance of the FaultDetector struct and returns an error when applicable.
func (c *FaultDetector) Validate() error {
return nil
var validationErrors error

l1ProviderMatched, _ := regexp.MatchString(ProviderRegex, c.L1RPCEndpoint)
if !l1ProviderMatched {
validationErrors = multierr.Append(validationErrors, fmt.Errorf("faultdetector.l1_rpc_endpoint expected to match regex: `%s`, received: '%s'", ProviderRegex, c.L1RPCEndpoint))
}
l2ProviderMatched, _ := regexp.MatchString(ProviderRegex, c.L2RPCEndpoint)
if !l2ProviderMatched {
validationErrors = multierr.Append(validationErrors, fmt.Errorf("faultdetector.l2_rpc_endpoint expected to match regex: `%s`, received: '%s'", ProviderRegex, c.L2RPCEndpoint))
}

addressMatched, _ := regexp.MatchString(AddressRegex, c.L2OutputOracleContractAddress)
if !addressMatched {
validationErrors = multierr.Append(validationErrors, fmt.Errorf("faultdetector.l2_output_oracle_contract_address expected to match regex: `%s`, received: '%s'", AddressRegex, c.L2OutputOracleContractAddress))
}

return validationErrors
}
150 changes: 145 additions & 5 deletions pkg/config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -231,13 +231,73 @@ func TestValidate_Api(t *testing.T) {
}
}

// TODO: Update test table when implementing the fault detector
func TestValidate_FaultDetector(t *testing.T) {
testCases := []struct {
name string
config *FaultDetector
want error
}{}
}{
{
name: "should return nil when correct http/https endpoints are given",
config: &FaultDetector{
L1RPCEndpoint: "https://xyz.com",
L2RPCEndpoint: "http://xyz.com",
Startbatchindex: 100,
L2OutputOracleContractAddress: "0x0000000000000000000000000000000000000000",
},
want: nil,
},
{
name: "should return nil when correct ws/wss endpoints are given",
config: &FaultDetector{
L1RPCEndpoint: "wss://xyz.com",
L2RPCEndpoint: "ws://xyz.com",
Startbatchindex: 100,
L2OutputOracleContractAddress: "0x0000000000000000000000000000000000000000",
},
want: nil,
},
{
name: "should return error when invalid l1 provider endpoint is given",
config: &FaultDetector{
L1RPCEndpoint: "://xyz.com",
L2RPCEndpoint: "http://xyz.com",
Startbatchindex: 100,
L2OutputOracleContractAddress: "0x0000000000000000000000000000000000000000",
},
want: fmt.Errorf("faultdetector.l1_rpc_endpoint expected to match regex: `%s`, received: '://xyz.com'", ProviderRegex),
},
{
name: "should return error when invalid l2 provider endpoint is given",
config: &FaultDetector{
L1RPCEndpoint: "http://xyz.com",
L2RPCEndpoint: "ht://xyz.com",
Startbatchindex: 100,
L2OutputOracleContractAddress: "0x0000000000000000000000000000000000000000",
},
want: fmt.Errorf("faultdetector.l2_rpc_endpoint expected to match regex: `%s`, received: 'ht://xyz.com'", ProviderRegex),
},
{
name: "should return error when invalid address length",
config: &FaultDetector{
L1RPCEndpoint: "http://xyz.com",
L2RPCEndpoint: "http://xyz.com",
Startbatchindex: 100,
L2OutputOracleContractAddress: "randomAddress",
},
want: fmt.Errorf("faultdetector.l2_output_oracle_contract_address expected to match regex: `%s`, received: 'randomAddress'", AddressRegex),
},
{
name: "should return error when invalid address beginning",
config: &FaultDetector{
L1RPCEndpoint: "http://xyz.com",
L2RPCEndpoint: "http://xyz.com",
Startbatchindex: 100,
L2OutputOracleContractAddress: "xx0000000000000000000000000000000000000000",
},
want: fmt.Errorf("faultdetector.l2_output_oracle_contract_address expected to match regex: `%s`, received: 'xx0000000000000000000000000000000000000000'", AddressRegex),
},
}

t.Parallel()
for _, tc := range testCases {
Expand Down Expand Up @@ -316,7 +376,12 @@ func TestValidate_Config(t *testing.T) {
"/api",
[]string{"v1"},
},
&FaultDetector{},
&FaultDetector{
L1RPCEndpoint: "https://xyz.com",
L2RPCEndpoint: "http://xyz.com",
Startbatchindex: 100,
L2OutputOracleContractAddress: "0x0000000000000000000000000000000000000000",
},
},
want: nil,
},
Expand All @@ -334,7 +399,12 @@ func TestValidate_Config(t *testing.T) {
"/api",
[]string{"v1"},
},
&FaultDetector{},
&FaultDetector{
L1RPCEndpoint: "https://xyz.com",
L2RPCEndpoint: "http://xyz.com",
Startbatchindex: 100,
L2OutputOracleContractAddress: "0x0000000000000000000000000000000000000000",
},
},
want: formatError(
fmt.Errorf("api.server.port expected in range: %d - %d, received: %d", uint(0), uint(math.Pow(2, 16)-1), 543210),
Expand All @@ -354,7 +424,12 @@ func TestValidate_Config(t *testing.T) {
"api/",
[]string{"v1", "version1"},
},
&FaultDetector{},
&FaultDetector{
L1RPCEndpoint: "https://xyz.com",
L2RPCEndpoint: "http://xyz.com",
Startbatchindex: 100,
L2OutputOracleContractAddress: "0x0000000000000000000000000000000000000000",
},
},
want: formatError(
multierr.Combine(
Expand All @@ -369,6 +444,71 @@ func TestValidate_Config(t *testing.T) {
),
),
},
{
name: "should return error when incorrect L1RPCEndpoint is provided",
config: &Config{
&System{
"info",
},
&Api{
&Server{
"127.0.0.256",
8080,
},
"/api",
[]string{"v1"},
},
&FaultDetector{
L1RPCEndpoint: "htps://xyz.com",
L2RPCEndpoint: "http://xyz.com",
Startbatchindex: 100,
L2OutputOracleContractAddress: "0x0000000000000000000000000000000000000000",
},
},
want: formatError(
multierr.Combine(
fmt.Errorf(
"api.server.host expected to match regex: `%v`, received: '%v'",
`^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$`,
"127.0.0.256",
),
fmt.Errorf("faultdetector.l1_rpc_endpoint expected to match regex: `%s`, received: 'htps://xyz.com'", ProviderRegex),
),
),
},
{
name: "should return error when incorrect L2OutputOracleContractAddress is provided",
config: &Config{
&System{
"info",
},
&Api{
&Server{
"127.0.0.256",
8080,
},
"/api",
[]string{"v1"},
},
&FaultDetector{
L1RPCEndpoint: "https://xyz.com",
L2RPCEndpoint: "htps://xyz.com",
Startbatchindex: 100,
L2OutputOracleContractAddress: "xx0000000000000000000000000000000000000000",
},
},
want: formatError(
multierr.Combine(
fmt.Errorf(
"api.server.host expected to match regex: `%v`, received: '%v'",
`^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$`,
"127.0.0.256",
),
fmt.Errorf("faultdetector.l2_rpc_endpoint expected to match regex: `%s`, received: 'htps://xyz.com'", ProviderRegex),
fmt.Errorf("faultdetector.l2_output_oracle_contract_address expected to match regex: `%s`, received: 'xx0000000000000000000000000000000000000000'", AddressRegex),
),
),
},
}

t.Parallel()
Expand Down
2 changes: 0 additions & 2 deletions pkg/fault_detector/fault_detector.go

This file was deleted.

Loading

0 comments on commit 09749c8

Please sign in to comment.