Replace call to `GenerateConfig` with local JSON. Closes #5739

Signed-off-by: Pedro Pombeiro <pombeirp@users.noreply.github.com>
This commit is contained in:
Pedro Pombeiro 2018-09-07 11:53:43 +02:00
parent e69fb18de9
commit 4ab5e43616
No known key found for this signature in database
GPG Key ID: A65DEB11E4BBC647
10 changed files with 201 additions and 199 deletions

View File

@ -16,7 +16,7 @@ dependencies {
implementation 'com.instabug.library:instabug:3+' implementation 'com.instabug.library:instabug:3+'
implementation 'status-im:function:0.0.1' 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' final String statusGoGroup = 'status-im', statusGoName = 'status-go'
// Check if the local status-go jar exists, and compile against that if it does // Check if the local status-go jar exists, and compile against that if it does

View File

@ -151,66 +151,20 @@ class StatusModule extends ReactContextBaseJavaModule implements LifecycleEventL
return null; 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 // retrieve parameters from app config, that will be applied onto the Go-side config later on
final String dataDir = root + defaultConfig.get("DataDir"); final String absDataDirPath = pathCombine(absRootDirPath, jsonConfig.getString("DataDir"));
final int networkId = defaultConfig.getInt("NetworkId"); final Boolean logEnabled = jsonConfig.getBoolean("LogEnabled");
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 gethLogFilePath = logEnabled ? prepareLogsFile() : null; final String gethLogFilePath = logEnabled ? prepareLogsFile() : null;
jsonConfig.put("LogEnabled", logEnabled);
jsonConfig.put("DataDir", absDataDirPath);
jsonConfig.put("KeyStoreDir", absKeystoreDirPath);
jsonConfig.put("LogFile", gethLogFilePath); 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(); 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) { private static void prettyPrintConfig(final String config) {
Log.d(TAG, "startNode() with config (see below)"); Log.d(TAG, "startNode() with config (see below)");
String configOutput = config; String configOutput = config;
@ -227,16 +181,22 @@ class StatusModule extends ReactContextBaseJavaModule implements LifecycleEventL
Log.d(TAG, "******************* ENDOF NODE CONFIG *************************"); Log.d(TAG, "******************* ENDOF NODE CONFIG *************************");
} }
private String getTestnetDataDir(final String root) { private String getTestnetDataDir(final String absRootDirPath) {
return root + "/ethereum/testnet"; 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(); Activity currentActivity = getCurrentActivity();
final String root = currentActivity.getApplicationInfo().dataDir; final String absRootDirPath = currentActivity.getApplicationInfo().dataDir;
final String dataFolder = this.getTestnetDataDir(root); final String dataFolder = this.getTestnetDataDir(absRootDirPath);
Log.d(TAG, "Starting Geth node in folder: " + dataFolder); Log.d(TAG, "Starting Geth node in folder: " + dataFolder);
try { try {
@ -247,11 +207,11 @@ class StatusModule extends ReactContextBaseJavaModule implements LifecycleEventL
Log.e(TAG, "error making folder: " + dataFolder, e); 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); final File ropstenFlag = new File(ropstenFlagPath);
if (!ropstenFlag.exists()) { if (!ropstenFlag.exists()) {
try { try {
final String chaindDataFolderPath = dataFolder + "/StatusIM/lightchaindata"; final String chaindDataFolderPath = pathCombine(dataFolder, "StatusIM/lightchaindata");
final File lightChainFolder = new File(chaindDataFolderPath); final File lightChainFolder = new File(chaindDataFolderPath);
if (lightChainFolder.isDirectory()) { if (lightChainFolder.isDirectory()) {
String[] children = lightChainFolder.list(); String[] children = lightChainFolder.list();
@ -266,10 +226,9 @@ class StatusModule extends ReactContextBaseJavaModule implements LifecycleEventL
} }
} }
String testnetDataDir = dataFolder; String testnetDataDir = dataFolder;
String oldKeystoreDir = testnetDataDir + "/keystore"; String oldKeystoreDir = pathCombine(testnetDataDir, "keystore");
String newKeystoreDir = root + "/keystore"; String newKeystoreDir = pathCombine(absRootDirPath, "keystore");
final File oldKeystore = new File(oldKeystoreDir); final File oldKeystore = new File(oldKeystoreDir);
if (oldKeystore.exists()) { if (oldKeystore.exists()) {
try { 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); String res = Statusgo.StartNode(updatedJsonConfigString);
if (res.startsWith("{\"error\":\"\"")) { if (res.startsWith("{\"error\":\"\"")) {
Log.d(TAG, "StartNode result: " + res); 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() { private String getOldExternalDir() {
File extStore = Environment.getExternalStorageDirectory(); File extStore = Environment.getExternalStorageDirectory();
return extStore.exists() ? extStore.getAbsolutePath() + "/ethereum/testnet" : getNewInternalDir(); return extStore.exists() ? pathCombine(extStore.getAbsolutePath(), "ethereum/testnet") : getNewInternalDir();
} }
private String getNewInternalDir() { private String getNewInternalDir() {
Activity currentActivity = getCurrentActivity(); Activity currentActivity = getCurrentActivity();
return currentActivity.getApplicationInfo().dataDir + "/ethereum/testnet"; return pathCombine(currentActivity.getApplicationInfo().dataDir, "ethereum/testnet");
} }
private void deleteDirectory(File folder) { private void deleteDirectory(File folder) {
@ -384,7 +348,7 @@ class StatusModule extends ReactContextBaseJavaModule implements LifecycleEventL
} }
@ReactMethod @ReactMethod
public void startNode(final String config, final String fleet) { public void startNode(final String config) {
Log.d(TAG, "startNode"); Log.d(TAG, "startNode");
if (!checkAvailability()) { if (!checkAvailability()) {
return; return;
@ -393,7 +357,7 @@ class StatusModule extends ReactContextBaseJavaModule implements LifecycleEventL
Runnable r = new Runnable() { Runnable r = new Runnable() {
@Override @Override
public void run() { public void run() {
doStartNode(config, fleet); doStartNode(config);
} }
}; };

View File

@ -37,7 +37,7 @@ ExternalProject_Add(StatusGo_ep
PREFIX ${StatusGo_PREFIX} PREFIX ${StatusGo_PREFIX}
SOURCE_DIR ${StatusGo_SOURCE_DIR} SOURCE_DIR ${StatusGo_SOURCE_DIR}
GIT_REPOSITORY https://github.com/status-im/status-go.git 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} BUILD_BYPRODUCTS ${StatusGo_STATIC_LIB}
CONFIGURE_COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/${CONFIGURE_SCRIPT} ${GO_ROOT_PATH} ${StatusGo_ROOT} ${StatusGo_SOURCE_DIR} CONFIGURE_COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/${CONFIGURE_SCRIPT} ${GO_ROOT_PATH} ${StatusGo_ROOT} ${StatusGo_SOURCE_DIR}
BUILD_COMMAND "" BUILD_COMMAND ""

View File

@ -18,6 +18,7 @@
#include <QVariantMap> #include <QVariantMap>
#include <QDir> #include <QDir>
#include <QStandardPaths> #include <QStandardPaths>
#include <QtConcurrent>
#include "libstatus.h" #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); Q_D(RCTStatus);
qDebug() << "call of RCTStatus::startNode with param configString:" << configString; qDebug() << "call of RCTStatus::startNode with param configString:" << configString;
QJsonParseError jsonError; QJsonParseError jsonError;
QJsonDocument jsonDoc = QJsonDocument::fromJson(configString.toUtf8(), &jsonError); const QJsonDocument& jsonDoc = QJsonDocument::fromJson(configString.toUtf8(), &jsonError);
if (jsonError.error != QJsonParseError::NoError){ if (jsonError.error != QJsonParseError::NoError){
qDebug() << jsonError.errorString(); qDebug() << jsonError.errorString();
} }
qDebug() << " RCTStatus::startNode configString: " << jsonDoc.toVariant().toMap();
QVariantMap configJSON = jsonDoc.toVariant().toMap(); QVariantMap configJSON = jsonDoc.toVariant().toMap();
qDebug() << " RCTStatus::startNode configString: " << configJSON;
int networkId = configJSON["NetworkId"].toInt(); 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 rootDirPath = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
QString networkDir = rootDirPath + dataDir; QDir rootDir(rootDirPath);
QString keyStoreDir = rootDirPath + "keystore"; QString absDataDirPath = rootDirPath + relativeDataDirPath;
QDir dir(networkDir); QDir dataDir(absDataDirPath);
if (!dir.exists()) { if (!dataDir.exists()) {
dir.mkpath("."); dataDir.mkpath(".");
}
qDebug()<<"RCTStatus::startNode networkDir: "<<networkDir;
char *configChars = GenerateConfig(networkDir.toUtf8().data(), fleet.toUtf8().data(), networkId);
qDebug() << "RCTStatus::startNode GenerateConfig result: " << statusGoResultError(configChars);
jsonDoc = QJsonDocument::fromJson(QString(configChars).toUtf8(), &jsonError);
if (jsonError.error != QJsonParseError::NoError){
qDebug() << jsonError.errorString();
} }
qDebug() << " RCTStatus::startNode GenerateConfig configString: " << jsonDoc.toVariant().toMap(); configJSON["DataDir"] = absDataDirPath;
QVariantMap generatedConfig = jsonDoc.toVariant().toMap(); configJSON["KeyStoreDir"] = rootDir.absoluteFilePath("keystore");
generatedConfig["KeyStoreDir"] = keyStoreDir; configJSON["LogFile"] = dataDir.absoluteFilePath("geth.log");
generatedConfig["LogFile"] = networkDir + "/geth.log";
generatedConfig["ClusterConfig.Fleet"] = fleet;
const char* result = StartNode(QString(QJsonDocument::fromVariant(generatedConfig).toJson(QJsonDocument::Compact)).toUtf8().data()); const QJsonDocument& updatedJsonDoc = QJsonDocument::fromVariant(configJSON);
qDebug() << " RCTStatus::startNode updated configString: " << updatedJsonDoc.toVariant().toMap();
const char* result = StartNode(QString(updatedJsonDoc.toJson(QJsonDocument::Compact)).toUtf8().data());
qDebug() << "RCTStatus::startNode StartNode result: " << statusGoResultError(result); qDebug() << "RCTStatus::startNode StartNode result: " << statusGoResultError(result);
} }
@ -126,63 +119,77 @@ void RCTStatus::stopNode() {
void RCTStatus::createAccount(QString password, double callbackId) { void RCTStatus::createAccount(QString password, double callbackId) {
Q_D(RCTStatus); Q_D(RCTStatus);
qDebug() << "call of RCTStatus::createAccount with param callbackId: " << callbackId; qDebug() << "call of RCTStatus::createAccount with param callbackId: " << callbackId;
const char* result = CreateAccount(password.toUtf8().data()); QtConcurrent::run([&](QString password, double callbackId) {
qDebug() << "RCTStatus::createAccount CreateAccount result: " << statusGoResultError(result); const char* result = CreateAccount(password.toUtf8().data());
d->bridge->invokePromiseCallback(callbackId, QVariantList{result}); 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) { void RCTStatus::notifyUsers(QString token, QString payloadJSON, QString tokensJSON, double callbackId) {
Q_D(RCTStatus); Q_D(RCTStatus);
qDebug() << "call of RCTStatus::notifyUsers with param callbackId: " << callbackId; qDebug() << "call of RCTStatus::notifyUsers with param callbackId: " << callbackId;
const char* result = NotifyUsers(token.toUtf8().data(), payloadJSON.toUtf8().data(), tokensJSON.toUtf8().data()); QtConcurrent::run([&](QString token, QString payloadJSON, QString tokensJSON, double callbackId) {
qDebug() << "RCTStatus::notifyUsers Notify result: " << statusGoResultError(result); const char* result = NotifyUsers(token.toUtf8().data(), payloadJSON.toUtf8().data(), tokensJSON.toUtf8().data());
d->bridge->invokePromiseCallback(callbackId, QVariantList{result}); qDebug() << "RCTStatus::notifyUsers Notify result: " << statusGoResultError(result);
d->bridge->invokePromiseCallback(callbackId, QVariantList{result});
}, token, payloadJSON, tokensJSON, callbackId);
} }
void RCTStatus::addPeer(QString enode, double callbackId) { void RCTStatus::addPeer(QString enode, double callbackId) {
Q_D(RCTStatus); Q_D(RCTStatus);
qDebug() << "call of RCTStatus::addPeer with param callbackId: " << callbackId; qDebug() << "call of RCTStatus::addPeer with param callbackId: " << callbackId;
const char* result = AddPeer(enode.toUtf8().data()); QtConcurrent::run([&](QString enode, double callbackId) {
qDebug() << "RCTStatus::addPeer AddPeer result: " << statusGoResultError(result); const char* result = AddPeer(enode.toUtf8().data());
d->bridge->invokePromiseCallback(callbackId, QVariantList{result}); qDebug() << "RCTStatus::addPeer AddPeer result: " << statusGoResultError(result);
d->bridge->invokePromiseCallback(callbackId, QVariantList{result});
}, enode, callbackId);
} }
void RCTStatus::recoverAccount(QString passphrase, QString password, double callbackId) { void RCTStatus::recoverAccount(QString passphrase, QString password, double callbackId) {
Q_D(RCTStatus); Q_D(RCTStatus);
qDebug() << "call of RCTStatus::recoverAccount with param callbackId: " << callbackId; qDebug() << "call of RCTStatus::recoverAccount with param callbackId: " << callbackId;
const char* result = RecoverAccount(password.toUtf8().data(), passphrase.toUtf8().data()); QtConcurrent::run([&](QString passphrase, QString password, double callbackId) {
qDebug() << "RCTStatus::recoverAccount RecoverAccount result: " << statusGoResultError(result); const char* result = RecoverAccount(password.toUtf8().data(), passphrase.toUtf8().data());
d->bridge->invokePromiseCallback(callbackId, QVariantList{result}); 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) { void RCTStatus::login(QString address, QString password, double callbackId) {
Q_D(RCTStatus); Q_D(RCTStatus);
qDebug() << "call of RCTStatus::login with param callbackId: " << callbackId; qDebug() << "call of RCTStatus::login with param callbackId: " << callbackId;
const char* result = Login(address.toUtf8().data(), password.toUtf8().data()); QtConcurrent::run([&](QString address, QString password, double callbackId) {
qDebug() << "RCTStatus::login Login result: " << statusGoResultError(result); const char* result = Login(address.toUtf8().data(), password.toUtf8().data());
d->bridge->invokePromiseCallback(callbackId, QVariantList{result}); 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) { void RCTStatus::sendTransaction(QString txArgsJSON, QString password, double callbackId) {
Q_D(RCTStatus); Q_D(RCTStatus);
qDebug() << "call of RCTStatus::sendTransaction with param callbackId: " << callbackId; qDebug() << "call of RCTStatus::sendTransaction with param callbackId: " << callbackId;
const char* result = SendTransaction(txArgsJSON.toUtf8().data(), password.toUtf8().data()); QtConcurrent::run([&](QString txArgsJSON, QString password, double callbackId) {
qDebug() << "RCTStatus::sendTransaction SendTransaction result: " << statusGoResultError(result); const char* result = SendTransaction(txArgsJSON.toUtf8().data(), password.toUtf8().data());
d->bridge->invokePromiseCallback(callbackId, QVariantList{result}); qDebug() << "RCTStatus::sendTransaction SendTransaction result: " << statusGoResultError(result);
d->bridge->invokePromiseCallback(callbackId, QVariantList{result});
}, txArgsJSON, password, callbackId);
} }
void RCTStatus::signMessage(QString rpcParams, double callbackId) { void RCTStatus::signMessage(QString rpcParams, double callbackId) {
Q_D(RCTStatus); Q_D(RCTStatus);
qDebug() << "call of RCTStatus::signMessage with param callbackId: " << callbackId; qDebug() << "call of RCTStatus::signMessage with param callbackId: " << callbackId;
const char* result = SignMessage(rpcParams.toUtf8().data()); QtConcurrent::run([&](QString rpcParams, double callbackId) {
qDebug() << "RCTStatus::signMessage SignMessage result: " << statusGoResultError(result); const char* result = SignMessage(rpcParams.toUtf8().data());
d->bridge->invokePromiseCallback(callbackId, QVariantList{result}); 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) { void RCTStatus::callRPC(QString payload, double callbackId) {
Q_D(RCTStatus); Q_D(RCTStatus);
qDebug() << "call of RCTStatus::callRPC with param callbackId: " << callbackId; qDebug() << "call of RCTStatus::callRPC with param callbackId: " << callbackId;
const char* result = CallRPC(payload.toUtf8().data()); QtConcurrent::run([&](QString payload, double callbackId) {
qDebug() << "RCTStatus::callRPC CallRPC result: " << statusGoResultError(result); const char* result = CallRPC(payload.toUtf8().data());
d->bridge->invokePromiseCallback(callbackId, QVariantList{result}); qDebug() << "RCTStatus::callRPC CallRPC result: " << statusGoResultError(result);
d->bridge->invokePromiseCallback(callbackId, QVariantList{result});
}, payload, callbackId);
} }
void RCTStatus::callPrivateRPC(QString payload, double callbackId) { void RCTStatus::callPrivateRPC(QString payload, double callbackId) {
Q_D(RCTStatus); Q_D(RCTStatus);
qDebug() << "call of RCTStatus::callPrivateRPC with param callbackId: " << callbackId; qDebug() << "call of RCTStatus::callPrivateRPC with param callbackId: " << callbackId;
const char* result = CallPrivateRPC(payload.toUtf8().data()); QtConcurrent::run([&](QString payload, double callbackId) {
qDebug() << "RCTStatus::callPrivateRPC CallPrivateRPC result: " << statusGoResultError(result); const char* result = CallPrivateRPC(payload.toUtf8().data());
d->bridge->invokePromiseCallback(callbackId, QVariantList{result}); qDebug() << "RCTStatus::callPrivateRPC CallPrivateRPC result: " << statusGoResultError(result);
d->bridge->invokePromiseCallback(callbackId, QVariantList{result});
}, payload, callbackId);
} }
void RCTStatus::closeApplication() { void RCTStatus::closeApplication() {

View File

@ -32,7 +32,7 @@ public:
QList<ModuleMethod*> methodsToExport() override; QList<ModuleMethod*> methodsToExport() override;
QVariantMap constantsToExport() 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 stopNode();
Q_INVOKABLE void createAccount(QString password, double callbackId); Q_INVOKABLE void createAccount(QString password, double callbackId);
Q_INVOKABLE void notifyUsers(QString token, QString payloadJSON, QString tokensJSON, double callbackId); Q_INVOKABLE void notifyUsers(QString token, QString payloadJSON, QString tokensJSON, double callbackId);

View File

@ -65,8 +65,7 @@ RCT_EXPORT_MODULE();
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
#pragma mark - startNode #pragma mark - startNode
//////////////////////////////////////////////////////////////////// startNode //////////////////////////////////////////////////////////////////// startNode
RCT_EXPORT_METHOD(startNode:(NSString *)configString RCT_EXPORT_METHOD(startNode:(NSString *)configString) {
fleet:(NSString *)fleet) {
#if DEBUG #if DEBUG
NSLog(@"StartNode() method called"); NSLog(@"StartNode() method called");
#endif #endif
@ -75,18 +74,18 @@ RCT_EXPORT_METHOD(startNode:(NSString *)configString
NSURL *rootUrl =[[fileManager NSURL *rootUrl =[[fileManager
URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask]
lastObject]; lastObject];
NSURL *testnetFolderName = [rootUrl URLByAppendingPathComponent:@"ethereum/testnet"]; NSURL *absTestnetFolderName = [rootUrl URLByAppendingPathComponent:@"ethereum/testnet"];
if (![fileManager fileExistsAtPath:testnetFolderName.path]) if (![fileManager fileExistsAtPath:absTestnetFolderName.path])
[fileManager createDirectoryAtPath:testnetFolderName.path withIntermediateDirectories:YES attributes:nil error:&error]; [fileManager createDirectoryAtPath:absTestnetFolderName.path withIntermediateDirectories:YES attributes:nil error:&error];
NSURL *flagFolderUrl = [rootUrl URLByAppendingPathComponent:@"ropsten_flag"]; NSURL *flagFolderUrl = [rootUrl URLByAppendingPathComponent:@"ropsten_flag"];
if(![fileManager fileExistsAtPath:flagFolderUrl.path]){ if(![fileManager fileExistsAtPath:flagFolderUrl.path]){
NSLog(@"remove lightchaindata"); NSLog(@"remove lightchaindata");
NSURL *lightChainData = [testnetFolderName URLByAppendingPathComponent:@"StatusIM/lightchaindata"]; NSURL *absLightChainDataUrl = [absTestnetFolderName URLByAppendingPathComponent:@"StatusIM/lightchaindata"];
if([fileManager fileExistsAtPath:lightChainData.path]) { if([fileManager fileExistsAtPath:absLightChainDataUrl.path]) {
[fileManager removeItemAtPath:lightChainData.path [fileManager removeItemAtPath:absLightChainDataUrl.path
error:nil]; error:nil];
} }
[fileManager createDirectoryAtPath:flagFolderUrl.path [fileManager createDirectoryAtPath:flagFolderUrl.path
@ -97,12 +96,12 @@ RCT_EXPORT_METHOD(startNode:(NSString *)configString
NSLog(@"after remove lightchaindata"); NSLog(@"after remove lightchaindata");
NSURL *oldKeystoreUrl = [testnetFolderName URLByAppendingPathComponent:@"keystore"]; NSURL *absTestnetKeystoreUrl = [absTestnetFolderName URLByAppendingPathComponent:@"keystore"];
NSURL *newKeystoreUrl = [rootUrl URLByAppendingPathComponent:@"keystore"]; NSURL *absKeystoreUrl = [rootUrl URLByAppendingPathComponent:@"keystore"];
if([fileManager fileExistsAtPath:oldKeystoreUrl.path]){ if([fileManager fileExistsAtPath:absTestnetKeystoreUrl.path]){
NSLog(@"copy keystore"); NSLog(@"copy keystore");
[fileManager copyItemAtPath:oldKeystoreUrl.path toPath:newKeystoreUrl.path error:nil]; [fileManager copyItemAtPath:absTestnetKeystoreUrl.path toPath:absKeystoreUrl.path error:nil];
[fileManager removeItemAtPath:oldKeystoreUrl.path error:nil]; [fileManager removeItemAtPath:absTestnetKeystoreUrl.path error:nil];
} }
NSLog(@"after lightChainData"); NSLog(@"after lightChainData");
@ -110,60 +109,34 @@ RCT_EXPORT_METHOD(startNode:(NSString *)configString
NSLog(@"preconfig: %@", configString); NSLog(@"preconfig: %@", configString);
NSData *configData = [configString dataUsingEncoding:NSUTF8StringEncoding]; NSData *configData = [configString dataUsingEncoding:NSUTF8StringEncoding];
NSDictionary *configJSON = [NSJSONSerialization JSONObjectWithData:configData options:NSJSONReadingMutableContainers error:nil]; NSDictionary *configJSON = [NSJSONSerialization JSONObjectWithData:configData options:NSJSONReadingMutableContainers error:nil];
int networkId = [configJSON[@"NetworkId"] integerValue]; NSString *relativeDataDir = [configJSON objectForKey:@"DataDir"];
NSString *dataDir = [configJSON objectForKey:@"DataDir"]; NSString *absDataDir = [rootUrl.path stringByAppendingString:relativeDataDir];
NSString *upstreamURL = [configJSON valueForKeyPath:@"UpstreamConfig.URL"]; NSURL *absDataDirUrl = [NSURL fileURLWithPath:absDataDir];
NSArray *bootnodes = [configJSON valueForKeyPath:@"ClusterConfig.BootNodes"]; NSURL *absLogUrl = [absDataDirUrl URLByAppendingPathComponent:@"geth.log"];
NSString *networkDir = [rootUrl.path stringByAppendingString:dataDir]; [configJSON setValue:absDataDirUrl.path forKey:@"DataDir"];
NSString *devCluster = [ReactNativeConfig envFor:@"ETHEREUM_DEV_CLUSTER"]; [configJSON setValue:absKeystoreUrl.path forKey:@"KeyStoreDir"];
NSString *logEnabled = [configJSON objectForKey:@"LogEnabled"]; [configJSON setValue:absLogUrl.path forKey:@"LogFile"];
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"];
[resultingConfigJson setValue:[NSNumber numberWithBool:YES] forKeyPath:@"WhisperConfig.LightClient"]; NSString *resultingConfig = [configJSON bv_jsonStringWithPrettyPrint:NO];
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];
NSLog(@"node config %@", resultingConfig); NSLog(@"node config %@", resultingConfig);
if(![fileManager fileExistsAtPath:networkDirUrl.path]) { if(![fileManager fileExistsAtPath:absDataDirUrl.path]) {
[fileManager createDirectoryAtPath:networkDirUrl.path withIntermediateDirectories:YES attributes:nil error:nil]; [fileManager createDirectoryAtPath:absDataDirUrl.path withIntermediateDirectories:YES attributes:nil error:nil];
} }
NSLog(@"logUrlPath %@", logUrl.path); NSLog(@"logUrlPath %@", absLogUrl.path);
if(![fileManager fileExistsAtPath:logUrl.path]) { if(![fileManager fileExistsAtPath:absLogUrl.path]) {
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init]; NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
[dict setObject:[NSNumber numberWithInt:511] forKey:NSFilePosixPermissions]; [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), dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),
^(void) ^(void)
{ {
char *res = StartNode((char *) [resultingConfig UTF8String]); char *res = StartNode((char *) [resultingConfig UTF8String]);
NSLog(@"StartNode result %@", [NSString stringWithUTF8String: res]); }); NSLog(@"StartNode result %@", [NSString stringWithUTF8String: res]);
});
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////

View File

@ -25,7 +25,7 @@
<artifactItem> <artifactItem>
<groupId>status-im</groupId> <groupId>status-im</groupId>
<artifactId>status-go-ios-simulator</artifactId> <artifactId>status-go-ios-simulator</artifactId>
<version>v0.14.1</version> <version>v0.15.0</version>
<type>zip</type> <type>zip</type>
<overWrite>true</overWrite> <overWrite>true</overWrite>
<outputDirectory>./</outputDirectory> <outputDirectory>./</outputDirectory>

View File

@ -3,8 +3,8 @@
(def adjust-resize 16) (def adjust-resize 16)
(defn start-node [config fleet] (defn start-node [config]
(native-module/start-node config fleet)) (native-module/start-node config))
(defn stop-node [] (defn stop-node []
(native-module/stop-node)) (native-module/stop-node))

View File

@ -58,9 +58,9 @@
(when status (when status
(call-module #(.stopNode status)))) (call-module #(.stopNode status))))
(defn start-node [config fleet] (defn start-node [config]
(when status (when status
(call-module #(.startNode status config fleet)))) (call-module #(.startNode status config))))
(defonce account-creation? (atom false)) (defonce account-creation? (atom false))

View File

@ -12,8 +12,7 @@
(vals $) (vals $)
(map :address $))] (map :address $))]
(if (seq bootnodes) (if (seq bootnodes)
(assoc config :ClusterConfig {:Enabled true (assoc-in config [:ClusterConfig :BootNodes] bootnodes)
:BootNodes bootnodes})
config))) config)))
(defn- add-log-level [config log-level] (defn- add-log-level [config log-level]
@ -24,11 +23,47 @@
:LogLevel log-level :LogLevel log-level
:LogEnabled true))) :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] (defn get-account-network [db address]
(get-in db [:accounts/accounts address :network])) (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] (defn- get-account-node-config [db address]
(let [accounts (get db :accounts/accounts) (let [accounts (get db :accounts/accounts)
current-fleet-key (fleet/current-fleet db address)
current-fleet (get fleet/fleets current-fleet-key)
{:keys [network {:keys [network
settings settings
bootnodes bootnodes
@ -37,6 +72,24 @@
log-level (or (:log-level settings) log-level (or (:log-level settings)
config/log-level-status-go)] config/log-level-status-go)]
(cond-> (get-in networks [network :config]) (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 (and
config/bootnodes-settings-enabled? config/bootnodes-settings-enabled?
use-custom-bootnodes) use-custom-bootnodes)
@ -47,6 +100,8 @@
(defn get-node-config [db network] (defn get-node-config [db network]
(-> (get-in (:networks/networks db) [network :config]) (-> (get-in (:networks/networks db) [network :config])
(get-base-node-config)
(assoc :NoDiscovery true)
(add-log-level config/log-level-status-go))) (add-log-level config/log-level-status-go)))
(defn start (defn start
@ -59,11 +114,10 @@
node-config (if address node-config (if address
(get-account-node-config db address) (get-account-node-config db address)
(get-node-config db network)) (get-node-config db network))
node-config-json (types/clj->json node-config) node-config-json (types/clj->json node-config)]
fleet (name (fleet/current-fleet db address))]
(log/info "Node config: " node-config-json) (log/info "Node config: " node-config-json)
{:db (assoc db :network network) {:db (assoc db :network network)
:node/start [node-config-json fleet]}))) :node/start node-config-json})))
(defn restart (defn restart
[] []
@ -77,8 +131,8 @@
(re-frame/reg-fx (re-frame/reg-fx
:node/start :node/start
(fn [[config fleet]] (fn [config]
(status/start-node config fleet))) (status/start-node config)))
(re-frame/reg-fx (re-frame/reg-fx
:node/stop :node/stop