Add custom bootnodes
Signed-off-by: Andrea Maria Piana <andrea.maria.piana@gmail.com>
This commit is contained in:
parent
7711dc51ad
commit
33ad919508
|
@ -19,3 +19,4 @@ INSTABUG_SURVEYS=1
|
|||
GROUP_CHATS_ENABLED=0
|
||||
FORCE_SENT_RECEIVED_TRACKING=1
|
||||
ADD_CUSTOM_MAILSERVERS_ENABLED=0
|
||||
BOOTNODES_SETTINGS_ENABLED=0
|
||||
|
|
|
@ -20,3 +20,4 @@ GROUP_CHATS_ENABLED=0
|
|||
FORCE_SENT_RECEIVED_TRACKING=0
|
||||
USE_SYM_KEY=0
|
||||
ADD_CUSTOM_MAILSERVERS_ENABLED=0
|
||||
BOOTNODES_SETTINGS_ENABLED=0
|
||||
|
|
|
@ -17,7 +17,7 @@ dependencies {
|
|||
implementation 'com.github.ericwlange:AndroidJSCore:3.0.1'
|
||||
implementation 'status-im:function:0.0.1'
|
||||
|
||||
String statusGoVersion = 'develop-g5aae87ab'
|
||||
String statusGoVersion = 'develop-gbc14e6fa'
|
||||
final String statusGoGroup = 'status-im', statusGoName = 'status-go'
|
||||
|
||||
// Check if the local status-go jar exists, and compile against that if it does
|
||||
|
|
|
@ -183,6 +183,8 @@ class StatusModule extends ReactContextBaseJavaModule implements LifecycleEventL
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
int testnetNetworkId = 3;
|
||||
String testnetDataDir = root + "/ethereum/testnet";
|
||||
String oldKeystoreDir = testnetDataDir + "/keystore";
|
||||
String newKeystoreDir = root + "/keystore";
|
||||
|
@ -204,14 +206,19 @@ class StatusModule extends ReactContextBaseJavaModule implements LifecycleEventL
|
|||
}
|
||||
}
|
||||
|
||||
String config = Statusgo.GenerateConfig(testnetDataDir, 3);
|
||||
String config;
|
||||
try {
|
||||
JSONObject customConfig = new JSONObject(defaultConfig);
|
||||
|
||||
String dataDir = root + customConfig.get("DataDir");
|
||||
|
||||
config = Statusgo.GenerateConfig(dataDir, customConfig.getInt("NetworkId"));
|
||||
|
||||
JSONObject jsonConfig = new JSONObject(config);
|
||||
|
||||
String gethLogFilePath = prepareLogsFile();
|
||||
boolean logsEnabled = (gethLogFilePath != null) && !TextUtils.isEmpty(this.logLevel);
|
||||
String dataDir = root + customConfig.get("DataDir");
|
||||
|
||||
jsonConfig.put("LogEnabled", (gethLogFilePath != null && logsEnabled));
|
||||
jsonConfig.put("LogFile", gethLogFilePath);
|
||||
jsonConfig.put("LogLevel", TextUtils.isEmpty(this.logLevel) ? "ERROR" : this.logLevel.toUpperCase());
|
||||
|
@ -236,10 +243,22 @@ class StatusModule extends ReactContextBaseJavaModule implements LifecycleEventL
|
|||
} catch (Exception e) {
|
||||
|
||||
}
|
||||
try {
|
||||
Object clusterConfig = customConfig.get("ClusterConfig");
|
||||
if (clusterConfig != null) {
|
||||
Log.d(TAG, "ClusterConfig is not null");
|
||||
jsonConfig.put("ClusterConfig", clusterConfig);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.w(TAG, "Something went wrong parsing cluster config" + e.getMessage());
|
||||
}
|
||||
|
||||
|
||||
jsonConfig.put("KeyStoreDir", newKeystoreDir);
|
||||
|
||||
config = jsonConfig.toString();
|
||||
} catch (JSONException e) {
|
||||
config = Statusgo.GenerateConfig(testnetDataDir, testnetNetworkId);
|
||||
Log.d(TAG, "Something went wrong " + e.getMessage());
|
||||
Log.d(TAG, "Default configuration will be used");
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:self
|
||||
options:(NSJSONWritingOptions) (prettyPrint ? NSJSONWritingPrettyPrinted : 0)
|
||||
error:&error];
|
||||
|
||||
|
||||
if (! jsonData) {
|
||||
NSLog(@"bv_jsonStringWithPrettyPrint: error: %@", error.localizedDescription);
|
||||
return @"{}";
|
||||
|
@ -35,7 +35,7 @@
|
|||
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:self
|
||||
options:(NSJSONWritingOptions) (prettyPrint ? NSJSONWritingPrettyPrinted : 0)
|
||||
error:&error];
|
||||
|
||||
|
||||
if (! jsonData) {
|
||||
NSLog(@"bv_jsonStringWithPrettyPrint: error: %@", error.localizedDescription);
|
||||
return @"[]";
|
||||
|
@ -90,7 +90,7 @@ RCT_EXPORT_METHOD(parseJail:(NSString *)chatId
|
|||
}
|
||||
NSDictionary *result = [_jail parseJail:chatId withCode:js];
|
||||
stringResult = [result bv_jsonStringWithPrettyPrint:NO];
|
||||
|
||||
|
||||
callback(@[stringResult]);
|
||||
}
|
||||
|
||||
|
@ -103,7 +103,7 @@ RCT_EXPORT_METHOD(callJail:(NSString *)chatId
|
|||
NSLog(@"CallJail() method called");
|
||||
#endif
|
||||
dispatch_async( dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||
|
||||
|
||||
NSString *stringResult;
|
||||
if(_jail == nil) {
|
||||
_jail = [Jail new];
|
||||
|
@ -130,12 +130,12 @@ RCT_EXPORT_METHOD(startNode:(NSString *)configString) {
|
|||
URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask]
|
||||
lastObject];
|
||||
NSURL *testnetFolderName = [rootUrl URLByAppendingPathComponent:@"ethereum/testnet"];
|
||||
|
||||
|
||||
if (![fileManager fileExistsAtPath:testnetFolderName.path])
|
||||
[fileManager createDirectoryAtPath:testnetFolderName.path withIntermediateDirectories:YES attributes:nil error:&error];
|
||||
|
||||
|
||||
NSURL *flagFolderUrl = [rootUrl URLByAppendingPathComponent:@"ropsten_flag"];
|
||||
|
||||
|
||||
if(![fileManager fileExistsAtPath:flagFolderUrl.path]){
|
||||
NSLog(@"remove lightchaindata");
|
||||
NSURL *lightChainData = [testnetFolderName URLByAppendingPathComponent:@"StatusIM/lightchaindata"];
|
||||
|
@ -148,9 +148,9 @@ RCT_EXPORT_METHOD(startNode:(NSString *)configString) {
|
|||
attributes:nil
|
||||
error:&error];
|
||||
}
|
||||
|
||||
|
||||
NSLog(@"after remove lightchaindata");
|
||||
|
||||
|
||||
NSURL *oldKeystoreUrl = [testnetFolderName URLByAppendingPathComponent:@"keystore"];
|
||||
NSURL *newKeystoreUrl = [rootUrl URLByAppendingPathComponent:@"keystore"];
|
||||
if([fileManager fileExistsAtPath:oldKeystoreUrl.path]){
|
||||
|
@ -158,15 +158,16 @@ RCT_EXPORT_METHOD(startNode:(NSString *)configString) {
|
|||
[fileManager copyItemAtPath:oldKeystoreUrl.path toPath:newKeystoreUrl.path error:nil];
|
||||
[fileManager removeItemAtPath:oldKeystoreUrl.path error:nil];
|
||||
}
|
||||
|
||||
|
||||
NSLog(@"after lightChainData");
|
||||
|
||||
|
||||
NSLog(@"preconfig: %@", configString);
|
||||
NSData *configData = [configString dataUsingEncoding:NSUTF8StringEncoding];
|
||||
NSDictionary *configJSON = [NSJSONSerialization JSONObjectWithData:configData options:NSJSONReadingMutableContainers error:nil];
|
||||
int networkId = [configJSON[@"NetworkId"] integerValue];
|
||||
NSString *dataDir = [configJSON objectForKey:@"DataDir"];
|
||||
NSString *upstreamURL = [configJSON valueForKeyPath:@"UpstreamConfig.URL"];
|
||||
NSArray *bootnodes = [configJSON valueForKeyPath:@"ClusterConfig.BootNodes"];
|
||||
NSString *networkDir = [rootUrl.path stringByAppendingString:dataDir];
|
||||
NSString *devCluster = [ReactNativeConfig envFor:@"ETHEREUM_DEV_CLUSTER"];
|
||||
NSString *logLevel = [[ReactNativeConfig envFor:@"LOG_LEVEL_STATUS_GO"] uppercaseString];
|
||||
|
@ -180,19 +181,27 @@ RCT_EXPORT_METHOD(startNode:(NSString *)configString) {
|
|||
[resultingConfigJson setValue:[NSNumber numberWithBool:[logLevel length] != 0] forKey:@"LogEnabled"];
|
||||
[resultingConfigJson setValue:logUrl.path forKey:@"LogFile"];
|
||||
[resultingConfigJson setValue:([logLevel length] == 0 ? [NSString stringWithUTF8String: "ERROR"] : logLevel) forKey:@"LogLevel"];
|
||||
|
||||
|
||||
[resultingConfigJson setValue:[NSNumber numberWithBool:YES] forKeyPath:@"WhisperConfig.LightClient"];
|
||||
|
||||
if(upstreamURL != nil) {
|
||||
[resultingConfigJson setValue:[NSNumber numberWithBool:YES] forKeyPath:@"UpstreamConfig.Enabled"];
|
||||
[resultingConfigJson setValue:upstreamURL forKeyPath:@"UpstreamConfig.URL"];
|
||||
}
|
||||
|
||||
if(bootnodes != nil) {
|
||||
[resultingConfigJson setValue:[NSNumber numberWithBool:YES] forKeyPath:@"ClusterConfig.Enabled"];
|
||||
[resultingConfigJson setValue:bootnodes forKeyPath:@"ClusterConfig.BootNodes"];
|
||||
}
|
||||
|
||||
|
||||
NSString *resultingConfig = [resultingConfigJson bv_jsonStringWithPrettyPrint:NO];
|
||||
NSLog(@"node config %@", resultingConfig);
|
||||
|
||||
|
||||
if(![fileManager fileExistsAtPath:networkDirUrl.path]) {
|
||||
[fileManager createDirectoryAtPath:networkDirUrl.path withIntermediateDirectories:YES attributes:nil error:nil];
|
||||
}
|
||||
|
||||
|
||||
NSLog(@"logUrlPath %@", logUrl.path);
|
||||
if(![fileManager fileExistsAtPath:logUrl.path]) {
|
||||
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
|
||||
|
@ -353,7 +362,7 @@ RCT_EXPORT_METHOD(clearCookies) {
|
|||
|
||||
RCT_EXPORT_METHOD(clearStorageAPIs) {
|
||||
[[NSURLCache sharedURLCache] removeAllCachedResponses];
|
||||
|
||||
|
||||
NSString *path = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
|
||||
NSArray *array = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:path error:nil];
|
||||
for (NSString *string in array) {
|
||||
|
@ -408,7 +417,7 @@ RCT_EXPORT_METHOD(getDeviceUUID:(RCTResponseSenderBlock)callback) {
|
|||
NSLog(@"getDeviceUUID() method called");
|
||||
#endif
|
||||
NSString* Identifier = [[[UIDevice currentDevice] identifierForVendor] UUIDString];
|
||||
|
||||
|
||||
callback(@[Identifier]);
|
||||
}
|
||||
|
||||
|
@ -420,7 +429,7 @@ RCT_EXPORT_METHOD(getDeviceUUID:(RCTResponseSenderBlock)callback) {
|
|||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
NSString *sig = [NSString stringWithUTF8String:signal];
|
||||
#if DEBUG
|
||||
NSLog(@"SignalEvent");
|
||||
|
@ -428,7 +437,7 @@ RCT_EXPORT_METHOD(getDeviceUUID:(RCTResponseSenderBlock)callback) {
|
|||
#endif
|
||||
[bridge.eventDispatcher sendAppEventWithName:@"gethEvent"
|
||||
body:@{@"jsonEvent": sig}];
|
||||
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -447,7 +456,7 @@ RCT_EXPORT_METHOD(getDeviceUUID:(RCTResponseSenderBlock)callback) {
|
|||
#endif
|
||||
[bridge.eventDispatcher sendAppEventWithName:@"gethEvent"
|
||||
body:@{@"jsonEvent": signal}];
|
||||
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
<artifactItem>
|
||||
<groupId>status-im</groupId>
|
||||
<artifactId>status-go-ios-simulator</artifactId>
|
||||
<version>develop-g5aae87ab</version>
|
||||
<version>develop-gbc14e6fa</version>
|
||||
<type>zip</type>
|
||||
<overWrite>true</overWrite>
|
||||
<outputDirectory>./</outputDirectory>
|
||||
|
|
|
@ -10,9 +10,22 @@
|
|||
(core/single-clj :account)
|
||||
(update :settings core/deserialize)))
|
||||
|
||||
(defn- deserialize-bootnodes [bootnodes]
|
||||
(reduce-kv
|
||||
(fn [acc id {:keys [chain] :as bootnode}]
|
||||
(assoc-in acc [chain id] bootnode))
|
||||
{}
|
||||
bootnodes))
|
||||
|
||||
(defn- serialize-bootnodes [bootnodes]
|
||||
(->> bootnodes
|
||||
vals
|
||||
(mapcat vals)))
|
||||
|
||||
(defn- deserialize-account [account]
|
||||
(-> account
|
||||
(update :settings core/deserialize)
|
||||
(update :bootnodes deserialize-bootnodes)
|
||||
(update :networks (partial reduce-kv
|
||||
(fn [acc network-id props]
|
||||
(assoc acc network-id
|
||||
|
@ -31,6 +44,7 @@
|
|||
(defn- serialize-account [account]
|
||||
(-> account
|
||||
(update :settings core/serialize)
|
||||
(update :bootnodes serialize-bootnodes)
|
||||
(update :networks (partial map (fn [[_ props]]
|
||||
(update props :config types/clj->json))))))
|
||||
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
(ns status-im.data-store.realm.schemas.base.core
|
||||
(:require [status-im.data-store.realm.schemas.base.v1.core :as v1]
|
||||
[status-im.data-store.realm.schemas.base.v2.core :as v2]
|
||||
[status-im.data-store.realm.schemas.base.v3.core :as v3]))
|
||||
[status-im.data-store.realm.schemas.base.v3.core :as v3]
|
||||
[status-im.data-store.realm.schemas.base.v4.core :as v4]))
|
||||
|
||||
;; put schemas ordered by version
|
||||
(def schemas [{:schema v1/schema
|
||||
|
@ -12,4 +13,7 @@
|
|||
:migration v2/migration}
|
||||
{:schema v3/schema
|
||||
:schemaVersion 3
|
||||
:migration v3/migration}])
|
||||
:migration v3/migration}
|
||||
{:schema v4/schema
|
||||
:schemaVersion 4
|
||||
:migration v4/migration}])
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
(ns status-im.data-store.realm.schemas.base.v4.account)
|
||||
|
||||
(def schema {:name :account
|
||||
:primaryKey :address
|
||||
:properties {:address :string
|
||||
:public-key :string
|
||||
:name {:type :string :optional true}
|
||||
:email {:type :string :optional true}
|
||||
:status {:type :string :optional true}
|
||||
:debug? {:type :bool :default false}
|
||||
:photo-path :string
|
||||
:signing-phrase {:type :string}
|
||||
:mnemonic {:type :string :optional true}
|
||||
:last-updated {:type :int :default 0}
|
||||
:last-sign-in {:type :int :default 0}
|
||||
:signed-up? {:type :bool
|
||||
:default false}
|
||||
:network :string
|
||||
:networks {:type :list
|
||||
:objectType :network}
|
||||
:bootnodes {:type :list
|
||||
:objectType :bootnode}
|
||||
:last-request {:type :int :optional true}
|
||||
:settings {:type :string}
|
||||
:sharing-usage-data? {:type :bool :default false}
|
||||
:dev-mode? {:type :bool :default false}
|
||||
:seed-backed-up? {:type :bool :default false}
|
||||
:wallet-set-up-passed? {:type :bool
|
||||
:default false}}})
|
|
@ -0,0 +1,8 @@
|
|||
(ns status-im.data-store.realm.schemas.base.v4.bootnode)
|
||||
|
||||
(def schema {:name :bootnode
|
||||
:primaryKey :id
|
||||
:properties {:id :string
|
||||
:name {:type :string}
|
||||
:chain {:type :string}
|
||||
:address {:type :string}}})
|
|
@ -0,0 +1,12 @@
|
|||
(ns status-im.data-store.realm.schemas.base.v4.core
|
||||
(:require [status-im.data-store.realm.schemas.base.v1.network :as network]
|
||||
[status-im.data-store.realm.schemas.base.v4.account :as account]
|
||||
[status-im.data-store.realm.schemas.base.v4.bootnode :as bootnode]
|
||||
[taoensso.timbre :as log]))
|
||||
|
||||
(def schema [network/schema
|
||||
bootnode/schema
|
||||
account/schema])
|
||||
|
||||
(defn migration [old-realm new-realm]
|
||||
(log/debug "migrating base database v4: " old-realm new-realm))
|
|
@ -622,6 +622,14 @@
|
|||
:close-app-button "Confirm"
|
||||
:connect-wnode-content "Connect to {{name}}?"
|
||||
|
||||
;; Bootnodes
|
||||
:bootnodes "Bootnodes"
|
||||
:bootnodes-settings "Bootnodes settings"
|
||||
:bootnodes-enabled "Bootnodes enabled"
|
||||
:bootnode-address "Bootnode address"
|
||||
:add-bootnode "Add bootnode"
|
||||
:specify-bootnode-address "Specify bootnode address"
|
||||
|
||||
:mainnet-warning-title "Warning!"
|
||||
:mainnet-warning-text "While we highly appreciate your contribution as a tester of Status, we’d like to point out the dangers. You’re switching to Mainnet mode which is still in Alpha. This means it is still in development and has not been audited yet. Some of the risks you may be exposed to include:\n\n- Accounts may be unrecoverable due to breaking changes\n- Loss of ETH and tokens\n- Failure to send or receive messages\n\nSwitching to Mainnet should be done for testing purposes only. By tapping \"I understand\", you confirm that you assume the full responsibility for all risks concerning your data and funds. "
|
||||
:mainnet-warning-ok-text "I understand"
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
(:require [cljs.spec.alpha :as spec]
|
||||
status-im.utils.db
|
||||
status-im.ui.screens.network-settings.db
|
||||
status-im.ui.screens.bootnodes-settings.db
|
||||
[status-im.constants :as const]))
|
||||
|
||||
(defn valid-length? [password]
|
||||
|
@ -24,6 +25,7 @@
|
|||
(spec/def :account/status (spec/nilable string?))
|
||||
(spec/def :account/network (spec/nilable string?))
|
||||
(spec/def :account/networks (spec/nilable :networks/networks))
|
||||
(spec/def :account/bootnodes (spec/nilable :bootnodes/bootnodes))
|
||||
(spec/def :account/wnode (spec/nilable string?))
|
||||
(spec/def :account/settings (spec/nilable (spec/map-of keyword? any?)))
|
||||
(spec/def :account/signing-phrase :global/not-empty-string)
|
||||
|
@ -41,7 +43,8 @@
|
|||
:account/networks :account/settings :account/wnode
|
||||
:account/last-sign-in :account/sharing-usage-data? :account/dev-mode?
|
||||
:account/seed-backed-up? :account/mnemonic
|
||||
:account/wallet-set-up-passed? :account/last-request]))
|
||||
:account/wallet-set-up-passed? :account/last-request
|
||||
:account/bootnodes]))
|
||||
|
||||
(spec/def :accounts/accounts (spec/nilable (spec/map-of :account/address :accounts/account)))
|
||||
|
||||
|
|
|
@ -63,12 +63,32 @@
|
|||
(assoc db :node/after-start nil)
|
||||
address password)))
|
||||
|
||||
(defn add-custom-bootnodes [config network all-bootnodes]
|
||||
(let [bootnodes (as-> all-bootnodes $
|
||||
(get $ network)
|
||||
(vals $)
|
||||
(map :address $))]
|
||||
(if (seq bootnodes)
|
||||
(assoc config :ClusterConfig {:Enabled true
|
||||
:BootNodes bootnodes})
|
||||
config)))
|
||||
|
||||
(defn get-network-by-address [db address]
|
||||
(let [accounts (get db :accounts/accounts)
|
||||
{:keys [network networks]} (get accounts address)
|
||||
config (get-in networks [network :config])]
|
||||
{:network network
|
||||
:config config}))
|
||||
{:keys [network
|
||||
settings
|
||||
bootnodes
|
||||
networks]} (get accounts address)
|
||||
use-custom-bootnodes (get-in settings [:bootnodes network])
|
||||
config (cond-> (get-in networks [network :config])
|
||||
|
||||
(and
|
||||
config/bootnodes-settings-enabled?
|
||||
use-custom-bootnodes)
|
||||
(add-custom-bootnodes network bootnodes))]
|
||||
{:use-custom-bootnodes use-custom-bootnodes
|
||||
:network network
|
||||
:config config}))
|
||||
|
||||
(defn wrap-with-initialize-geth-fx [db address password]
|
||||
(let [{:keys [network config]} (get-network-by-address db address)]
|
||||
|
@ -87,21 +107,31 @@
|
|||
{:db (assoc db :node/after-stop [::start-node address password])
|
||||
::stop-node nil})
|
||||
|
||||
(defn- restart-node? [account-network network use-custom-bootnodes]
|
||||
(or (not= account-network network)
|
||||
(and config/bootnodes-settings-enabled?
|
||||
use-custom-bootnodes)))
|
||||
|
||||
(defn login-account [{{:keys [network status-node-started?] :as db} :db} [_ address password]]
|
||||
(let [{use-custom-bootnodes :use-custom-bootnodes
|
||||
account-network :network} (get-network-by-address db address)
|
||||
db' (-> db
|
||||
(assoc-in [:accounts/login :processing] true))
|
||||
wrap-fn (cond (not status-node-started?)
|
||||
wrap-with-initialize-geth-fx
|
||||
|
||||
(not (restart-node? account-network
|
||||
network
|
||||
use-custom-bootnodes))
|
||||
wrap-with-login-account-fx
|
||||
|
||||
:else
|
||||
wrap-with-stop-node-fx)]
|
||||
(wrap-fn db' address password)))
|
||||
|
||||
(register-handler-fx
|
||||
:login-account
|
||||
(fn [{{:keys [network status-node-started?] :as db} :db} [_ address password]]
|
||||
(let [{account-network :network} (get-network-by-address db address)
|
||||
db' (-> db
|
||||
(assoc-in [:accounts/login :processing] true))
|
||||
wrap-fn (cond (not status-node-started?)
|
||||
wrap-with-initialize-geth-fx
|
||||
|
||||
(= account-network network)
|
||||
wrap-with-login-account-fx
|
||||
|
||||
:else
|
||||
wrap-with-stop-node-fx)]
|
||||
(wrap-fn db' address password))))
|
||||
login-account)
|
||||
|
||||
(register-handler-fx
|
||||
:login-handler
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
(ns status-im.ui.screens.bootnodes-settings.db
|
||||
(:require-macros [status-im.utils.db :refer [allowed-keys]])
|
||||
(:require
|
||||
[clojure.string :as string]
|
||||
[cljs.spec.alpha :as spec]))
|
||||
|
||||
(spec/def ::not-blank-string (complement string/blank?))
|
||||
|
||||
(spec/def :bootnode/address ::not-blank-string)
|
||||
(spec/def :bootnode/name ::not-blank-string)
|
||||
(spec/def :bootnode/id ::not-blank-string)
|
||||
(spec/def :bootnode/chain ::not-blank-string)
|
||||
(spec/def :bootnode/bootnode (allowed-keys :req-un [:bootnode/chain
|
||||
:bootnode/address
|
||||
:bootnode/name
|
||||
:bootnode/id]))
|
||||
|
||||
(spec/def :bootnodes/bootnodes (spec/nilable (spec/map-of :bootnode/id (spec/map-of :bootnode/id :bootnode/bootnode))))
|
|
@ -0,0 +1,51 @@
|
|||
(ns status-im.ui.screens.bootnodes-settings.edit-bootnode.events
|
||||
(:require [clojure.string :as string]
|
||||
[re-frame.core :as re-frame]
|
||||
[status-im.utils.handlers :refer [register-handler] :as handlers]
|
||||
[status-im.utils.handlers-macro :as handlers-macro]
|
||||
[status-im.ui.screens.accounts.utils :as accounts.utils]
|
||||
[status-im.utils.ethereum.core :as ethereum]
|
||||
[status-im.utils.types :as types]
|
||||
[status-im.utils.inbox :as utils.inbox]))
|
||||
|
||||
(defn- new-bootnode [id bootnode-name address chain]
|
||||
{:address address
|
||||
:chain chain
|
||||
:id (string/replace id "-" "")
|
||||
:name bootnode-name})
|
||||
|
||||
(defn save-new-bootnode [{{:bootnodes/keys [manage] :account/keys [account] :as db} :db :as cofx} _]
|
||||
(let [{:keys [name url]} manage
|
||||
network (:network db)
|
||||
bootnode (new-bootnode
|
||||
(:random-id cofx)
|
||||
(:value name)
|
||||
(:value url)
|
||||
network)
|
||||
new-bootnodes (assoc-in (:bootnodes account) [network (:id bootnode)] bootnode)]
|
||||
|
||||
(handlers-macro/merge-fx cofx
|
||||
{:db (dissoc db :bootnodes/manage)
|
||||
:dispatch [:navigate-back]}
|
||||
(accounts.utils/account-update {:bootnodes new-bootnodes}))))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:save-new-bootnode
|
||||
[(re-frame/inject-cofx :random-id)]
|
||||
save-new-bootnode)
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:bootnode-set-input
|
||||
(fn [{db :db} [_ input-key value]]
|
||||
{:db (update db :bootnodes/manage assoc input-key {:value value
|
||||
:error (if (= input-key :name)
|
||||
(string/blank? value)
|
||||
(not (utils.inbox/valid-enode-address? value)))})}))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:edit-bootnode
|
||||
(fn [{db :db} _]
|
||||
{:db (update-in db [:bootnodes/manage] assoc
|
||||
:name {:error true}
|
||||
:url {:error true})
|
||||
:dispatch [:navigate-to :edit-bootnode]}))
|
|
@ -0,0 +1,15 @@
|
|||
(ns status-im.ui.screens.bootnodes-settings.edit-bootnode.styles
|
||||
(:require-macros [status-im.utils.styles :refer [defstyle]]))
|
||||
|
||||
(def edit-bootnode-view
|
||||
{:flex 1
|
||||
:margin-horizontal 16
|
||||
:margin-vertical 15})
|
||||
|
||||
(def input-container
|
||||
{:margin-bottom 15})
|
||||
|
||||
(def bottom-container
|
||||
{:flex-direction :row
|
||||
:margin-horizontal 12
|
||||
:margin-vertical 15})
|
|
@ -0,0 +1,14 @@
|
|||
(ns status-im.ui.screens.bootnodes-settings.edit-bootnode.subs
|
||||
(:require [re-frame.core :refer [reg-sub]]))
|
||||
|
||||
(reg-sub
|
||||
:get-manage-bootnode
|
||||
:<- [:get :bootnodes/manage]
|
||||
(fn [manage]
|
||||
manage))
|
||||
|
||||
(reg-sub
|
||||
:manage-bootnode-valid?
|
||||
:<- [:get-manage-bootnode]
|
||||
(fn [manage]
|
||||
(not-any? :error (vals manage))))
|
|
@ -0,0 +1,42 @@
|
|||
(ns status-im.ui.screens.bootnodes-settings.edit-bootnode.views
|
||||
(:require-macros [status-im.utils.views :as views])
|
||||
(:require
|
||||
[re-frame.core :as re-frame]
|
||||
[status-im.ui.components.react :as react]
|
||||
[status-im.i18n :as i18n]
|
||||
[status-im.ui.components.styles :as components.styles]
|
||||
[status-im.ui.components.common.common :as components.common]
|
||||
[status-im.ui.components.status-bar.view :as status-bar]
|
||||
[status-im.ui.components.toolbar.view :as toolbar]
|
||||
[status-im.ui.components.text-input.view :as text-input]
|
||||
[status-im.ui.screens.bootnodes-settings.edit-bootnode.styles :as styles]))
|
||||
|
||||
(views/defview edit-bootnode []
|
||||
(views/letsubs [manage-bootnode [:get-manage-bootnode]
|
||||
is-valid? [:manage-bootnode-valid?]]
|
||||
[react/view components.styles/flex
|
||||
[status-bar/status-bar]
|
||||
[react/keyboard-avoiding-view components.styles/flex
|
||||
[toolbar/simple-toolbar (i18n/label :t/add-bootnode)]
|
||||
[react/scroll-view
|
||||
[react/view styles/edit-bootnode-view
|
||||
[text-input/text-input-with-label
|
||||
{:label (i18n/label :t/name)
|
||||
:placeholder (i18n/label :t/specify-name)
|
||||
:container styles/input-container
|
||||
:default-value (get-in manage-bootnode [:name :value])
|
||||
:on-change-text #(re-frame/dispatch [:bootnode-set-input :name %])
|
||||
:auto-focus true}]
|
||||
[text-input/text-input-with-label
|
||||
{:label (i18n/label :t/bootnode-address)
|
||||
:placeholder (i18n/label :t/specify-bootnode-address)
|
||||
:container styles/input-container
|
||||
:default-value (get-in manage-bootnode [:url :value])
|
||||
:on-change-text #(re-frame/dispatch [:bootnode-set-input :url %])}]]]
|
||||
[react/view styles/bottom-container
|
||||
[react/view components.styles/flex]
|
||||
[components.common/bottom-button
|
||||
{:forward? true
|
||||
:label (i18n/label :t/save)
|
||||
:disabled? (not is-valid?)
|
||||
:on-press #(re-frame/dispatch [:save-new-bootnode])}]]]]))
|
|
@ -0,0 +1,22 @@
|
|||
(ns status-im.ui.screens.bootnodes-settings.events
|
||||
(:require [re-frame.core :as re-frame]
|
||||
[status-im.utils.handlers :as handlers]
|
||||
[status-im.utils.handlers-macro :as handlers-macro]
|
||||
[status-im.ui.screens.accounts.events :as accounts-events]
|
||||
[status-im.i18n :as i18n]
|
||||
[status-im.transport.core :as transport]
|
||||
status-im.ui.screens.bootnodes-settings.edit-bootnode.events
|
||||
[status-im.utils.ethereum.core :as ethereum]))
|
||||
|
||||
(defn toggle-custom-bootnodes [value {:keys [db] :as cofx}]
|
||||
(let [network (get-in db [:account/account :network])
|
||||
settings (get-in db [:account/account :settings])]
|
||||
(handlers-macro/merge-fx cofx
|
||||
(accounts-events/update-settings
|
||||
(assoc-in settings [:bootnodes network] value)
|
||||
[:logout]))))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:toggle-custom-bootnodes
|
||||
(fn [cofx [_ value]]
|
||||
(toggle-custom-bootnodes value cofx)))
|
|
@ -0,0 +1,30 @@
|
|||
(ns status-im.ui.screens.bootnodes-settings.styles
|
||||
(:require [status-im.ui.components.colors :as colors])
|
||||
(:require-macros [status-im.utils.styles :refer [defstyle]]))
|
||||
|
||||
(def wrapper
|
||||
{:flex 1
|
||||
:background-color :white})
|
||||
|
||||
(def bootnode-item-inner
|
||||
{:padding-horizontal 16})
|
||||
|
||||
(defstyle bootnode-item
|
||||
{:flex-direction :row
|
||||
:background-color :white
|
||||
:align-items :center
|
||||
:padding-horizontal 16
|
||||
:ios {:height 64}
|
||||
:android {:height 56}})
|
||||
|
||||
(defstyle bootnode-item-name-text
|
||||
{:color colors/black
|
||||
:ios {:font-size 17
|
||||
:letter-spacing -0.2
|
||||
:line-height 20}
|
||||
:android {:font-size 16}})
|
||||
|
||||
(defstyle switch-container
|
||||
{:height 50
|
||||
:background-color colors/white
|
||||
:padding-left 15})
|
|
@ -0,0 +1,15 @@
|
|||
(ns status-im.ui.screens.bootnodes-settings.subs
|
||||
(:require [re-frame.core :as re-frame]
|
||||
status-im.ui.screens.bootnodes-settings.edit-bootnode.subs
|
||||
[status-im.utils.ethereum.core :as ethereum]))
|
||||
|
||||
(re-frame/reg-sub :settings/bootnodes-enabled
|
||||
:<- [:get :account/account]
|
||||
(fn [account]
|
||||
(let [{:keys [network settings]} account]
|
||||
(get-in settings [:bootnodes network]))))
|
||||
|
||||
(re-frame/reg-sub :settings/network-bootnodes
|
||||
:<- [:get :account/account]
|
||||
(fn [account]
|
||||
(get-in account [:bootnodes (:network account)])))
|
|
@ -0,0 +1,46 @@
|
|||
(ns status-im.ui.screens.bootnodes-settings.views
|
||||
(:require-macros [status-im.utils.views :as views])
|
||||
(:require [re-frame.core :as re-frame]
|
||||
[status-im.i18n :as i18n]
|
||||
[status-im.utils.config :as config]
|
||||
[status-im.ui.components.colors :as colors]
|
||||
[status-im.ui.components.icons.vector-icons :as vector-icons]
|
||||
[status-im.ui.components.list.views :as list]
|
||||
[status-im.ui.components.react :as react]
|
||||
[status-im.ui.components.status-bar.view :as status-bar]
|
||||
[status-im.ui.components.toolbar.view :as toolbar]
|
||||
[status-im.ui.components.toolbar.actions :as toolbar.actions]
|
||||
[status-im.ui.screens.profile.components.views :as profile.components]
|
||||
[status-im.ui.screens.bootnodes-settings.styles :as styles]))
|
||||
|
||||
(defn navigate-to-add-bootnode []
|
||||
(re-frame/dispatch [:edit-bootnode]))
|
||||
|
||||
(defn render-row [{:keys [name id]}]
|
||||
[react/view
|
||||
{:accessibility-label :bootnode-item}
|
||||
[react/view styles/bootnode-item
|
||||
[react/view styles/bootnode-item-inner
|
||||
[react/text {:style styles/bootnode-item-name-text}
|
||||
name]]]])
|
||||
|
||||
(views/defview bootnodes-settings []
|
||||
(views/letsubs [bootnodes-enabled [:settings/bootnodes-enabled]
|
||||
bootnodes [:settings/network-bootnodes]]
|
||||
[react/view {:flex 1}
|
||||
[status-bar/status-bar]
|
||||
[toolbar/toolbar {}
|
||||
toolbar/default-nav-back
|
||||
[toolbar/content-title (i18n/label :t/bootnodes-settings)]
|
||||
[toolbar/actions
|
||||
[(toolbar.actions/add false navigate-to-add-bootnode)]]]
|
||||
[react/view styles/switch-container
|
||||
[profile.components/settings-switch-item
|
||||
{:label-kw :t/bootnodes-enabled
|
||||
:value bootnodes-enabled
|
||||
:action-fn #(re-frame/dispatch [:toggle-custom-bootnodes %])}]]
|
||||
[react/view styles/wrapper
|
||||
[list/flat-list {:data (vals bootnodes)
|
||||
:default-separator? false
|
||||
:key-fn :id
|
||||
:render-fn render-row}]]]))
|
|
@ -170,6 +170,7 @@
|
|||
:networks/networks
|
||||
:networks/manage
|
||||
:mailservers/manage
|
||||
:bootnodes/manage
|
||||
:node/after-start
|
||||
:node/after-stop
|
||||
:inbox/wnodes
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
status-im.ui.screens.wallet.choose-recipient.events
|
||||
status-im.ui.screens.browser.events
|
||||
status-im.ui.screens.offline-messaging-settings.events
|
||||
status-im.ui.screens.bootnodes-settings.events
|
||||
status-im.ui.screens.currency-settings.events
|
||||
status-im.ui.screens.usage-data.events
|
||||
[re-frame.core :as re-frame]
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
(:require [re-frame.core :refer [dispatch dispatch-sync after] :as re-frame]
|
||||
[status-im.utils.handlers :refer [register-handler] :as handlers]
|
||||
status-im.ui.screens.network-settings.edit-network.events
|
||||
status-im.ui.screens.offline-messaging-settings.edit-mailserver.events
|
||||
[status-im.utils.handlers-macro :as handlers-macro]
|
||||
[status-im.ui.screens.accounts.utils :as accounts.utils]
|
||||
[status-im.i18n :as i18n]
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
[status-im.ui.screens.accounts.events :as accounts-events]
|
||||
[status-im.i18n :as i18n]
|
||||
[status-im.transport.core :as transport]
|
||||
status-im.ui.screens.offline-messaging-settings.edit-mailserver.events
|
||||
[status-im.utils.ethereum.core :as ethereum]))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
|
|
|
@ -152,6 +152,11 @@
|
|||
{:label-kw :t/offline-messaging
|
||||
:action-fn #(re-frame/dispatch [:navigate-to :offline-messaging-settings])
|
||||
:accessibility-label :offline-messages-settings-button}])
|
||||
(when config/bootnodes-settings-enabled?
|
||||
[profile.components/settings-item
|
||||
{:label-kw :t/bootnodes
|
||||
:action-fn #(re-frame/dispatch [:navigate-to :bootnodes-settings])
|
||||
:accessibility-label :bootnodes-settings-button}])
|
||||
[profile.components/settings-item-separator]
|
||||
[profile.components/settings-item
|
||||
{:label-kw :t/help-improve?
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
status-im.ui.screens.wallet.transactions.subs
|
||||
status-im.ui.screens.network-settings.subs
|
||||
status-im.ui.screens.offline-messaging-settings.subs
|
||||
status-im.ui.screens.bootnodes-settings.subs
|
||||
status-im.ui.screens.currency-settings.subs
|
||||
status-im.ui.screens.browser.subs
|
||||
status-im.bots.subs
|
||||
|
|
|
@ -39,6 +39,8 @@
|
|||
[status-im.ui.screens.network-settings.edit-network.views :refer [edit-network]]
|
||||
[status-im.ui.screens.offline-messaging-settings.views :refer [offline-messaging-settings]]
|
||||
[status-im.ui.screens.offline-messaging-settings.edit-mailserver.views :refer [edit-mailserver]]
|
||||
[status-im.ui.screens.bootnodes-settings.views :refer [bootnodes-settings]]
|
||||
[status-im.ui.screens.bootnodes-settings.edit-bootnode.views :refer [edit-bootnode]]
|
||||
[status-im.ui.screens.currency-settings.views :refer [currency-settings]]
|
||||
[status-im.ui.screens.browser.views :refer [browser]]
|
||||
[status-im.ui.screens.add-new.open-dapp.views :refer [open-dapp dapp-description]]
|
||||
|
@ -85,6 +87,8 @@
|
|||
:edit-network edit-network
|
||||
:offline-messaging-settings offline-messaging-settings
|
||||
:edit-mailserver edit-mailserver
|
||||
:bootnodes-settings bootnodes-settings
|
||||
:edit-bootnode edit-bootnode
|
||||
:currency-settings currency-settings
|
||||
:recent-recipients recent-recipients
|
||||
:recipient-qr-code recipient-qr-code
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
(def stub-status-go? (enabled? (get-config :STUB_STATUS_GO 0)))
|
||||
(def mainnet-warning-enabled? (enabled? (get-config :MAINNET_WARNING_ENABLED 0)))
|
||||
(def offline-inbox-enabled? (enabled? (get-config :OFFLINE_INBOX_ENABLED "1")))
|
||||
(def bootnodes-settings-enabled? (enabled? (get-config :BOOTNODES_SETTINGS_ENABLED "1")))
|
||||
(def log-level
|
||||
(-> (get-config :LOG_LEVEL "error")
|
||||
string/lower-case
|
||||
|
|
|
@ -35,7 +35,9 @@
|
|||
[status-im.test.utils.datetime]
|
||||
[status-im.test.utils.mixpanel]
|
||||
[status-im.test.utils.prices]
|
||||
[status-im.test.ui.screens.network-settings.edit-network.events]))
|
||||
[status-im.test.ui.screens.network-settings.edit-network.events]
|
||||
[status-im.test.ui.screens.bootnodes-settings.edit-bootnode.events]
|
||||
[status-im.test.ui.screens.accounts.login.events]))
|
||||
|
||||
(enable-console-print!)
|
||||
|
||||
|
@ -81,4 +83,6 @@
|
|||
'status-im.test.utils.datetime
|
||||
'status-im.test.utils.mixpanel
|
||||
'status-im.test.utils.prices
|
||||
'status-im.test.ui.screens.network-settings.edit-network.events)
|
||||
'status-im.test.ui.screens.network-settings.edit-network.events
|
||||
'status-im.test.ui.screens.bootnodes-settings.edit-bootnode.events
|
||||
'status-im.test.ui.screens.accounts.login.events)
|
||||
|
|
|
@ -0,0 +1,132 @@
|
|||
(ns status-im.test.ui.screens.accounts.login.events
|
||||
(:require [cljs.test :refer-macros [deftest is testing]]
|
||||
[status-im.utils.config :as config]
|
||||
[status-im.ui.screens.accounts.login.events :as events]))
|
||||
|
||||
(deftest login-account
|
||||
(let [mainnet-account {:network "mainnet_rpc"
|
||||
:networks {"mainnet_rpc" {:config {:NetworkId 1}}}}
|
||||
testnet-account {:network "testnet_rpc"
|
||||
:networks {"testnet_rpc" {:config {:NetworkId 3}}}}
|
||||
accounts {"mainnet" mainnet-account
|
||||
"testnet" testnet-account}
|
||||
initial-db {:db {:network "mainnet_rpc"
|
||||
:accounts/accounts accounts}}]
|
||||
|
||||
(testing "status-go has not started"
|
||||
(let [actual (events/login-account initial-db [nil "testnet" "password"])]
|
||||
(testing "it starts status-node if it has not started"
|
||||
(is (= {:NetworkId 3}
|
||||
(:initialize-geth-fx
|
||||
actual))))
|
||||
(testing "it logins the user after the node started"
|
||||
(is (= [::events/login-account "testnet" "password"] (get-in actual [:db :node/after-start]))))))
|
||||
|
||||
(testing "status-go has started & the user is on mainnet"
|
||||
(let [db (assoc-in initial-db [:db :status-node-started?] true)
|
||||
actual (events/login-account
|
||||
db
|
||||
[nil "mainnet" "password"])]
|
||||
(testing "it does not start status-node if it has already started"
|
||||
(is (not (:initialize-geth-fx actual))))
|
||||
(testing "it logs in the user"
|
||||
(is (= ["mainnet" "password"] (::events/login actual))))))
|
||||
|
||||
(testing "the user has selected a different network"
|
||||
(testing "status-go has started"
|
||||
(let [db (assoc-in initial-db [:db :status-node-started?] true)
|
||||
actual (events/login-account
|
||||
db
|
||||
[nil "testnet" "password"])]
|
||||
(testing "it dispatches start-node"
|
||||
(is (get-in actual [:db :node/after-stop] [::events/start-node "testnet" "password"])))
|
||||
(testing "it stops status-node"
|
||||
(is (contains? actual ::events/stop-node)))))
|
||||
|
||||
(testing "status-go has not started"
|
||||
(let [actual (events/login-account
|
||||
initial-db
|
||||
[nil "testnet" "password"])]
|
||||
(testing "it starts status-node"
|
||||
(is (= {:NetworkId 3} (:initialize-geth-fx actual))))
|
||||
(testing "it logins the user after the node started"
|
||||
(is (= [::events/login-account "testnet" "password"] (get-in actual [:db :node/after-start])))))))
|
||||
|
||||
(testing "custom bootnodes"
|
||||
(let [custom-bootnodes {"a" {:id "a"
|
||||
:name "name-a"
|
||||
:address "address-a"}
|
||||
"b" {:id "b"
|
||||
:name "name-b"
|
||||
:address "address-b"}}
|
||||
bootnodes-db (assoc-in
|
||||
initial-db
|
||||
[:db :accounts/accounts "mainnet" :bootnodes]
|
||||
{"mainnet_rpc" custom-bootnodes})]
|
||||
|
||||
(testing "custom bootnodes enabled"
|
||||
(let [bootnodes-enabled-db (assoc-in
|
||||
bootnodes-db
|
||||
[:db :accounts/accounts "mainnet" :settings]
|
||||
{:bootnodes {"mainnet_rpc" true}})
|
||||
actual (events/login-account
|
||||
bootnodes-enabled-db
|
||||
[nil "mainnet" "password"])]
|
||||
(testing "status-node has started"
|
||||
(let [db (assoc-in bootnodes-enabled-db [:db :status-node-started?] true)
|
||||
actual (events/login-account
|
||||
db
|
||||
[nil "mainnet" "password"])]
|
||||
(testing "it dispatches start-node"
|
||||
(is (get-in actual [:db :node/after-stop] [::events/start-node "testnet" "password"])))
|
||||
(testing "it stops status-node"
|
||||
(is (contains? actual ::events/stop-node)))))
|
||||
(testing "status-node has not started"
|
||||
(let [actual (events/login-account
|
||||
bootnodes-enabled-db
|
||||
[nil "mainnet" "password"])]
|
||||
(testing "it adds bootnodes to the config"
|
||||
(is (= {:ClusterConfig {:Enabled true
|
||||
:BootNodes ["address-a" "address-b"]}
|
||||
:NetworkId 1} (:initialize-geth-fx actual))))
|
||||
(testing "it logins the user after the node started"
|
||||
(is (= [::events/login-account "mainnet" "password"] (get-in actual [:db :node/after-start]))))))))
|
||||
|
||||
(testing "custom bootnodes not enabled"
|
||||
(testing "status-node has started"
|
||||
(let [db (assoc-in bootnodes-db [:db :status-node-started?] true)
|
||||
actual (events/login-account
|
||||
db
|
||||
[nil "mainnet" "password"])]
|
||||
(testing "it does not start status-node if it has already started"
|
||||
(is (not (:initialize-geth-fx actual))))
|
||||
(testing "it logs in the user"
|
||||
(is (= ["mainnet" "password"] (::events/login actual))))))
|
||||
(testing "status-node has not started"
|
||||
(let [actual (events/login-account
|
||||
bootnodes-db
|
||||
[nil "mainnet" "password"])]
|
||||
(testing "it starts status-node without custom bootnodes"
|
||||
(is (= {:NetworkId 1} (:initialize-geth-fx actual))))
|
||||
(testing "it logins the user after the node started"
|
||||
(is (= [::events/login-account "mainnet" "password"] (get-in actual [:db :node/after-start])))))))))))
|
||||
|
||||
(deftest restart-node?
|
||||
(testing "custom bootnodes is toggled off"
|
||||
(with-redefs [config/bootnodes-settings-enabled? false]
|
||||
(testing "it returns true when the network is different"
|
||||
(is (events/restart-node? "mainnet_rpc" "mainnet" true)))
|
||||
(testing "it returns false when the network is the same"
|
||||
(is (not (events/restart-node? "mainnet" "mainnet" true))))))
|
||||
(testing "custom bootnodes is toggled on"
|
||||
(with-redefs [config/bootnodes-settings-enabled? true]
|
||||
(testing "the user is not using custom bootnodes"
|
||||
(testing "it returns true when the network is different"
|
||||
(is (events/restart-node? "mainnet_rpc" "mainnet" false)))
|
||||
(testing "it returns false when the network is the same"
|
||||
(is (not (events/restart-node? "mainnet" "mainnet" false)))))
|
||||
(testing "the user is using custom bootnodes"
|
||||
(testing "it returns true when the network is different"
|
||||
(is (events/restart-node? "mainnet" "mainnet" true)))
|
||||
(testing "it returns true when the network is the same"
|
||||
(is (events/restart-node? "mainnet_rpc" "mainnet" true)))))))
|
|
@ -0,0 +1,19 @@
|
|||
(ns status-im.test.ui.screens.bootnodes-settings.edit-bootnode.events
|
||||
(:require [cljs.test :refer-macros [deftest is testing]]
|
||||
[status-im.ui.screens.bootnodes-settings.edit-bootnode.events :as events]))
|
||||
|
||||
(deftest add-new-bootnode
|
||||
(testing "adding a bootnode"
|
||||
(let [new-bootnode {:name {:value "name"}
|
||||
:url {:value "url"}}
|
||||
expected {"mainnet_rpc" {"someid" {:name "name"
|
||||
:address "url"
|
||||
:chain "mainnet_rpc"
|
||||
:id "someid"}}}
|
||||
actual (events/save-new-bootnode
|
||||
{:random-id "some-id"
|
||||
:db {:bootnodes/manage new-bootnode
|
||||
:network "mainnet_rpc"
|
||||
:account/account {}}}
|
||||
nil)]
|
||||
(is (= expected (get-in actual [:db :account/account :bootnodes]))))))
|
Loading…
Reference in New Issue