github.com/status-im/status-go@v1.1.0/appdatabase/node_config_test.go (about)

     1  package appdatabase
     2  
     3  import (
     4  	"crypto/rand"
     5  	"database/sql"
     6  	"fmt"
     7  	"math"
     8  	"math/big"
     9  	"sort"
    10  	"testing"
    11  	"time"
    12  
    13  	"github.com/stretchr/testify/require"
    14  
    15  	"github.com/ethereum/go-ethereum/p2p/discv5"
    16  
    17  	"github.com/status-im/status-go/eth-node/crypto"
    18  	"github.com/status-im/status-go/nodecfg"
    19  	"github.com/status-im/status-go/params"
    20  	"github.com/status-im/status-go/t/helpers"
    21  )
    22  
    23  func setupTestDB(t *testing.T) (*sql.DB, func()) {
    24  	db, cleanup, err := helpers.SetupTestSQLDB(DbInitializer{}, "settings-tests-")
    25  	require.NoError(t, err)
    26  	return db, func() { require.NoError(t, cleanup()) }
    27  }
    28  
    29  func TestGetNodeConfig(t *testing.T) {
    30  	db, stop := setupTestDB(t)
    31  	defer stop()
    32  
    33  	nodeConfig := randomNodeConfig()
    34  	require.NoError(t, nodecfg.SaveNodeConfig(db, nodeConfig))
    35  
    36  	dbNodeConfig, err := nodecfg.GetNodeConfigFromDB(db)
    37  	require.NoError(t, err)
    38  	require.Equal(t, nodeConfig, dbNodeConfig)
    39  }
    40  
    41  func TestSaveNodeConfig(t *testing.T) {
    42  	db, stop := setupTestDB(t)
    43  	defer stop()
    44  
    45  	newNodeConfig := randomNodeConfig()
    46  
    47  	require.NoError(t, nodecfg.SaveNodeConfig(db, newNodeConfig))
    48  
    49  	dbNodeConfig, err := nodecfg.GetNodeConfigFromDB(db)
    50  	require.NoError(t, err)
    51  	require.Equal(t, *newNodeConfig, *dbNodeConfig)
    52  }
    53  
    54  func TestMigrateNodeConfig(t *testing.T) {
    55  	// Migration will be run in setupTestDB. If there's an error, that function will fail
    56  	db, stop := setupTestDB(t)
    57  	defer stop()
    58  
    59  	// node_config column should be empty
    60  	var result string
    61  	err := db.QueryRow("SELECT COALESCE(NULL, 'empty')").Scan(&result)
    62  	require.NoError(t, err)
    63  	require.Equal(t, "empty", result)
    64  }
    65  
    66  func randomString() string {
    67  	b := make([]byte, 10)
    68  	_, _ = rand.Read(b)
    69  	return fmt.Sprintf("%x", b)[:10]
    70  }
    71  
    72  func randomBool() bool {
    73  	return randomInt(2) == 1
    74  }
    75  
    76  func randomInt(max int64) int {
    77  	r, _ := rand.Int(rand.Reader, big.NewInt(max))
    78  	return int(r.Int64())
    79  }
    80  
    81  func randomFloat(max int64) float64 {
    82  	r, _ := rand.Int(rand.Reader, big.NewInt(max))
    83  	return float64(r.Int64()) / (1 << 63)
    84  }
    85  
    86  func randomStringSlice() []string {
    87  	m := randomInt(7)
    88  	var result []string
    89  	for i := 0; i < m; i++ {
    90  		result = append(result, randomString())
    91  	}
    92  	sort.Strings(result)
    93  	return result
    94  }
    95  
    96  func randomTopicSlice() []discv5.Topic {
    97  	randomValues := randomStringSlice()
    98  	var result []discv5.Topic
    99  	for _, v := range randomValues {
   100  		result = append(result, discv5.Topic(v))
   101  	}
   102  	return result
   103  }
   104  
   105  func randomTopicLimits() map[discv5.Topic]params.Limits {
   106  	result := make(map[discv5.Topic]params.Limits)
   107  	m := randomInt(7) + 1
   108  	for i := 0; i < m; i++ {
   109  		result[discv5.Topic(fmt.Sprint(i))] = params.Limits{Min: randomInt(2), Max: randomInt(10)}
   110  	}
   111  	return result
   112  }
   113  
   114  func randomCustomNodes() map[string]string {
   115  	result := make(map[string]string)
   116  	m := randomInt(7)
   117  	for i := 0; i < m; i++ {
   118  		result[randomString()] = randomString()
   119  	}
   120  	return result
   121  }
   122  
   123  func randomNodeConfig() *params.NodeConfig {
   124  	privK, _ := crypto.GenerateKey()
   125  
   126  	return &params.NodeConfig{
   127  		NetworkID:                 uint64(int64(randomInt(math.MaxInt64))),
   128  		DataDir:                   randomString(),
   129  		KeyStoreDir:               randomString(),
   130  		NodeKey:                   randomString(),
   131  		NoDiscovery:               randomBool(),
   132  		ListenAddr:                randomString(),
   133  		AdvertiseAddr:             randomString(),
   134  		Name:                      randomString(),
   135  		Version:                   randomString(),
   136  		APIModules:                randomString(),
   137  		TLSEnabled:                randomBool(),
   138  		MaxPeers:                  randomInt(math.MaxInt64),
   139  		MaxPendingPeers:           randomInt(math.MaxInt64),
   140  		EnableStatusService:       randomBool(),
   141  		BridgeConfig:              params.BridgeConfig{Enabled: randomBool()},
   142  		WalletConfig:              params.WalletConfig{Enabled: randomBool()},
   143  		LocalNotificationsConfig:  params.LocalNotificationsConfig{Enabled: randomBool()},
   144  		BrowsersConfig:            params.BrowsersConfig{Enabled: randomBool()},
   145  		PermissionsConfig:         params.PermissionsConfig{Enabled: randomBool()},
   146  		MailserversConfig:         params.MailserversConfig{Enabled: randomBool()},
   147  		Web3ProviderConfig:        params.Web3ProviderConfig{Enabled: randomBool()},
   148  		ConnectorConfig:           params.ConnectorConfig{Enabled: randomBool()},
   149  		SwarmConfig:               params.SwarmConfig{Enabled: randomBool()},
   150  		MailServerRegistryAddress: randomString(),
   151  		HTTPEnabled:               randomBool(),
   152  		HTTPHost:                  randomString(),
   153  		HTTPPort:                  randomInt(math.MaxInt64),
   154  		HTTPVirtualHosts:          randomStringSlice(),
   155  		HTTPCors:                  randomStringSlice(),
   156  		WSEnabled:                 false, // NOTE: leaving ws field idle since we are moving away from the storing the whole config
   157  		WSHost:                    "",
   158  		WSPort:                    0,
   159  		IPCEnabled:                randomBool(),
   160  		IPCFile:                   randomString(),
   161  		LogEnabled:                randomBool(),
   162  		LogMobileSystem:           randomBool(),
   163  		LogDir:                    randomString(),
   164  		LogFile:                   randomString(),
   165  		LogLevel:                  randomString(),
   166  		LogMaxBackups:             randomInt(math.MaxInt64),
   167  		LogMaxSize:                randomInt(math.MaxInt64),
   168  		LogCompressRotated:        randomBool(),
   169  		LogToStderr:               randomBool(),
   170  		UpstreamConfig:            params.UpstreamRPCConfig{Enabled: randomBool(), URL: randomString()},
   171  		ClusterConfig: params.ClusterConfig{
   172  			Enabled:     randomBool(),
   173  			Fleet:       randomString(),
   174  			StaticNodes: randomStringSlice(),
   175  			BootNodes:   randomStringSlice(),
   176  		},
   177  		LightEthConfig: params.LightEthConfig{
   178  			Enabled:            randomBool(),
   179  			DatabaseCache:      randomInt(math.MaxInt64),
   180  			TrustedNodes:       randomStringSlice(),
   181  			MinTrustedFraction: randomInt(math.MaxInt64),
   182  		},
   183  		RegisterTopics: randomTopicSlice(),
   184  		RequireTopics:  randomTopicLimits(),
   185  		PushNotificationServerConfig: params.PushNotificationServerConfig{
   186  			Enabled:   randomBool(),
   187  			GorushURL: randomString(),
   188  			Identity:  privK,
   189  		},
   190  		ShhextConfig: params.ShhextConfig{
   191  			PFSEnabled:                   randomBool(),
   192  			InstallationID:               randomString(),
   193  			MailServerConfirmations:      randomBool(),
   194  			EnableConnectionManager:      randomBool(),
   195  			EnableLastUsedMonitor:        randomBool(),
   196  			ConnectionTarget:             randomInt(math.MaxInt64),
   197  			RequestsDelay:                time.Duration(randomInt(math.MaxInt64)),
   198  			MaxServerFailures:            randomInt(math.MaxInt64),
   199  			MaxMessageDeliveryAttempts:   randomInt(math.MaxInt64),
   200  			WhisperCacheDir:              randomString(),
   201  			DisableGenericDiscoveryTopic: randomBool(),
   202  			SendV1Messages:               randomBool(),
   203  			DataSyncEnabled:              randomBool(),
   204  			VerifyTransactionURL:         randomString(),
   205  			VerifyENSURL:                 randomString(),
   206  			VerifyENSContractAddress:     randomString(),
   207  			VerifyTransactionChainID:     int64(randomInt(math.MaxInt64)),
   208  			AnonMetricsSendID:            randomString(),
   209  			AnonMetricsServerEnabled:     randomBool(),
   210  			AnonMetricsServerPostgresURI: randomString(),
   211  			BandwidthStatsEnabled:        randomBool(),
   212  		},
   213  		WakuV2Config: params.WakuV2Config{
   214  			Enabled:             randomBool(),
   215  			Host:                randomString(),
   216  			Port:                randomInt(math.MaxInt64),
   217  			LightClient:         randomBool(),
   218  			FullNode:            randomBool(),
   219  			DiscoveryLimit:      randomInt(math.MaxInt64),
   220  			DataDir:             randomString(),
   221  			MaxMessageSize:      uint32(randomInt(math.MaxInt64)),
   222  			EnableConfirmations: randomBool(),
   223  			CustomNodes:         randomCustomNodes(),
   224  			EnableDiscV5:        randomBool(),
   225  			UDPPort:             randomInt(math.MaxInt64),
   226  			AutoUpdate:          randomBool(),
   227  		},
   228  		WakuConfig: params.WakuConfig{
   229  			Enabled:                 randomBool(),
   230  			LightClient:             randomBool(),
   231  			FullNode:                randomBool(),
   232  			EnableMailServer:        randomBool(),
   233  			DataDir:                 randomString(),
   234  			MinimumPoW:              randomFloat(math.MaxInt64),
   235  			MailServerPassword:      randomString(),
   236  			MailServerRateLimit:     randomInt(math.MaxInt64),
   237  			MailServerDataRetention: randomInt(math.MaxInt64),
   238  			TTL:                     randomInt(math.MaxInt64),
   239  			MaxMessageSize:          uint32(randomInt(math.MaxInt64)),
   240  			DatabaseConfig: params.DatabaseConfig{
   241  				PGConfig: params.PGConfig{
   242  					Enabled: randomBool(),
   243  					URI:     randomString(),
   244  				},
   245  			},
   246  			EnableRateLimiter:      randomBool(),
   247  			PacketRateLimitIP:      int64(randomInt(math.MaxInt64)),
   248  			PacketRateLimitPeerID:  int64(randomInt(math.MaxInt64)),
   249  			BytesRateLimitIP:       int64(randomInt(math.MaxInt64)),
   250  			BytesRateLimitPeerID:   int64(randomInt(math.MaxInt64)),
   251  			RateLimitTolerance:     int64(randomInt(math.MaxInt64)),
   252  			BloomFilterMode:        randomBool(),
   253  			SoftBlacklistedPeerIDs: randomStringSlice(),
   254  			EnableConfirmations:    randomBool(),
   255  		},
   256  	}
   257  }
   258  
   259  func TestConfigValidate(t *testing.T) {
   260  	// GIVEN
   261  	db, stop := setupTestDB(t)
   262  	defer stop()
   263  
   264  	tmpdir := t.TempDir()
   265  	nodeConfig, err := params.NewNodeConfig(tmpdir, 1777)
   266  
   267  	require.NoError(t, err)
   268  	require.NoError(t, nodeConfig.Validate())
   269  	require.NoError(t, nodecfg.SaveNodeConfig(db, nodeConfig))
   270  
   271  	// WHEN
   272  	dbNodeConfig, err := nodecfg.GetNodeConfigFromDB(db)
   273  	require.NoError(t, err)
   274  
   275  	// THEN
   276  	require.NoError(t, dbNodeConfig.Validate())
   277  }
   278  
   279  func TestRepairLoadedTorrentConfig(t *testing.T) {
   280  	// GIVEN
   281  	db, stop := setupTestDB(t)
   282  	defer stop()
   283  
   284  	tmpdir := t.TempDir()
   285  	nodeConfig, err := params.NewNodeConfig(tmpdir, 1777)
   286  	require.NoError(t, err)
   287  
   288  	require.NoError(t, nodeConfig.Validate())
   289  
   290  	// Write config to db
   291  	require.NoError(t, nodecfg.SaveNodeConfig(db, nodeConfig))
   292  
   293  	// WHEN: Corrupt the torrent config data as described in the ticket
   294  	// (https://github.com/status-im/status-desktop/issues/14643)
   295  	// Write invalid torrent config to database
   296  	nodeConfig.TorrentConfig.DataDir = ""
   297  	nodeConfig.TorrentConfig.TorrentDir = ""
   298  	nodeConfig.TorrentConfig.Enabled = true
   299  	require.Error(t, nodeConfig.Validate())
   300  
   301  	_, err = db.Exec(`INSERT OR REPLACE INTO torrent_config (
   302      		enabled, port, data_dir, torrent_dir, synthetic_id
   303  		) VALUES (?, ?, ?, ?, 'id')`,
   304  		nodeConfig.TorrentConfig.Enabled,
   305  		nodeConfig.TorrentConfig.Port,
   306  		nodeConfig.TorrentConfig.DataDir,
   307  		nodeConfig.TorrentConfig.TorrentDir,
   308  	)
   309  	require.NoError(t, err)
   310  
   311  	dbNodeConfig, err := nodecfg.GetNodeConfigFromDB(db)
   312  	require.NoError(t, err)
   313  
   314  	// THEN The invalid torrent config should be repaired
   315  	require.Error(t, dbNodeConfig.Validate())
   316  	require.NoError(t, dbNodeConfig.UpdateWithDefaults())
   317  	require.NoError(t, dbNodeConfig.Validate())
   318  }