From 4ab5e43616f347e22187799e40f3361fa9f72bce Mon Sep 17 00:00:00 2001 From: Pedro Pombeiro Date: Fri, 7 Sep 2018 11:53:43 +0200 Subject: [PATCH] Replace call to `GenerateConfig` with local JSON. Closes #5739 Signed-off-by: Pedro Pombeiro --- .../react-native-status/android/build.gradle | 2 +- .../status/ethereum/module/StatusModule.java | 118 ++++++------------ .../desktop/CMakeLists.txt | 2 +- .../react-native-status/desktop/rctstatus.cpp | 117 +++++++++-------- .../react-native-status/desktop/rctstatus.h | 2 +- .../ios/RCTStatus/RCTStatus.m | 81 ++++-------- .../react-native-status/ios/RCTStatus/pom.xml | 2 +- src/status_im/native_module/core.cljs | 4 +- src/status_im/native_module/impl/module.cljs | 4 +- src/status_im/node/core.cljs | 68 ++++++++-- 10 files changed, 201 insertions(+), 199 deletions(-) diff --git a/modules/react-native-status/android/build.gradle b/modules/react-native-status/android/build.gradle index 26cfd36106..9dd3da1ccf 100644 --- a/modules/react-native-status/android/build.gradle +++ b/modules/react-native-status/android/build.gradle @@ -16,7 +16,7 @@ dependencies { implementation 'com.instabug.library:instabug:3+' implementation 'status-im:function:0.0.1' - String statusGoVersion = 'v0.14.1' + String statusGoVersion = 'v0.15.0' final String statusGoGroup = 'status-im', statusGoName = 'status-go' // Check if the local status-go jar exists, and compile against that if it does diff --git a/modules/react-native-status/android/src/main/java/im/status/ethereum/module/StatusModule.java b/modules/react-native-status/android/src/main/java/im/status/ethereum/module/StatusModule.java index 86728ff3c4..b792df2b00 100644 --- a/modules/react-native-status/android/src/main/java/im/status/ethereum/module/StatusModule.java +++ b/modules/react-native-status/android/src/main/java/im/status/ethereum/module/StatusModule.java @@ -151,66 +151,20 @@ class StatusModule extends ReactContextBaseJavaModule implements LifecycleEventL return null; } - private String generateConfig(final JSONObject defaultConfig, final String root, final String keystoreDir, final String fleet) throws JSONException { + private String updateConfig(final String jsonConfigString, final String absRootDirPath, final String absKeystoreDirPath) throws JSONException { + final JSONObject jsonConfig = new JSONObject(jsonConfigString); // retrieve parameters from app config, that will be applied onto the Go-side config later on - final String dataDir = root + defaultConfig.get("DataDir"); - final int networkId = defaultConfig.getInt("NetworkId"); - final Object upstreamConfig = defaultConfig.opt("UpstreamConfig"); - final Boolean logEnabled = defaultConfig.getBoolean("LogEnabled"); - final String logLevel = defaultConfig.optString("LogLevel", "ERROR"); - - // retrieve config from Go side, in order to use as the basis of the config - JSONObject jsonConfig = new JSONObject( - Statusgo.GenerateConfig(dataDir, fleet, networkId)); - - jsonConfig.put("NetworkId", networkId); - jsonConfig.put("DataDir", dataDir); - jsonConfig.put("KeyStoreDir", keystoreDir); - - if (upstreamConfig != null) { - Log.d(TAG, "UpstreamConfig is not null"); - jsonConfig.put("UpstreamConfig", upstreamConfig); - } - + final String absDataDirPath = pathCombine(absRootDirPath, jsonConfig.getString("DataDir")); + final Boolean logEnabled = jsonConfig.getBoolean("LogEnabled"); final String gethLogFilePath = logEnabled ? prepareLogsFile() : null; - jsonConfig.put("LogEnabled", logEnabled); + + jsonConfig.put("DataDir", absDataDirPath); + jsonConfig.put("KeyStoreDir", absKeystoreDirPath); jsonConfig.put("LogFile", gethLogFilePath); - jsonConfig.put("LogLevel", TextUtils.isEmpty(logLevel) ? "ERROR" : logLevel); - - // Setting up whisper config - JSONObject whisperConfig = jsonConfig.optJSONObject("WhisperConfig"); - if (whisperConfig == null) { - whisperConfig = new JSONObject(); - } - whisperConfig.put("LightClient", true); - jsonConfig.put("WhisperConfig", whisperConfig); - - // Setting up cluster config - JSONObject clusterConfig = jsonConfig.optJSONObject("ClusterConfig"); - if (clusterConfig != null) { - Log.d(TAG, "ClusterConfig is not null"); - clusterConfig.put("Fleet", fleet); - jsonConfig.put("ClusterConfig", clusterConfig); - } else { - Log.w(TAG, "ClusterConfig: Cannot find ClusterConfig: doesn't exist or not a JSON object"); - Log.w(TAG, "ClusterConfig: Fleet will be set to defaults"); - } return jsonConfig.toString(); } - private String generateConfigFromDefaultConfig(final String root, final String keystoreDir, final String fleet, final String defaultConfig) { - try { - JSONObject customConfig = new JSONObject(defaultConfig); - - return generateConfig(customConfig, root, keystoreDir, fleet); - } catch (JSONException e) { - Log.d(TAG, "Something went wrong " + e.getMessage()); - Log.d(TAG, "Default configuration will be used: ropsten, beta fleet"); - return Statusgo.GenerateConfig(this.getTestnetDataDir(root), "eth.beta", TESTNET_NETWORK_ID); - } - } - private static void prettyPrintConfig(final String config) { Log.d(TAG, "startNode() with config (see below)"); String configOutput = config; @@ -227,16 +181,22 @@ class StatusModule extends ReactContextBaseJavaModule implements LifecycleEventL Log.d(TAG, "******************* ENDOF NODE CONFIG *************************"); } - private String getTestnetDataDir(final String root) { - return root + "/ethereum/testnet"; + private String getTestnetDataDir(final String absRootDirPath) { + return pathCombine(absRootDirPath, "ethereum/testnet"); } - private void doStartNode(final String defaultConfig, final String fleet) { + private String pathCombine(final String path1, final String path2) { + // Replace this logic with Paths.get(path1, path2) once API level 26+ becomes the minimum supported API level + final File file = new File(path1, path2); + return file.getAbsolutePath(); + } + + private void doStartNode(final String jsonConfigString) { Activity currentActivity = getCurrentActivity(); - final String root = currentActivity.getApplicationInfo().dataDir; - final String dataFolder = this.getTestnetDataDir(root); + final String absRootDirPath = currentActivity.getApplicationInfo().dataDir; + final String dataFolder = this.getTestnetDataDir(absRootDirPath); Log.d(TAG, "Starting Geth node in folder: " + dataFolder); try { @@ -247,11 +207,11 @@ class StatusModule extends ReactContextBaseJavaModule implements LifecycleEventL Log.e(TAG, "error making folder: " + dataFolder, e); } - final String ropstenFlagPath = root + "/ropsten_flag"; + final String ropstenFlagPath = pathCombine(absRootDirPath, "ropsten_flag"); final File ropstenFlag = new File(ropstenFlagPath); if (!ropstenFlag.exists()) { try { - final String chaindDataFolderPath = dataFolder + "/StatusIM/lightchaindata"; + final String chaindDataFolderPath = pathCombine(dataFolder, "StatusIM/lightchaindata"); final File lightChainFolder = new File(chaindDataFolderPath); if (lightChainFolder.isDirectory()) { String[] children = lightChainFolder.list(); @@ -266,10 +226,9 @@ class StatusModule extends ReactContextBaseJavaModule implements LifecycleEventL } } - String testnetDataDir = dataFolder; - String oldKeystoreDir = testnetDataDir + "/keystore"; - String newKeystoreDir = root + "/keystore"; + String oldKeystoreDir = pathCombine(testnetDataDir, "keystore"); + String newKeystoreDir = pathCombine(absRootDirPath, "keystore"); final File oldKeystore = new File(oldKeystoreDir); if (oldKeystore.exists()) { try { @@ -288,29 +247,34 @@ class StatusModule extends ReactContextBaseJavaModule implements LifecycleEventL } } - final String config = this.generateConfigFromDefaultConfig(root, newKeystoreDir, fleet, defaultConfig); + try { + final String updatedJsonConfigString = this.updateConfig(jsonConfigString, absRootDirPath, newKeystoreDir); - prettyPrintConfig(config); + prettyPrintConfig(updatedJsonConfigString); - String res = Statusgo.StartNode(config); - if (res.startsWith("{\"error\":\"\"")) { - Log.d(TAG, "StartNode result: " + res); + String res = Statusgo.StartNode(updatedJsonConfigString); + if (res.startsWith("{\"error\":\"\"")) { + Log.d(TAG, "StartNode result: " + res); + Log.d(TAG, "Geth node started"); + } + else { + Log.e(TAG, "StartNode failed: " + res); + } + status.sendMessage(); + } catch (JSONException e) { + Log.e(TAG, "updateConfig failed: " + e.getMessage()); + System.exit(1); } - else { - Log.e(TAG, "StartNode failed: " + res); - } - Log.d(TAG, "Geth node started"); - status.sendMessage(); } private String getOldExternalDir() { File extStore = Environment.getExternalStorageDirectory(); - return extStore.exists() ? extStore.getAbsolutePath() + "/ethereum/testnet" : getNewInternalDir(); + return extStore.exists() ? pathCombine(extStore.getAbsolutePath(), "ethereum/testnet") : getNewInternalDir(); } private String getNewInternalDir() { Activity currentActivity = getCurrentActivity(); - return currentActivity.getApplicationInfo().dataDir + "/ethereum/testnet"; + return pathCombine(currentActivity.getApplicationInfo().dataDir, "ethereum/testnet"); } private void deleteDirectory(File folder) { @@ -384,7 +348,7 @@ class StatusModule extends ReactContextBaseJavaModule implements LifecycleEventL } @ReactMethod - public void startNode(final String config, final String fleet) { + public void startNode(final String config) { Log.d(TAG, "startNode"); if (!checkAvailability()) { return; @@ -393,7 +357,7 @@ class StatusModule extends ReactContextBaseJavaModule implements LifecycleEventL Runnable r = new Runnable() { @Override public void run() { - doStartNode(config, fleet); + doStartNode(config); } }; diff --git a/modules/react-native-status/desktop/CMakeLists.txt b/modules/react-native-status/desktop/CMakeLists.txt index 75f86c1a61..0ad9b786a0 100755 --- a/modules/react-native-status/desktop/CMakeLists.txt +++ b/modules/react-native-status/desktop/CMakeLists.txt @@ -37,7 +37,7 @@ ExternalProject_Add(StatusGo_ep PREFIX ${StatusGo_PREFIX} SOURCE_DIR ${StatusGo_SOURCE_DIR} GIT_REPOSITORY https://github.com/status-im/status-go.git - GIT_TAG v0.14.1 + GIT_TAG v0.15.0 BUILD_BYPRODUCTS ${StatusGo_STATIC_LIB} CONFIGURE_COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/${CONFIGURE_SCRIPT} ${GO_ROOT_PATH} ${StatusGo_ROOT} ${StatusGo_SOURCE_DIR} BUILD_COMMAND "" diff --git a/modules/react-native-status/desktop/rctstatus.cpp b/modules/react-native-status/desktop/rctstatus.cpp index eda8d6a275..8b500763ca 100644 --- a/modules/react-native-status/desktop/rctstatus.cpp +++ b/modules/react-native-status/desktop/rctstatus.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include "libstatus.h" @@ -71,47 +72,39 @@ void RCTStatus::getDeviceUUID(double callbackId) { } -void RCTStatus::startNode(QString configString, QString fleet) { +void RCTStatus::startNode(QString configString) { Q_D(RCTStatus); qDebug() << "call of RCTStatus::startNode with param configString:" << configString; QJsonParseError jsonError; - QJsonDocument jsonDoc = QJsonDocument::fromJson(configString.toUtf8(), &jsonError); + const QJsonDocument& jsonDoc = QJsonDocument::fromJson(configString.toUtf8(), &jsonError); if (jsonError.error != QJsonParseError::NoError){ qDebug() << jsonError.errorString(); } - qDebug() << " RCTStatus::startNode configString: " << jsonDoc.toVariant().toMap(); QVariantMap configJSON = jsonDoc.toVariant().toMap(); + qDebug() << " RCTStatus::startNode configString: " << configJSON; int networkId = configJSON["NetworkId"].toInt(); - QString dataDir = configJSON["DataDir"].toString(); + QString relativeDataDirPath = configJSON["DataDir"].toString(); + if (!relativeDataDirPath.startsWith("/")) + relativeDataDirPath.prepend("/"); - QString rootDirPath = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/"; - QString networkDir = rootDirPath + dataDir; - QString keyStoreDir = rootDirPath + "keystore"; - QDir dir(networkDir); - if (!dir.exists()) { - dir.mkpath("."); - } - qDebug()<<"RCTStatus::startNode networkDir: "<bridge->invokePromiseCallback(callbackId, QVariantList{result}); + QtConcurrent::run([&](QString password, double callbackId) { + const char* result = CreateAccount(password.toUtf8().data()); + qDebug() << "RCTStatus::createAccount CreateAccount result: " << statusGoResultError(result); + d->bridge->invokePromiseCallback(callbackId, QVariantList{result}); + }, password, callbackId); } void RCTStatus::notifyUsers(QString token, QString payloadJSON, QString tokensJSON, double callbackId) { Q_D(RCTStatus); qDebug() << "call of RCTStatus::notifyUsers with param callbackId: " << callbackId; - const char* result = NotifyUsers(token.toUtf8().data(), payloadJSON.toUtf8().data(), tokensJSON.toUtf8().data()); - qDebug() << "RCTStatus::notifyUsers Notify result: " << statusGoResultError(result); - d->bridge->invokePromiseCallback(callbackId, QVariantList{result}); + QtConcurrent::run([&](QString token, QString payloadJSON, QString tokensJSON, double callbackId) { + const char* result = NotifyUsers(token.toUtf8().data(), payloadJSON.toUtf8().data(), tokensJSON.toUtf8().data()); + qDebug() << "RCTStatus::notifyUsers Notify result: " << statusGoResultError(result); + d->bridge->invokePromiseCallback(callbackId, QVariantList{result}); + }, token, payloadJSON, tokensJSON, callbackId); } void RCTStatus::addPeer(QString enode, double callbackId) { Q_D(RCTStatus); qDebug() << "call of RCTStatus::addPeer with param callbackId: " << callbackId; - const char* result = AddPeer(enode.toUtf8().data()); - qDebug() << "RCTStatus::addPeer AddPeer result: " << statusGoResultError(result); - d->bridge->invokePromiseCallback(callbackId, QVariantList{result}); + QtConcurrent::run([&](QString enode, double callbackId) { + const char* result = AddPeer(enode.toUtf8().data()); + qDebug() << "RCTStatus::addPeer AddPeer result: " << statusGoResultError(result); + d->bridge->invokePromiseCallback(callbackId, QVariantList{result}); + }, enode, callbackId); } void RCTStatus::recoverAccount(QString passphrase, QString password, double callbackId) { Q_D(RCTStatus); qDebug() << "call of RCTStatus::recoverAccount with param callbackId: " << callbackId; - const char* result = RecoverAccount(password.toUtf8().data(), passphrase.toUtf8().data()); - qDebug() << "RCTStatus::recoverAccount RecoverAccount result: " << statusGoResultError(result); - d->bridge->invokePromiseCallback(callbackId, QVariantList{result}); + QtConcurrent::run([&](QString passphrase, QString password, double callbackId) { + const char* result = RecoverAccount(password.toUtf8().data(), passphrase.toUtf8().data()); + qDebug() << "RCTStatus::recoverAccount RecoverAccount result: " << statusGoResultError(result); + d->bridge->invokePromiseCallback(callbackId, QVariantList{result}); + }, passphrase, password, callbackId); } void RCTStatus::login(QString address, QString password, double callbackId) { Q_D(RCTStatus); qDebug() << "call of RCTStatus::login with param callbackId: " << callbackId; - const char* result = Login(address.toUtf8().data(), password.toUtf8().data()); - qDebug() << "RCTStatus::login Login result: " << statusGoResultError(result); - d->bridge->invokePromiseCallback(callbackId, QVariantList{result}); + QtConcurrent::run([&](QString address, QString password, double callbackId) { + const char* result = Login(address.toUtf8().data(), password.toUtf8().data()); + qDebug() << "RCTStatus::login Login result: " << statusGoResultError(result); + d->bridge->invokePromiseCallback(callbackId, QVariantList{result}); + }, address, password, callbackId); } void RCTStatus::sendTransaction(QString txArgsJSON, QString password, double callbackId) { Q_D(RCTStatus); qDebug() << "call of RCTStatus::sendTransaction with param callbackId: " << callbackId; - const char* result = SendTransaction(txArgsJSON.toUtf8().data(), password.toUtf8().data()); - qDebug() << "RCTStatus::sendTransaction SendTransaction result: " << statusGoResultError(result); - d->bridge->invokePromiseCallback(callbackId, QVariantList{result}); + QtConcurrent::run([&](QString txArgsJSON, QString password, double callbackId) { + const char* result = SendTransaction(txArgsJSON.toUtf8().data(), password.toUtf8().data()); + qDebug() << "RCTStatus::sendTransaction SendTransaction result: " << statusGoResultError(result); + d->bridge->invokePromiseCallback(callbackId, QVariantList{result}); + }, txArgsJSON, password, callbackId); } void RCTStatus::signMessage(QString rpcParams, double callbackId) { Q_D(RCTStatus); qDebug() << "call of RCTStatus::signMessage with param callbackId: " << callbackId; - const char* result = SignMessage(rpcParams.toUtf8().data()); - qDebug() << "RCTStatus::signMessage SignMessage result: " << statusGoResultError(result); - d->bridge->invokePromiseCallback(callbackId, QVariantList{result}); + QtConcurrent::run([&](QString rpcParams, double callbackId) { + const char* result = SignMessage(rpcParams.toUtf8().data()); + qDebug() << "RCTStatus::signMessage SignMessage result: " << statusGoResultError(result); + d->bridge->invokePromiseCallback(callbackId, QVariantList{result}); + }, rpcParams, callbackId); } @@ -210,17 +217,21 @@ void RCTStatus::clearStorageAPIs() { void RCTStatus::callRPC(QString payload, double callbackId) { Q_D(RCTStatus); qDebug() << "call of RCTStatus::callRPC with param callbackId: " << callbackId; - const char* result = CallRPC(payload.toUtf8().data()); - qDebug() << "RCTStatus::callRPC CallRPC result: " << statusGoResultError(result); - d->bridge->invokePromiseCallback(callbackId, QVariantList{result}); + QtConcurrent::run([&](QString payload, double callbackId) { + const char* result = CallRPC(payload.toUtf8().data()); + qDebug() << "RCTStatus::callRPC CallRPC result: " << statusGoResultError(result); + d->bridge->invokePromiseCallback(callbackId, QVariantList{result}); + }, payload, callbackId); } void RCTStatus::callPrivateRPC(QString payload, double callbackId) { Q_D(RCTStatus); qDebug() << "call of RCTStatus::callPrivateRPC with param callbackId: " << callbackId; - const char* result = CallPrivateRPC(payload.toUtf8().data()); - qDebug() << "RCTStatus::callPrivateRPC CallPrivateRPC result: " << statusGoResultError(result); - d->bridge->invokePromiseCallback(callbackId, QVariantList{result}); + QtConcurrent::run([&](QString payload, double callbackId) { + const char* result = CallPrivateRPC(payload.toUtf8().data()); + qDebug() << "RCTStatus::callPrivateRPC CallPrivateRPC result: " << statusGoResultError(result); + d->bridge->invokePromiseCallback(callbackId, QVariantList{result}); + }, payload, callbackId); } void RCTStatus::closeApplication() { diff --git a/modules/react-native-status/desktop/rctstatus.h b/modules/react-native-status/desktop/rctstatus.h index 0f8e599d31..55db5e7d8f 100644 --- a/modules/react-native-status/desktop/rctstatus.h +++ b/modules/react-native-status/desktop/rctstatus.h @@ -32,7 +32,7 @@ public: QList methodsToExport() override; QVariantMap constantsToExport() override; - Q_INVOKABLE void startNode(QString configString, QString fleet); + Q_INVOKABLE void startNode(QString configString); Q_INVOKABLE void stopNode(); Q_INVOKABLE void createAccount(QString password, double callbackId); Q_INVOKABLE void notifyUsers(QString token, QString payloadJSON, QString tokensJSON, double callbackId); diff --git a/modules/react-native-status/ios/RCTStatus/RCTStatus.m b/modules/react-native-status/ios/RCTStatus/RCTStatus.m index a39bbbb735..dab425d488 100644 --- a/modules/react-native-status/ios/RCTStatus/RCTStatus.m +++ b/modules/react-native-status/ios/RCTStatus/RCTStatus.m @@ -65,8 +65,7 @@ RCT_EXPORT_MODULE(); //////////////////////////////////////////////////////////////////// #pragma mark - startNode //////////////////////////////////////////////////////////////////// startNode -RCT_EXPORT_METHOD(startNode:(NSString *)configString - fleet:(NSString *)fleet) { +RCT_EXPORT_METHOD(startNode:(NSString *)configString) { #if DEBUG NSLog(@"StartNode() method called"); #endif @@ -75,18 +74,18 @@ RCT_EXPORT_METHOD(startNode:(NSString *)configString NSURL *rootUrl =[[fileManager URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject]; - NSURL *testnetFolderName = [rootUrl URLByAppendingPathComponent:@"ethereum/testnet"]; + NSURL *absTestnetFolderName = [rootUrl URLByAppendingPathComponent:@"ethereum/testnet"]; - if (![fileManager fileExistsAtPath:testnetFolderName.path]) - [fileManager createDirectoryAtPath:testnetFolderName.path withIntermediateDirectories:YES attributes:nil error:&error]; + if (![fileManager fileExistsAtPath:absTestnetFolderName.path]) + [fileManager createDirectoryAtPath:absTestnetFolderName.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"]; - if([fileManager fileExistsAtPath:lightChainData.path]) { - [fileManager removeItemAtPath:lightChainData.path + NSURL *absLightChainDataUrl = [absTestnetFolderName URLByAppendingPathComponent:@"StatusIM/lightchaindata"]; + if([fileManager fileExistsAtPath:absLightChainDataUrl.path]) { + [fileManager removeItemAtPath:absLightChainDataUrl.path error:nil]; } [fileManager createDirectoryAtPath:flagFolderUrl.path @@ -97,12 +96,12 @@ RCT_EXPORT_METHOD(startNode:(NSString *)configString NSLog(@"after remove lightchaindata"); - NSURL *oldKeystoreUrl = [testnetFolderName URLByAppendingPathComponent:@"keystore"]; - NSURL *newKeystoreUrl = [rootUrl URLByAppendingPathComponent:@"keystore"]; - if([fileManager fileExistsAtPath:oldKeystoreUrl.path]){ + NSURL *absTestnetKeystoreUrl = [absTestnetFolderName URLByAppendingPathComponent:@"keystore"]; + NSURL *absKeystoreUrl = [rootUrl URLByAppendingPathComponent:@"keystore"]; + if([fileManager fileExistsAtPath:absTestnetKeystoreUrl.path]){ NSLog(@"copy keystore"); - [fileManager copyItemAtPath:oldKeystoreUrl.path toPath:newKeystoreUrl.path error:nil]; - [fileManager removeItemAtPath:oldKeystoreUrl.path error:nil]; + [fileManager copyItemAtPath:absTestnetKeystoreUrl.path toPath:absKeystoreUrl.path error:nil]; + [fileManager removeItemAtPath:absTestnetKeystoreUrl.path error:nil]; } NSLog(@"after lightChainData"); @@ -110,60 +109,34 @@ RCT_EXPORT_METHOD(startNode:(NSString *)configString 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 *logEnabled = [configJSON objectForKey:@"LogEnabled"]; - NSString *logLevel = [configJSON objectForKey:@"LogLevel"]; - char *configChars = GenerateConfig((char *)[networkDir UTF8String], (char *)[fleet UTF8String], networkId); - NSString *config = [NSString stringWithUTF8String: configChars]; - configData = [config dataUsingEncoding:NSUTF8StringEncoding]; - NSDictionary *resultingConfigJson = [NSJSONSerialization JSONObjectWithData:configData options:NSJSONReadingMutableContainers error:nil]; - NSURL *networkDirUrl = [NSURL fileURLWithPath:networkDir]; - NSURL *logUrl = [networkDirUrl URLByAppendingPathComponent:@"geth.log"]; - [resultingConfigJson setValue:newKeystoreUrl.path forKey:@"KeyStoreDir"]; - [resultingConfigJson setValue:logEnabled forKey:@"LogEnabled"]; - [resultingConfigJson setValue:logUrl.path forKey:@"LogFile"]; - [resultingConfigJson setValue:([logLevel length] == 0 ? [NSString stringWithUTF8String: "ERROR"] : logLevel) forKey:@"LogLevel"]; + NSString *relativeDataDir = [configJSON objectForKey:@"DataDir"]; + NSString *absDataDir = [rootUrl.path stringByAppendingString:relativeDataDir]; + NSURL *absDataDirUrl = [NSURL fileURLWithPath:absDataDir]; + NSURL *absLogUrl = [absDataDirUrl URLByAppendingPathComponent:@"geth.log"]; + [configJSON setValue:absDataDirUrl.path forKey:@"DataDir"]; + [configJSON setValue:absKeystoreUrl.path forKey:@"KeyStoreDir"]; + [configJSON setValue:absLogUrl.path forKey:@"LogFile"]; - [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"]; - } - - if([fleet length] > 0) { - [resultingConfigJson setValue:fleet forKeyPath:@"ClusterConfig.Fleet"]; - } - - NSString *resultingConfig = [resultingConfigJson bv_jsonStringWithPrettyPrint:NO]; + NSString *resultingConfig = [configJSON bv_jsonStringWithPrettyPrint:NO]; NSLog(@"node config %@", resultingConfig); - if(![fileManager fileExistsAtPath:networkDirUrl.path]) { - [fileManager createDirectoryAtPath:networkDirUrl.path withIntermediateDirectories:YES attributes:nil error:nil]; + if(![fileManager fileExistsAtPath:absDataDirUrl.path]) { + [fileManager createDirectoryAtPath:absDataDirUrl.path withIntermediateDirectories:YES attributes:nil error:nil]; } - NSLog(@"logUrlPath %@", logUrl.path); - if(![fileManager fileExistsAtPath:logUrl.path]) { + NSLog(@"logUrlPath %@", absLogUrl.path); + if(![fileManager fileExistsAtPath:absLogUrl.path]) { NSMutableDictionary *dict = [[NSMutableDictionary alloc] init]; [dict setObject:[NSNumber numberWithInt:511] forKey:NSFilePosixPermissions]; - [fileManager createFileAtPath:logUrl.path contents:nil attributes:dict]; + [fileManager createFileAtPath:absLogUrl.path contents:nil attributes:dict]; } dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void) { char *res = StartNode((char *) [resultingConfig UTF8String]); - NSLog(@"StartNode result %@", [NSString stringWithUTF8String: res]); }); + NSLog(@"StartNode result %@", [NSString stringWithUTF8String: res]); + }); } //////////////////////////////////////////////////////////////////// diff --git a/modules/react-native-status/ios/RCTStatus/pom.xml b/modules/react-native-status/ios/RCTStatus/pom.xml index c56bbc641e..30a69a69b2 100644 --- a/modules/react-native-status/ios/RCTStatus/pom.xml +++ b/modules/react-native-status/ios/RCTStatus/pom.xml @@ -25,7 +25,7 @@ status-im status-go-ios-simulator - v0.14.1 + v0.15.0 zip true ./ diff --git a/src/status_im/native_module/core.cljs b/src/status_im/native_module/core.cljs index 43885f1cab..3bd69cffdd 100644 --- a/src/status_im/native_module/core.cljs +++ b/src/status_im/native_module/core.cljs @@ -3,8 +3,8 @@ (def adjust-resize 16) -(defn start-node [config fleet] - (native-module/start-node config fleet)) +(defn start-node [config] + (native-module/start-node config)) (defn stop-node [] (native-module/stop-node)) diff --git a/src/status_im/native_module/impl/module.cljs b/src/status_im/native_module/impl/module.cljs index f9d009cce3..6cec2c6201 100644 --- a/src/status_im/native_module/impl/module.cljs +++ b/src/status_im/native_module/impl/module.cljs @@ -58,9 +58,9 @@ (when status (call-module #(.stopNode status)))) -(defn start-node [config fleet] +(defn start-node [config] (when status - (call-module #(.startNode status config fleet)))) + (call-module #(.startNode status config)))) (defonce account-creation? (atom false)) diff --git a/src/status_im/node/core.cljs b/src/status_im/node/core.cljs index a2dbbded24..71ee0f1353 100644 --- a/src/status_im/node/core.cljs +++ b/src/status_im/node/core.cljs @@ -12,8 +12,7 @@ (vals $) (map :address $))] (if (seq bootnodes) - (assoc config :ClusterConfig {:Enabled true - :BootNodes bootnodes}) + (assoc-in config [:ClusterConfig :BootNodes] bootnodes) config))) (defn- add-log-level [config log-level] @@ -24,11 +23,47 @@ :LogLevel log-level :LogEnabled true))) +(defn get-network-genesis-hash-prefix + "returns the hex representation of the first 8 bytes of a network's genesis hash" + [network] + (case network + 1 "d4e56740f876aef8" + 3 "41941023680923e0" + 4 "6341fd3daf94b748" + nil)) + +(defn get-les-topic + "returns discovery v5 topic derived from genesis of the provided network" + [network] + (let [les-discovery-identifier "LES2@" + hash-prefix (get-network-genesis-hash-prefix network)] + (when hash-prefix + (str les-discovery-identifier hash-prefix)))) + +(defn get-topics + [network] + (let [les-topic (get-les-topic network)] + (cond-> {"whisper" {:Min 2, :Max 2}} + les-topic (assoc les-topic {:Min 2, :Max 2})))) + (defn get-account-network [db address] (get-in db [:accounts/accounts address :network])) +(defn- get-base-node-config [config] + (assoc config + :Name "StatusIM")) + +(defn- pick-nodes + "Picks `limit` different nodes randomly from the list of nodes + if there is more than `limit` nodes in the list, otherwise return the list + of nodes" + [limit nodes] + (take limit (shuffle nodes))) + (defn- get-account-node-config [db address] (let [accounts (get db :accounts/accounts) + current-fleet-key (fleet/current-fleet db address) + current-fleet (get fleet/fleets current-fleet-key) {:keys [network settings bootnodes @@ -37,6 +72,24 @@ log-level (or (:log-level settings) config/log-level-status-go)] (cond-> (get-in networks [network :config]) + :always + (get-base-node-config) + + current-fleet + (assoc :NoDiscovery false + :ClusterConfig {:Enabled true + :Fleet (name current-fleet-key) + :BootNodes (pick-nodes 4 (vals (:boot current-fleet))) + :TrustedMailServers (pick-nodes 6 (vals (:mail current-fleet))) + :StaticNodes (pick-nodes 2 (vals (:whisper current-fleet)))}) + + :always + (assoc :WhisperConfig {:Enabled true + :LightClient true + :MinimumPoW 0.001 + :EnableNTPSync true} + :RequireTopics (get-topics network)) + (and config/bootnodes-settings-enabled? use-custom-bootnodes) @@ -47,6 +100,8 @@ (defn get-node-config [db network] (-> (get-in (:networks/networks db) [network :config]) + (get-base-node-config) + (assoc :NoDiscovery true) (add-log-level config/log-level-status-go))) (defn start @@ -59,11 +114,10 @@ node-config (if address (get-account-node-config db address) (get-node-config db network)) - node-config-json (types/clj->json node-config) - fleet (name (fleet/current-fleet db address))] + node-config-json (types/clj->json node-config)] (log/info "Node config: " node-config-json) {:db (assoc db :network network) - :node/start [node-config-json fleet]}))) + :node/start node-config-json}))) (defn restart [] @@ -77,8 +131,8 @@ (re-frame/reg-fx :node/start - (fn [[config fleet]] - (status/start-node config fleet))) + (fn [config] + (status/start-node config))) (re-frame/reg-fx :node/stop