Skip to content
This repository was archived by the owner on Feb 17, 2024. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ local.properties
*.iml
gradlew
gradlew.bat
android/.settings
android/.project

# node.js
#
Expand Down
18 changes: 9 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,10 @@ const config: NodeConfig = {
"enode://XXXX@X[::]:XXXX",
"enode://YYYY@Y[::]:YYYY"
],
"networkID": networkID, // --networkid / Network identifier (integer, 0=Olympic (disused), 1=Frontier, 2=Morden (disused), 3=Ropsten) (default: 1)
"networkID": networkID, // --networkid / Network identifier (integer, 42220=mainnet, 62320=baklava (testnet), 44787=alfajores (testnet)) (default: 1)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"maxPeers": 0, // --maxpeers / Maximum number of network peers (network disabled if set to 0) (default: 25)
"genesis": genesis, // genesis.json file
"nodeDir": ".private-ethereum", // --datadir / Data directory for the databases and keystore
"nodeDir": ".celo", // --datadir / Data directory for the databases and keystore
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thinking out loud, we'll want to make sure an update from Valora 1.0.1 to 1.1.0 with these changes doesn't throw errors due to the changed nodeDir. Agree we should make this change here though 👍

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fwiw the approach the app does is specifying .${DEFAULT_TESTNET} as the nodeDir, I think (not totally sure) it tolerates a change well

"keyStoreDir": "keystore", // --keystore / Directory for the keystore (default = inside the datadir)
"enodes": "enode://XXXX@X[::]:XXXX" // static_nodes.json file. Comma separated enode URLs
"noDiscovery": false, // --nodiscover / determines if the node will not participate in p2p discovery (v5)
Expand Down Expand Up @@ -95,7 +95,7 @@ The object that holds the config of the node consists of these fields:
- `logFile` **string** Path where to write geth logfile
- `logFileLogLevel` **number** Log level when writing to file
- `maxPeers` **number** Maximum number of network peers (network disabled if set to 0) (default: 25)
- `networkID` **number** Network identifier
- `networkID` **number** Network identifier
- `noDiscovery` **boolean** Determines if the node will not participate in p2p discovery (v5)
- `nodeDir` **string** Data directory for the databases and keystore
- `syncMode` **number** The number associated with a sync mode in `celo-blockchain/mobile/geth.go`
Expand All @@ -108,8 +108,8 @@ The object that holds the config of the node consists of these fields:
When dealing with blockchain accounts we're usually handling binary data in the hexadecimal format as a general convention of the ecosystem.
These can be private keys, hashes, or transactions encoded in RLP format.
The `celo-blockchain` (geth) library being more low-level expects byte arrays, but getting byte arrays accross the native bridge is troublesome.
As mentioned above a hexadecimal encoded string is the common way of passing around such data but our native environments are lacking in standard library support for parsing hex strings.
We could have added additional code for this, but it would increase our attack surface, it being hard(er) to test and maintain.
As mentioned above a hexadecimal encoded string is the common way of passing around such data but our native environments are lacking in standard library support for parsing hex strings.
We could have added additional code for this, but it would increase our attack surface, it being hard(er) to test and maintain.
Therefore, we've decided to rely on Base64 encoding which is better supported by the native platforms.

This means in several places where we're passing binary data to the bridge `base64` is te preferred encoding. This is easily achieved on the javascript side with access to the `Buffer` type.
Expand All @@ -128,7 +128,7 @@ Configures the node and returns true on success, may throw errors.

**start(): Promise<boolean>**

Start creates a live P2P node and starts running it.
Start creates a live P2P node and starts running it.
Returns true if a node was started, false if node was already running and may throw errors.

### stop
Expand Down Expand Up @@ -195,12 +195,12 @@ Sign a transaction with a passphrase for the signer account.

**Parameters**:
- `txRLPBase64` - base64 encoded transaction in RLP format
- `signer` - the address of the signer
- `signer` - the address of the signer
- `passphrase` - the passphrase to unlock the signer account

Returns the signed transaction in RLP format encoded as base64.

### signHash
### signHash

**signHash(hashBase64: string, signer: string): Promise<signatureBase64: string>**

Expand All @@ -220,7 +220,7 @@ Sign a hash with a passphrase for the signer account.

**Parameters**:
- `hashBase64` - base64 encoded hash
- `signer` - the address of the signer
- `signer` - the address of the signer
- `passphrase` - the passphrase to unlock the signer account

Returns the signature (binary) encoded as base64.
Expand Down
32 changes: 19 additions & 13 deletions android/src/main/java/com/reactnativegeth/RNGethModule.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@
import org.ethereum.geth.Address;
import org.ethereum.geth.BigInt;
import org.ethereum.geth.Context;
// import org.ethereum.geth.Enode;
// import org.ethereum.geth.Enodes;
import org.ethereum.geth.Enode;
import org.ethereum.geth.Enodes;
import org.ethereum.geth.EthereumClient;
import org.ethereum.geth.Geth;
import org.ethereum.geth.Header;
Expand Down Expand Up @@ -107,17 +107,23 @@ public void setConfig(ReadableMap config, Promise promise) {
if (config.hasKey("keyStoreDir")) keyStoreDir = config.getString("keyStoreDir");
if (config.hasKey("syncMode")) nc.setSyncMode(config.getInt("syncMode"));
if (config.hasKey("useLightweightKDF")) nc.setUseLightweightKDF(config.getBoolean("useLightweightKDF"));
// if (config.hasKey("noDiscovery")) nc.setNoDiscovery(config.getBoolean("noDiscovery"));
// if (config.hasKey("bootnodeEnodes")) {
// ReadableArray bootnodeEnodes = config.getArray("bootnodeEnodes");
// int enodesSize = bootnodeEnodes.size();
// Enodes enodes = new Enodes(enodesSize);
// for (int i = 0; i < enodesSize; i++) {
// Enode enode = new Enode(bootnodeEnodes.getString(i));
// enodes.set(i, enode);
// }
// nc.setBootstrapNodes(enodes);
// }
if (config.hasKey("noDiscovery")) nc.setNoDiscovery(config.getBoolean("noDiscovery"));
if (config.hasKey("bootnodeEnodes")) {
ReadableArray bootnodeEnodes = config.getArray("bootnodeEnodes");
int enodesSize = bootnodeEnodes.size();
Enodes enodes = new Enodes(enodesSize);
for (int i = 0; i < enodesSize; i++) {
Enode enode = new Enode(bootnodeEnodes.getString(i));
enodes.set(i, enode);
}
nc.setBootstrapNodes(enodes);
}
// HTTP RPC configurations, which should only be used for development & debugging
if (config.hasKey("httpHost")) nc.setHTTPHost(config.getString("httpHost"));
if (config.hasKey("httpPort")) nc.setHTTPPort(config.getInt("httpPort"));
if (config.hasKey("httpVirtualHosts")) nc.setHTTPVirtualHosts(config.getString("httpVirtualHosts"));
if (config.hasKey("httpModules")) nc.setHTTPModules(config.getString("httpModules"));

if (config.hasKey("ipcPath")) nc.setIPCPath(config.getString("ipcPath"));
if (config.hasKey("logFile")) {
String logFileName = config.getString("logFile");
Expand Down
66 changes: 51 additions & 15 deletions ios/RNGeth.swift
Original file line number Diff line number Diff line change
Expand Up @@ -33,15 +33,15 @@ class RNGeth: RCTEventEmitter, GethNewHeadHandlerProtocol {
runner = NodeRunner()
super.init()
}

// MARK: Utils

func convertToDictionary(from text: String) throws -> [String: String] {
guard let data = text.data(using: .utf8) else { return [:] }
let anyResult: Any = try JSONSerialization.jsonObject(with: data, options: [])
return anyResult as? [String: String] ?? [:]
}

// MARK: RCTEventEmitter

// Not yet sure we actually need main queue setup,
Expand All @@ -63,9 +63,9 @@ class RNGeth: RCTEventEmitter, GethNewHeadHandlerProtocol {
override func supportedEvents() -> [String]! {
return ["GethNewHead"]
}

// MARK: GethNewHeadHandlerProtocol

func onError(_ failure: String?) {
NSLog("@", failure!)
}
Expand All @@ -88,7 +88,7 @@ class RNGeth: RCTEventEmitter, GethNewHeadHandlerProtocol {
NSLog("@", NSErr)
}
}

// MARK: Bridge methods

/**
Expand All @@ -100,13 +100,13 @@ class RNGeth: RCTEventEmitter, GethNewHeadHandlerProtocol {
do {
var addresses: [String] = []
let accounts = try runner.getAccounts()

for i in 0..<accounts.size() {
if let address = try accounts.get(i).getAddress()?.getHex() {
addresses.append(address)
}
}

resolve([addresses] as NSObject)
} catch let NSErr as NSError {
NSLog("@", NSErr)
Expand Down Expand Up @@ -291,14 +291,14 @@ class RNGeth: RCTEventEmitter, GethNewHeadHandlerProtocol {
resolve([true] as NSObject)
return;
}

do {
guard let nodeconfig = GethNewNodeConfig() else {
throw RuntimeError("Unable to create node config")
}
let nodeDir = (config?["nodeDir"] as? String) ?? ETH_DIR
let keyStoreDir = (config?["keyStoreDir"] as? String) ?? KEY_STORE_DIR

if let enodes = config?["enodes"] as? String {
runner.writeStaticNodesFile(enodes: enodes)
}
Expand All @@ -317,14 +317,50 @@ class RNGeth: RCTEventEmitter, GethNewHeadHandlerProtocol {
if let useLightweightKDF = config?["useLightweightKDF"] as? Bool {
nodeconfig.useLightweightKDF = useLightweightKDF
}
if let ipcPath = config?["ipcPath"] as? String {
if let noDiscovery = config?["noDiscovery"] as? Bool {
nodeconfig.noDiscovery = noDiscovery
}
if let bootnodeEnodes = config?["bootnodeEnodes"] as? [String] {
guard let enodes = GethEnodes(bootnodeEnodes.count) else {
throw error ?? RuntimeError("Unable to create GethEnodes")
}
for i in 0..<bootnodeEnodes.count {
try enodes.set(i, enode: GethEnode(bootnodeEnodes[i]))
}
nodeconfig.bootstrapNodes = enodes
}
// HTTP RPC configurations, which should only be used for development & debugging
if let httpHost = config?["httpHost"] as? String {
// Workaround gomobile objc binding bug for properties starting with a capital letter in the go source
// See https://github.com/golang/go/issues/32008
// Once that bug is fixed the assertion will fail and we can switch back to:
// nodeconfig.ipcPath = ipcPath
// nodeconfig.httpHost = httpHost
nodeconfig.setValue(httpHost, forKey: "HTTPHost")
}
if let httpPort = config?["httpPort"] as? Int {
// See comment for httpHost
nodeconfig.setValue(httpPort, forKey: "HTTPPort")
}
if let httpVirtualHosts = config?["httpVirtualHosts"] as? String {
// See comment for httpHost
nodeconfig.setValue(httpVirtualHosts, forKey: "HTTPVirtualHosts")
}
if let httpModules = config?["httpModules"] as? String {
// See comment for httpHost
nodeconfig.setValue(httpModules, forKey: "HTTPModules")
}
if let ipcPath = config?["ipcPath"] as? String {
// See comment for httpHost
nodeconfig.setValue(ipcPath, forKey: "IPCPath")
assert(nodeconfig.ipcPath == ipcPath)
}
if let logFile = config?["logFile"] as? String {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 I actually wanted to bring this up, I noticed it was happening only on android.

var logLevel = 3 // Info
if let logFileLogLevel = config?["logFileLogLevel"] as? Int {
logLevel = logFileLogLevel
}
GethSendLogsToFile(logFile, logLevel, "term")
}

let dataDir = DATA_DIR_PREFIX + "/" + nodeDir

Expand All @@ -351,7 +387,7 @@ class RNGeth: RCTEventEmitter, GethNewHeadHandlerProtocol {
reject(nil, nil, NCErr)
}
}

/**
* Start creates a live P2P node and starts running it.
*
Expand All @@ -373,7 +409,7 @@ class RNGeth: RCTEventEmitter, GethNewHeadHandlerProtocol {
reject(nil, nil, NSErr)
}
}

@objc(subscribeNewHead:rejecter:)
func subscribeNewHead(resolver resolve: RCTPromiseResolveBlock, rejecter reject: RCTPromiseRejectBlock) -> Void {
do {
Expand All @@ -384,7 +420,7 @@ class RNGeth: RCTEventEmitter, GethNewHeadHandlerProtocol {
reject(nil, nil, NSErr)
}
}

/**
* Terminates a running node along with all it's services.
*
Expand Down
5 changes: 4 additions & 1 deletion src/GethNativeModule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ export type NodeConfig = {
bootnodeEnodes?: string[],
enodes?: string,
genesis?: string,
httpHost?: string,
httpModules?: string,
httpPort?: number,
httpVirtualHosts?: string,
ipcPath?: string
keyStoreDir?: string,
logFile?: string,
Expand Down Expand Up @@ -99,4 +103,3 @@ export interface GethNativeModule {
*/
listAccounts: () => Promise<string[]>,
}