Geth version: geth-android-all-1.6.7-ab5646c5
OS & Version: Linux
Commit hash : (if develop)
Light client on Android syncing with Ropsten testnet.
From the Android logs (below), it looks like the ChainID is correct (3), but syncing never starts.
E/GoLog: INFO [07-23|03:45:58] Starting peer-to-peer node instance=GethDroid/v1.6.7-stable/android-arm/go1.8.3
E/GoLog: INFO [07-23|03:45:58] Allocated cache and file handles database=/data/data/com.example.myfirstapp/files/.ethereum/GethDroid/lightchaindata cache=16 handles=16
E/GoLog: INFO [07-23|03:45:58] Writing custom genesis block
E/GoLog: INFO [07-23|03:45:58] Initialised chain configuration config="{ChainID: 3 Homestead: 0 DAO: <nil> DAOSupport: true EIP150: 0 EIP155: 10 EIP158: 10 Metropolis: 9223372036854775807 Engine: ethash}"
E/GoLog: INFO [07-23|03:45:58] Disk storage enabled for ethash caches dir=/data/data/com.example.myfirstapp/files/.ethereum/GethDroid/ethash count=3
E/GoLog: INFO [07-23|03:45:58] Disk storage enabled for ethash DAGs dir=.ethash count=2
E/GoLog: INFO [07-23|03:45:58] Loaded most recent local header number=0 hash=419410…ca4a2d td=1048576
E/GoLog: INFO [07-23|03:45:58] Starting P2P networking
E/GoLog: WARN [07-23|03:45:58] Light client mode is an experimental feature
E/GoLog: INFO [07-23|03:45:58] RLPx listener up self="enode://21befafd82ec9daf7a5bbfb2f53f897df82a3d6adc735aa27b5625c9e4dde4e163f89b877a5192178ca6222ee653d512d761a0e847cf241bacffe0e295260093@[::]:42415?discport=0"
The code I am using is from the Mobile client wiki article, except the NodeConfig has been modified:
NodeConfig nodeConfig = Geth.newNodeConfig();
nodeConfig.setEthereumDatabaseCache(16);
nodeConfig.setEthereumEnabled(true);
nodeConfig.setEthereumGenesis(Geth.testnetGenesis());
nodeConfig.setEthereumNetworkID(3);
Note that the unmodified MainActivity.java example does work on my Android device for mainnet, so it's not a problem with permissions, router, etc.
The full code is below:
package com.example.myfirstapp;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.widget.TextView;
import org.ethereum.geth.*;
import org.ethereum.geth.Geth;
import static org.ethereum.geth.Geth.*;
public class MainActivity extends AppCompatActivity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setTitle("Android In-Process Node");
final TextView textbox = (TextView) findViewById(R.id.textbox);
Context ctx = new Context();
NodeConfig nodeConfig = Geth.newNodeConfig();
nodeConfig.setEthereumDatabaseCache(16);
nodeConfig.setEthereumEnabled(true);
nodeConfig.setEthereumGenesis(Geth.testnetGenesis());
nodeConfig.setEthereumNetworkID(3);
try {
Node node = newNode(getFilesDir() + "/.ethereum", nodeConfig);
node.start();
textbox.append("starting\n");
NodeInfo info = node.getNodeInfo();
textbox.append("My name: " + info.getName() + "\n");
textbox.append("My address: " + info.getListenerAddress() + "\n");
textbox.append("My protocols: " + info.getProtocols() + "\n\n");
EthereumClient ec = node.getEthereumClient();
textbox.append("Latest block: " + ec.getBlockByNumber(ctx, -1).getNumber() + ", syncing...\n");
NewHeadHandler handler = new NewHeadHandler() {
@Override
public void onError(String error) {
textbox.append("error = " + error + "\n");
}
@Override
public void onNewHead(final Header header) {
MainActivity.this.runOnUiThread(new Runnable() {
public void run() {
textbox.append("#" + header.getNumber() + ": " + header.getHash().getHex().substring(0, 10) + "…\n");
}
});
}
};
ec.subscribeNewHead(ctx, handler, 16);
} catch (Exception e) {
textbox.append("\n" + e.getMessage() + "\n");
e.printStackTrace();
}
}
}
[backtrace]
I also spend a couple of weeks trying to figure it out. The only way for the syncing to start in the mobile client when connected to the testnet is by specifying the nodes, otherwise it won't start syncing.
You have to get the list of peers listed in the thread https://gitter.im/ethereum/ropsten and then create a static-nodes.json file with the peers.
This has to be copied in the data directory.
In your case it should be something like getFilesDir() + "/.ethereum/GethDroid/static-nodes.json".
After copying the nodes and restarting your node that syncing should start.
@kelsos Thanks for the reply!
I want to make sure I have the correct list of peers from the gitter.im link. Is this the file content I need to use?
https://gist.github.com/rfikki/ec233552af9f71eb9a00f6cbc4dd7b0d
@4n00p If this is the latest peer list then yes.
@kelsos It's still not able to work. I am using what is supposed to be the latest peer list obtained from gitter.
It looks like I am making a file at:
/data/data/com.example.myfirstapp/files/.ethereum/GethDroid/static-nodes.json
Here is my output:
I/System.out: [
I/System.out: "enode://0b4c77caf2942d12c6c66049cbe14968316581c5bdc62e4bf140b558df10306ccac8fddcc65b7f41458f26f4aa61bac36634ebb858a76c6f3d2d0353dc473691@190.174.36.115:30303",
I/System.out: "enode://167824e9fab5e88dcbc0cf66ac0aadd5967e71836702c2df19d781a0dbb3425cf7fd19545149a508af5eaae52dbf056ede507b5a296c63e4e082b9c5823f1717@69.118.224.44:30303",
I/System.out: "enode://20c9ad97c081d63397d7b685a412227a40e23c8bdc6688c6f37e97cfbc22d2b4d1db1510d8f61e6a8866ad7f0e17c02b14182d37ea7c3c8b9c2683aeb6b733a1@52.169.14.227:30303",
I/System.out: "enode://2507fb78c342d4c884789b6b2e02d07007544d2dc051bf26da861c3cdd9588b7584905b8881256bda66000e23fc790e667ebdfaa69064e5db5ca32f3a77bc806@62.113.241.17:30303",
I/System.out: "enode://39645adb84972cf64ebf1bebbeb8ec24e2e5fe740ab10da9db4c7f72287a6e5f4e14b4db0480324f76775fe11ab0d81833770eece7765b668a6509b31518e7e6@120.77.208.222:30303",
I/System.out: "enode://46b62290ca12a0f5194108aa49bbe3132e5480c8875c7c0a72c4b99b1d4070ed81bcbadbb45ccefdb0c520a628519895ed57794ac2a105aedc85d5c2b1444e5d@104.153.108.98:35555",
I/System.out: "enode://6a91b770ba3f7d08ab1e95fa4c948dca2b4fb5ba22f506ab86614caa582c7532a806abf9ab5d8d2f9970626b2248b54be9871a7cb1dea142c6922af52c2a504b@163.172.139.90:30303",
I/System.out: "enode://6ce05930c72abc632c58e2e4324f7c7ea478cec0ed4fa2528982cf34483094e9cbc9216e7aa349691242576d552a2a56aaeae426c5303ded677ce455ba1acd9d@13.84.180.240:30303",
I/System.out: "enode://8fdea91d05756ac365c7baed10eb0efabd56cc4318db0d8ef3e3d35aeb1d191c243c42fee2963bf704ba7ef46e81fbb5d6c0c9cff2bb09e0f295761bf656d663@185.128.234.220:30303",
I/System.out: "enode://9a4dea061c907e0562e0d5541b208377644a37d248fc019f3e98edd34ab38aba9f51bc6dd70e7cc7c6909509138bbb717bafe583e77f794f4a5290459357c076@92.111.1.196:30303",
I/System.out: "enode://bcc3003c624085896fdaf6ecde45198032c76da6dcda4827861e94af41c6df7685766c0a3891483ba00ff7c339400e897fb107c94d579a59392263a4a13f89b2@192.241.129.128:30304",
I/System.out: "enode://c79cd33186b1dcee5d9b593d76dceddc2019af8038154e5dd5a34e6c9dada3f050166a83580ad05701ed93a0f3b3a3f735222a21d1729026a0509c046198cfd0@172.104.57.227:30303"
I/System.out: ]
E/GoLog: INFO [07-26|02:07:34] Starting peer-to-peer node instance=GethDroid/v1.6.7-stable/android-arm/go1.8.3
E/GoLog: INFO [07-26|02:07:34] Allocated cache and file handles database=/data/data/com.example.myfirstapp/files/.ethereum/GethDroid/lightchaindata cache=16 handles=16
E/GoLog: INFO [07-26|02:07:34] Writing custom genesis block
E/GoLog: INFO [07-26|02:07:34] Initialised chain configuration config="{ChainID: 3 Homestead: 0 DAO: <nil> DAOSupport: true EIP150: 0 EIP155: 10 EIP158: 10 Metropolis: 9223372036854775807 Engine: ethash}"
E/GoLog: INFO [07-26|02:07:34] Disk storage enabled for ethash caches dir=/data/data/com.example.myfirstapp/files/.ethereum/GethDroid/ethash count=3
E/GoLog: INFO [07-26|02:07:34] Disk storage enabled for ethash DAGs dir=.ethash count=2
E/GoLog: INFO [07-26|02:07:34] Loaded most recent local header number=0 hash=419410…ca4a2d td=1048576
E/GoLog: INFO [07-26|02:07:34] Starting P2P networking
E/GoLog: WARN [07-26|02:07:34] Light client mode is an experimental feature
E/GoLog: INFO [07-26|02:07:34] RLPx listener up self="enode://f9379172d0a67cd050648e9bb10d6cc09b2697af96e71641d56e00008afd7bda7c1f46caf3b8cddd6075d833b55f34358f454fa7ac5ff88e9fe4d9cecd98f6f9@[::]:60281?discport=0"
Here is my code. It's a modified version of MainActivity.java from the wiki example.
package com.example.myfirstapp;
import android.os.Bundle;
import android.os.Environment;
import android.support.v7.app.AppCompatActivity;
import android.widget.TextView;
import org.ethereum.geth.Context;
import org.ethereum.geth.Enodes;
import org.ethereum.geth.EthereumClient;
import org.ethereum.geth.Geth;
import org.ethereum.geth.Header;
import org.ethereum.geth.NewHeadHandler;
import org.ethereum.geth.Node;
import org.ethereum.geth.NodeConfig;
import org.ethereum.geth.NodeInfo;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.OutputStreamWriter;
import static org.ethereum.geth.Geth.*;
public class MainActivity extends AppCompatActivity {
private static final String STATIC_NODES_JSON = "[\n" +
"\"enode://0b4c77caf2942d12c6c66049cbe14968316581c5bdc62e4bf140b558df10306ccac8fddcc65b7f41458f26f4aa61bac36634ebb858a76c6f3d2d0353dc473691@190.174.36.115:30303\",\n" +
"\"enode://167824e9fab5e88dcbc0cf66ac0aadd5967e71836702c2df19d781a0dbb3425cf7fd19545149a508af5eaae52dbf056ede507b5a296c63e4e082b9c5823f1717@69.118.224.44:30303\",\n" +
"\"enode://20c9ad97c081d63397d7b685a412227a40e23c8bdc6688c6f37e97cfbc22d2b4d1db1510d8f61e6a8866ad7f0e17c02b14182d37ea7c3c8b9c2683aeb6b733a1@52.169.14.227:30303\",\n" +
"\"enode://2507fb78c342d4c884789b6b2e02d07007544d2dc051bf26da861c3cdd9588b7584905b8881256bda66000e23fc790e667ebdfaa69064e5db5ca32f3a77bc806@62.113.241.17:30303\",\n" +
"\"enode://39645adb84972cf64ebf1bebbeb8ec24e2e5fe740ab10da9db4c7f72287a6e5f4e14b4db0480324f76775fe11ab0d81833770eece7765b668a6509b31518e7e6@120.77.208.222:30303\",\n" +
"\"enode://46b62290ca12a0f5194108aa49bbe3132e5480c8875c7c0a72c4b99b1d4070ed81bcbadbb45ccefdb0c520a628519895ed57794ac2a105aedc85d5c2b1444e5d@104.153.108.98:35555\",\n" +
"\"enode://6a91b770ba3f7d08ab1e95fa4c948dca2b4fb5ba22f506ab86614caa582c7532a806abf9ab5d8d2f9970626b2248b54be9871a7cb1dea142c6922af52c2a504b@163.172.139.90:30303\",\n" +
"\"enode://6ce05930c72abc632c58e2e4324f7c7ea478cec0ed4fa2528982cf34483094e9cbc9216e7aa349691242576d552a2a56aaeae426c5303ded677ce455ba1acd9d@13.84.180.240:30303\",\n" +
"\"enode://8fdea91d05756ac365c7baed10eb0efabd56cc4318db0d8ef3e3d35aeb1d191c243c42fee2963bf704ba7ef46e81fbb5d6c0c9cff2bb09e0f295761bf656d663@185.128.234.220:30303\",\n" +
"\"enode://9a4dea061c907e0562e0d5541b208377644a37d248fc019f3e98edd34ab38aba9f51bc6dd70e7cc7c6909509138bbb717bafe583e77f794f4a5290459357c076@92.111.1.196:30303\",\n" +
"\"enode://bcc3003c624085896fdaf6ecde45198032c76da6dcda4827861e94af41c6df7685766c0a3891483ba00ff7c339400e897fb107c94d579a59392263a4a13f89b2@192.241.129.128:30304\",\n" +
"\"enode://c79cd33186b1dcee5d9b593d76dceddc2019af8038154e5dd5a34e6c9dada3f050166a83580ad05701ed93a0f3b3a3f735222a21d1729026a0509c046198cfd0@172.104.57.227:30303\"\n" +
"]";
protected void onCreate(Bundle savedInstanceState) {
System.out.println(STATIC_NODES_JSON);
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setTitle("Android In-Process Node");
final TextView textbox = (TextView) findViewById(R.id.textbox);
Context ctx = new Context();
NodeConfig nodeConfig = Geth.newNodeConfig();
nodeConfig.setEthereumDatabaseCache(16);
nodeConfig.setEthereumEnabled(true);
nodeConfig.setEthereumGenesis(Geth.testnetGenesis());
nodeConfig.setEthereumNetworkID(3);
try {
Node node = newNode(getFilesDir() + "/.ethereum", nodeConfig);
write(textbox);
node.start();
textbox.append("starting\n");
NodeInfo info = node.getNodeInfo();
textbox.append("My name: " + info.getName() + "\n");
textbox.append("My address: " + info.getListenerAddress() + "\n");
textbox.append("My protocols: " + info.getProtocols() + "\n\n");
EthereumClient ec = node.getEthereumClient();
textbox.append("Latest block: " + ec.getBlockByNumber(ctx, -1).getNumber() + ", syncing...\n");
NewHeadHandler handler = new NewHeadHandler() {
@Override
public void onError(String error) {
textbox.append("error = " + error + "\n");
}
@Override
public void onNewHead(final Header header) {
MainActivity.this.runOnUiThread(new Runnable() {
public void run() {
textbox.append("#" + header.getNumber() + ": " + header.getHash().getHex().substring(0, 10) + "…\n");
}
});
}
};
textbox.append("6\n");
ec.subscribeNewHead(ctx, handler, 16);
} catch (Exception e) {
textbox.append("\n" + e.getMessage() + "\n");
e.printStackTrace();
}
}
public void write(TextView textbox) throws IOException {
File mydir = new File(getFilesDir(),".ethereum");
textbox.append("mydir =" + mydir + "\n");
File subdir = new File(mydir, "GethDroid");
textbox.append("subdir =" + subdir + "\n");
if(subdir.exists() == false){
subdir.mkdir();
textbox.append(subdir.getAbsolutePath() + " subdir created \n");
}
File fileWithinMyDir = new File(subdir, "static-nodes.json"); //Getting a file within the dir.
if(fileWithinMyDir.exists() == false){
fileWithinMyDir.createNewFile();
textbox.append(fileWithinMyDir.getAbsolutePath() + " created new file \n");
}
FileOutputStream fOut = new FileOutputStream(fileWithinMyDir); //Use the stream as usual to write into the file.
OutputStreamWriter myOutWriter = new OutputStreamWriter(fOut);
myOutWriter.write(STATIC_NODES_JSON);
myOutWriter.close();
fOut.flush();
fOut.close();
}
}
Saving the file static-nodes.json to /data/data/com.example.myfirstapp/files/.ethereum/ (and not under "/GethDroid") does not help, either.
Can you try setting the enodes via bootstrapNodes - in WALLETH I am doing it like this:
val ethereumNode = Geth.newNode(path, NodeConfig().apply {
val bootNodes = Enodes()
val network = networkDefinitionProvider.currentDefinition
network.bootNodes.forEach {
bootNodes.append(Enode(it))
}
bootstrapNodes = bootNodes
ethereumGenesis = network.genesis
ethereumNetworkID = network.chainId
ethereumNetStats = settings.getStatsName() + ":Respect my [email protected]"
})
Hi @ligi
I tried that (or what I think is the java equivalent). It did not work, assuming I coded it correctly.
You can see the code here:
_line_ _60_
https://github.com/4n00p/MyApplication/blob/27f836ec2208efeec4aa5b3ac24130d6594110cd/app/src/main/java/com/example/myfirstapp/MainActivity.java#L60
Also, when I run the original example, it does work for mainnet, so it's not a networking problem. I have no clue what is going on.
@4n00p In my case I have the json as a file and I copy it, are you sure that what is finally in the json file is a valid json?
@kelsos
I read the file back and print it to the logs and it seems fine. I can try your method and report back. I'm pretty sure it's not a stupid error, but it's worth double checking. Are you certain that the path should be:
/data/data/com.example.myfirstapp/files/.ethereum/GethDroid/static-nodes.json
There are other folders such as:
/data/data/com.example.myfirstapp/files/.ethereum/GethDroid/lightchaindata
or even
/data/data/com.example.myfirstapp/files/.ethereum/
This is such a pain. I hope I can figure it out. If not, I could try to dev on mainnet? Sigh...
This is such a pain. I hope I can figure it out. If not, I could try to dev on mainnet? Sigh...
You could also use rinkeby - rinkeby for sure works fine with this setup
@4n00p I can confirm the problem - but it only seems to be a problem with ropsten. Please change the title of this issue /s/testnet/ropsten
with rinkeby:
07-28 12:35:03.192 9542 9564 E GoLog : INFO [07-28|10:35:03] Starting peer-to-peer node instance=GethDroid/v1.6.7-stable/android-amd64/go1.8.3
07-28 12:35:03.192 9542 9564 E GoLog : INFO [07-28|10:35:03] Allocated cache and file handles database=/data/user/0/org.walleth/files/.ethereum_rb/GethDroid/lightchaindata cache=16 handles=16
07-28 12:36:21.395 10560 10583 E GoLog : INFO [07-28|10:36:21] Starting peer-to-peer node instance=GethDroid/v1.6.7-stable/android-amd64/go1.8.3
07-28 12:36:21.395 10560 10583 E GoLog : INFO [07-28|10:36:21] Allocated cache and file handles database=/data/user/0/org.walleth/files/.ethereum_rb/GethDroid/lightchaindata cache=16 handles=16
07-28 12:36:21.401 10560 10583 E GoLog : INFO [07-28|10:36:21] Writing custom genesis block
07-28 12:36:21.430 10560 10583 E GoLog : INFO [07-28|10:36:21] Initialised chain configuration config="{ChainID: 4 Homestead: 1 DAO: <nil> DAOSupport: false EIP150: 2 EIP155: 3 EIP158: 3 Metropolis: <nil> Engine: clique}"
07-28 12:36:21.430 10560 10583 E GoLog : INFO [07-28|10:36:21] Loaded most recent local header number=0 hash=6341fd…67e177 td=1
07-28 12:36:21.431 10560 10583 E GoLog : INFO [07-28|10:36:21] Starting P2P networking
07-28 12:36:21.442 10560 10583 E GoLog : WARN [07-28|10:36:21] Light client mode is an experimental feature
07-28 12:36:21.443 10560 10583 E GoLog : INFO [07-28|10:36:21] Stats daemon started
07-28 12:36:21.447 10560 10583 E GoLog : INFO [07-28|10:36:21] RLPx listener up self="enode://f0767e288849709b2f63f99deadd1eaa62cf611c23ed9c12f3841a2c21f1826acb0e013b41bf567d3fc2ff3e58bba050ce7f88ed0d867f0f0009f3f7025eb2e8@[::]:50120?discport=0"
07-28 12:36:34.367 10560 10583 E GoLog : INFO [07-28|10:36:34] Block synchronisation started
07-28 12:36:35.879 10560 10583 E GoLog : INFO [07-28|10:36:35] Imported new block headers count=192 elapsed=272.470ms number=192 hash=8c570c…ba360c ignored=0
with ropsten:
07-28 12:31:43.371 9351 9386 E GoLog : INFO [07-28|10:31:43] Starting peer-to-peer node instance=GethDroid/v1.6.7-stable/android-amd64/go1.8.3
07-28 12:31:43.371 9351 9386 E GoLog : INFO [07-28|10:31:43] Allocated cache and file handles database=/data/user/0/org.walleth/files/.ethereum_rb/GethDroid/lightchaindata cache=16 handles=16
07-28 12:31:43.410 9351 9386 E GoLog : INFO [07-28|10:31:43] Initialised chain configuration config="{ChainID: 3 Homestead: 0 DAO: <nil> DAOSupport: false EIP150: 0 EIP155: 10 EIP158: 10 Metropolis: <nil> Engine: unknown}"
07-28 12:31:43.413 9351 9386 E GoLog : INFO [07-28|10:31:43] Disk storage enabled for ethash caches dir=/data/user/0/org.walleth/files/.ethereum_rb/GethDroid/ethash count=3
07-28 12:31:43.413 9351 9386 E GoLog : INFO [07-28|10:31:43] Disk storage enabled for ethash DAGs dir=.ethash count=2
07-28 12:31:43.416 9351 9386 E GoLog : INFO [07-28|10:31:43] Loaded most recent local header number=0 hash=419410…ca4a2d td=1048576
07-28 12:31:43.417 9351 9386 E GoLog : INFO [07-28|10:31:43] Starting P2P networking
07-28 12:31:43.430 9351 9388 E GoLog : WARN [07-28|10:31:43] Light client mode is an experimental feature
07-28 12:31:43.430 9351 9388 E GoLog : INFO [07-28|10:31:43] Stats daemon started
07-28 12:31:43.430 9351 9388 E GoLog : INFO [07-28|10:31:43] RLPx listener up self="enode://31816aac87c9202a5878a972e2afce54b10517b162c1ab1dd163d1e9ea6be31b6d702865169b70f919ec8e11c49b8542e51d4425732b3f14605358a690b23e90@[::]:43657?discport=0"
EDIT: perhaps also Geth.testnetGenesis() should be removed/renamed as there are now multiple test-nets ..-)
@ligi @kelsos
I was able to get the Android app to start syncing to Ropsten.
Here is the code, but it will only work for Android sdk < 22. If >= 23 you will need to ask the user for writing to file storage in the app. Not a big deal to add.
package com.example.myfirstapp;
import android.Manifest;
import android.content.pm.PackageManager;
import android.content.res.AssetManager;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.widget.TextView;
import org.apache.commons.io.IOUtils;
import org.ethereum.geth.Context;
import org.ethereum.geth.Enodes;
import org.ethereum.geth.EthereumClient;
import org.ethereum.geth.Geth;
import org.ethereum.geth.Header;
import org.ethereum.geth.NewHeadHandler;
import org.ethereum.geth.Node;
import org.ethereum.geth.NodeConfig;
import org.ethereum.geth.NodeInfo;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import static org.ethereum.geth.Geth.*;
public class MainActivity extends AppCompatActivity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setTitle("Android In-Process Node");
final TextView textbox = (TextView) findViewById(R.id.textbox);
try {
// System.out.println("BUILD >>> " + Build.VERSION.SDK_INT);
writeAsset(textbox);
Context ctx = new Context();
NodeConfig nodeConfig = Geth.newNodeConfig();
nodeConfig.setEthereumDatabaseCache(16);
nodeConfig.setEthereumEnabled(true);
nodeConfig.setEthereumGenesis(Geth.testnetGenesis());
nodeConfig.setEthereumNetworkID(3);
Node node = newNode(getFilesDir() + "/.ethereum", nodeConfig);
node.start();
textbox.append("starting\n");
NodeInfo info = node.getNodeInfo();
textbox.append("My name: " + info.getName() + "\n");
textbox.append("My address: " + info.getListenerAddress() + "\n");
textbox.append("My protocols: " + info.getProtocols() + "\n\n");
EthereumClient ec = node.getEthereumClient();
textbox.append("Latest block: " + ec.getBlockByNumber(ctx, -1).getNumber() + ", syncing...\n");
NewHeadHandler handler = new NewHeadHandler() {
@Override
public void onError(String error) {
textbox.append("error = " + error + "\n");
}
@Override
public void onNewHead(final Header header) {
MainActivity.this.runOnUiThread(new Runnable() {
public void run() {
textbox.append("#" + header.getNumber() + ": " + header.getHash().getHex().substring(0, 10) + "…\n");
}
});
}
};
textbox.append("6\n");
ec.subscribeNewHead(ctx, handler, 16);
} catch (Exception e) {
textbox.append("EXCEPTION\n" + e.getMessage() + "\n");
e.printStackTrace();
}
}
public void writeAsset(TextView textbox) throws IOException {
//need runtime permissions for (Build.VERSION.SDK_INT >= 23)
AssetManager assetManager = this.getAssets();
InputStream in = assetManager.open("static-nodes.json");
String fileContents = IOUtils.toString(in);
System.out.println("File contents >>>>\n" + fileContents.toString());
File dir = new File(getFilesDir() + "/.ethereum/GethDroid/");
if (dir.exists() == false) {
dir.mkdirs();
textbox.append("mkdirs" + dir.getAbsolutePath() + "\n");
}
File f = new File(dir, "static-nodes.json");
if (f.exists() == false) {
f.createNewFile();
textbox.append("create new file" + f.getAbsolutePath() + "\n");
}
copyString(fileContents, f);
textbox.append("finished copy\n");
in.close();
}
public void copyString(String fileContents, File outputFile) throws FileNotFoundException {
OutputStream output = new FileOutputStream(outputFile);
PrintWriter p = new PrintWriter(output);
p.println(fileContents);
p.flush();
p.close();
}
}
I am copying the static-nodes.json file from "/app/src/main/assets/static-nodes.json" to ".ethereum/GethDroid/static-nodes.json"
If I purposely created a malformed ".ethereum/GethDroid/static-nodes.json" file, GoLog outputs a json error in Android Monitor, so I knew that the file was being read in.
It looks like the app was syncing. I was able to take a block number and look it up on etherscan Ropsten explorer.
Unfortunately, now my app is freezing up a few minutes after syncing and never finishes...which is most likely an Android-specific problem.
[
"enode://0b4c77caf2942d12c6c66049cbe14968316581c5bdc62e4bf140b558df10306ccac8fddcc65b7f41458f26f4aa61bac36634ebb858a76c6f3d2d0353dc473691@190.174.36.115:30303",
"enode://167824e9fab5e88dcbc0cf66ac0aadd5967e71836702c2df19d781a0dbb3425cf7fd19545149a508af5eaae52dbf056ede507b5a296c63e4e082b9c5823f1717@69.118.224.44:30303",
"enode://20c9ad97c081d63397d7b685a412227a40e23c8bdc6688c6f37e97cfbc22d2b4d1db1510d8f61e6a8866ad7f0e17c02b14182d37ea7c3c8b9c2683aeb6b733a1@52.169.14.227:30303",
"enode://2507fb78c342d4c884789b6b2e02d07007544d2dc051bf26da861c3cdd9588b7584905b8881256bda66000e23fc790e667ebdfaa69064e5db5ca32f3a77bc806@62.113.241.17:30303",
"enode://39645adb84972cf64ebf1bebbeb8ec24e2e5fe740ab10da9db4c7f72287a6e5f4e14b4db0480324f76775fe11ab0d81833770eece7765b668a6509b31518e7e6@120.77.208.222:30303",
"enode://46b62290ca12a0f5194108aa49bbe3132e5480c8875c7c0a72c4b99b1d4070ed81bcbadbb45ccefdb0c520a628519895ed57794ac2a105aedc85d5c2b1444e5d@104.153.108.98:35555",
"enode://6a91b770ba3f7d08ab1e95fa4c948dca2b4fb5ba22f506ab86614caa582c7532a806abf9ab5d8d2f9970626b2248b54be9871a7cb1dea142c6922af52c2a504b@163.172.139.90:30303",
"enode://6ce05930c72abc632c58e2e4324f7c7ea478cec0ed4fa2528982cf34483094e9cbc9216e7aa349691242576d552a2a56aaeae426c5303ded677ce455ba1acd9d@13.84.180.240:30303",
"enode://8fdea91d05756ac365c7baed10eb0efabd56cc4318db0d8ef3e3d35aeb1d191c243c42fee2963bf704ba7ef46e81fbb5d6c0c9cff2bb09e0f295761bf656d663@185.128.234.220:30303",
"enode://9a4dea061c907e0562e0d5541b208377644a37d248fc019f3e98edd34ab38aba9f51bc6dd70e7cc7c6909509138bbb717bafe583e77f794f4a5290459357c076@92.111.1.196:30303",
"enode://bcc3003c624085896fdaf6ecde45198032c76da6dcda4827861e94af41c6df7685766c0a3891483ba00ff7c339400e897fb107c94d579a59392263a4a13f89b2@192.241.129.128:30304",
"enode://c79cd33186b1dcee5d9b593d76dceddc2019af8038154e5dd5a34e6c9dada3f050166a83580ad05701ed93a0f3b3a3f735222a21d1729026a0509c046198cfd0@172.104.57.227:30303"
]
You should not need runtime permissions for the files-dir - this is only needed for external storage.
What exactly is the change that made it work? Don't see it currently ..
What exactly is the change that made it work? Don't see it currently ..
That is a good question. I don't really know. The major difference from my newer code and the older one (when I made the bug report) is that I am copying from one file into another, rather than private static final String STATIC_NODES_JSON = ....
I'm sure it started syncing with the newer code, though. I took a screenshot, which I can post later.
@4n00p The freeze is android. They are doing a lot of changes regarding background execution, So depending on the versions you are running there is a high change that the application was killed in the background. Your best shot to keep it running is by running service with a foreground notification. However even this is not 100% sure to complete. I had my node stop syncing this way after a couple of hours. It might require some experimentation regarding doze etc in order to probably restart the node. Also the mobile syncing process is way slower than the PC.
@kelsos Yes, thanks. I am looking into avoiding the "Application Not Responding" (ANR) dialog.
If you and @ligi agree, I will close this ticket. It looks like ligi might still have some problems?
Feel free to close from my side - I don't care much for Ropsten - Rinkeby and Main are the real deal ;-)
Will try again later though - just currently traveling with limited internet - so cannot test light-client functions currently as this consumes to much traffic - will open another issue if this is still a problem then.
@kelsos I am not an Android expert, but I moved the blockchain sync code as part of an AsyncTask. It seems to sync pretty reliably. One problem is that it doesn't re-sync after app shutdown. I just need a node.stop() somewhere I think....
Is there a place where people discuss Ethereum+Android? I don't see much activity on gitter besides "Please send me ether". I think I need some guidance. Mostly because using Ethereum in an app seems to add up to a bad user experience. I wonder if it's better to use an Ethereum proxy node: https://github.com/p-acs/ethereum-android-lib
I will close the ticket soon.
package com.example.myfirstapp;
import android.content.res.AssetManager;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.widget.TextView;
import org.apache.commons.io.IOUtils;
import org.ethereum.geth.Context;
import org.ethereum.geth.EthereumClient;
import org.ethereum.geth.Geth;
import org.ethereum.geth.Header;
import org.ethereum.geth.NewHeadHandler;
import org.ethereum.geth.Node;
import org.ethereum.geth.NodeConfig;
import org.ethereum.geth.NodeInfo;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import static org.ethereum.geth.Geth.*;
public class MainActivity extends AppCompatActivity {
private TextView textbox = null;
private EthereumClient ec = null;
private final String TAG = MainActivity.class.getName();
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setTitle("Android Ethereum Node");
textbox = (TextView) findViewById(R.id.textbox);
try {
writeAsset();
Log.d(TAG, "starting");
textbox.append("Starting sync....\n");
new SyncBlockChain().execute();
} catch (Exception e) {
textbox.append("EXCEPTION\n" + e.getMessage() + "\n");
e.printStackTrace();
}
}
private class SyncBlockChain extends AsyncTask<Void, Long, String> {
protected String doInBackground(Void...arg0) {
try {
Context ctx = new Context();
NodeConfig nodeConfig = Geth.newNodeConfig();
nodeConfig.setEthereumDatabaseCache(16);
nodeConfig.setEthereumEnabled(true);
nodeConfig.setEthereumGenesis(Geth.testnetGenesis());
nodeConfig.setEthereumNetworkID(3);
Node node = newNode(getFilesDir() + "/.ethereum", nodeConfig);
node.start();
NodeInfo info = node.getNodeInfo();
Log.d(TAG, "My name: " + info.getName());
Log.d(TAG, "My address: " + info.getListenerAddress());
Log.d(TAG, "My protocols: " + info.getProtocols());
ec = node.getEthereumClient();
long blockNumber = ec.getBlockByNumber(ctx, -1).getNumber();
Log.d(TAG,"Latest block: " + blockNumber + ", syncing...\n");
NewHeadHandler handler = new NewHeadHandler() {
@Override
public void onError(String error) {
Log.d(TAG, "error = " + error );
}
@Override
public void onNewHead(final Header header) {
MainActivity.this.runOnUiThread(new Runnable() {
public void run() {
Log.d(TAG, "#" + header.getNumber() + ": " + header.getHash().getHex().substring(0, 10) + "…\n");
textbox.setText("#" + header.getNumber() + ": " + header.getHash().getHex().substring(0, 10) + "…\n");
}
});
}
};
ec.subscribeNewHead(ctx, handler, 16);
} catch (Exception e) {
Log.d(TAG, "EXCEPTION\n" + e.getMessage());
e.printStackTrace();
}
return "Done syncing ...";
}
protected void onProgressUpdate(Integer... progress) {
Log.d(TAG, "Latest block: " + progress + ", syncing...");
}
protected void onPostExecute(String result) {
Log.d(TAG,result);
}
}
public void writeAsset() throws IOException {
AssetManager assetManager = this.getAssets();
InputStream in = assetManager.open("static-nodes.json");
String fileContents = IOUtils.toString(in);
Log.d(TAG, "File contents >>>>\n" + fileContents.toString());
File dir = new File(getFilesDir() + "/.ethereum/GethDroid/");
if (dir.exists() == false) {
dir.mkdirs();
Log.d(TAG, "mkdirs" + dir.getAbsolutePath());
}
File f = new File(dir, "static-nodes.json");
if (f.exists() == false) {
f.createNewFile();
Log.d(TAG, "create new file" + f.getAbsolutePath());
}
copyString(fileContents, f);
Log.d(TAG, "finished copy");
in.close();
}
public void copyString(String fileContents, File outputFile) throws FileNotFoundException {
OutputStream output = new FileOutputStream(outputFile);
PrintWriter p = new PrintWriter(output);
p.println(fileContents);
p.flush();
p.close();
}
}
@4n00p an async-task is not the right instrument for this - you use an async-task if you have some work on the background-thread and handle the result afterwards on the ui-thread - you should use a service here
And yes a place to discuss android<>ethereum would be great - I am thinking about a subreddit - what do you think?
I wonder if it's better to use an Ethereum proxy node
This removes a lot of problems - but adds centralisation
I think you should make the subreddit. It could only help. One advice is to make a "code of conduct" to ensure a good environment for people to ask questions. I noticed that r/ethdev does not always have this.
@4n00p can you reliably sync with ropsten? I can perfectly sync with rinkeby but not with ropsten ..
@ligi
I tried again with the code and static-nodes.json I posted above and I am not able to sync. I posted the output below.
This is the code with MainActivity and a private class SyncBlockChain extends AsyncTask
I would say it was reliably working not too long ago. I will switch to Rinkeby, I suppose.
What ever happened to the Android+ethereum subreddit idea? I'm surprised there isn't more demand for one.
08-04 23:41:22.515 4339-4339/? I/art: Late-enabling -Xcheck:jni
08-04 23:41:22.828 4339-4339/com.example.myfirstapp I/InstantRun: starting instant run server: is main process
08-04 23:41:23.019 4339-4339/com.example.myfirstapp W/art: Before Android 4.1, method android.graphics.PorterDuffColorFilter android.support.graphics.drawable.VectorDrawableCompat.updateTintFilter(android.graphics.PorterDuffColorFilter, android.content.res.ColorStateList, android.graphics.PorterDuff$Mode) would have incorrectly overridden the package-private method in android.graphics.drawable.Drawable
08-04 23:41:23.118 4339-4349/com.example.myfirstapp W/art: Suspending all threads took: 17.358ms
08-04 23:41:23.392 4339-4339/com.example.myfirstapp D/com.example.myfirstapp.MainActivity: File contents >>>>
[
"enode://0b4c77caf2942d12c6c66049cbe14968316581c5bdc62e4bf140b558df10306ccac8fddcc65b7f41458f26f4aa61bac36634ebb858a76c6f3d2d0353dc473691@190.174.36.115:30303",
"enode://167824e9fab5e88dcbc0cf66ac0aadd5967e71836702c2df19d781a0dbb3425cf7fd19545149a508af5eaae52dbf056ede507b5a296c63e4e082b9c5823f1717@69.118.224.44:30303",
"enode://20c9ad97c081d63397d7b685a412227a40e23c8bdc6688c6f37e97cfbc22d2b4d1db1510d8f61e6a8866ad7f0e17c02b14182d37ea7c3c8b9c2683aeb6b733a1@52.169.14.227:30303",
"enode://2507fb78c342d4c884789b6b2e02d07007544d2dc051bf26da861c3cdd9588b7584905b8881256bda66000e23fc790e667ebdfaa69064e5db5ca32f3a77bc806@62.113.241.17:30303",
"enode://39645adb84972cf64ebf1bebbeb8ec24e2e5fe740ab10da9db4c7f72287a6e5f4e14b4db0480324f76775fe11ab0d81833770eece7765b668a6509b31518e7e6@120.77.208.222:30303",
"enode://46b62290ca12a0f5194108aa49bbe3132e5480c8875c7c0a72c4b99b1d4070ed81bcbadbb45ccefdb0c520a628519895ed57794ac2a105aedc85d5c2b1444e5d@104.153.108.98:35555",
"enode://6a91b770ba3f7d08ab1e95fa4c948dca2b4fb5ba22f506ab86614caa582c7532a806abf9ab5d8d2f9970626b2248b54be9871a7cb1dea142c6922af52c2a504b@163.172.139.90:30303",
"enode://6ce05930c72abc632c58e2e4324f7c7ea478cec0ed4fa2528982cf34483094e9cbc9216e7aa349691242576d552a2a56aaeae426c5303ded677ce455ba1acd9d@13.84.180.240:30303",
"enode://8fdea91d05756ac365c7baed10eb0efabd56cc4318db0d8ef3e3d35aeb1d191c243c42fee2963bf704ba7ef46e81fbb5d6c0c9cff2bb09e0f295761bf656d663@185.128.234.220:30303",
"enode://9a4dea061c907e0562e0d5541b208377644a37d248fc019f3e98edd34ab38aba9f51bc6dd70e7cc7c6909509138bbb717bafe583e77f794f4a5290459357c076@92.111.1.196:30303",
"enode://bcc3003c624085896fdaf6ecde45198032c76da6dcda4827861e94af41c6df7685766c0a3891483ba00ff7c339400e897fb107c94d579a59392263a4a13f89b2@192.241.129.128:30304",
"enode://c79cd33186b1dcee5d9b593d76dceddc2019af8038154e5dd5a34e6c9dada3f050166a83580ad05701ed93a0f3b3a3f735222a21d1729026a0509c046198cfd0@172.104.57.227:30303"
]
08-04 23:41:23.394 4339-4339/com.example.myfirstapp D/com.example.myfirstapp.MainActivity: mkdirs/data/data/com.example.myfirstapp/files/.ethereum/GethDroid
08-04 23:41:23.395 4339-4339/com.example.myfirstapp D/com.example.myfirstapp.MainActivity: create new file/data/data/com.example.myfirstapp/files/.ethereum/GethDroid/static-nodes.json
08-04 23:41:23.396 4339-4339/com.example.myfirstapp D/com.example.myfirstapp.MainActivity: finished copy
08-04 23:41:23.397 4339-4339/com.example.myfirstapp D/com.example.myfirstapp.MainActivity: starting
08-04 23:41:23.408 4339-4379/com.example.myfirstapp W/linker: Unsupported flags DT_FLAGS_1=0x8
08-04 23:41:23.408 4339-4379/com.example.myfirstapp W/linker: libgojni.so: unused DT entry: type 0x6ffffffe arg 0x19bd0
08-04 23:41:23.409 4339-4379/com.example.myfirstapp W/linker: libgojni.so: unused DT entry: type 0x6fffffff arg 0x1
08-04 23:41:23.430 4339-4339/com.example.myfirstapp I/ViewRootImpl: CPU Rendering VSync enable = false
08-04 23:41:23.434 4339-4380/com.example.myfirstapp D/OpenGLRenderer: Use EGL_SWAP_BEHAVIOR_PRESERVED: true
08-04 23:41:23.455 4339-4339/com.example.myfirstapp D/Atlas: Validating map...
08-04 23:41:23.475 4339-4339/com.example.myfirstapp D/skia: familyname=Roboto
08-04 23:41:23.476 4339-4339/com.example.myfirstapp D/skia: familyname=Roboto
08-04 23:41:23.480 4339-4339/com.example.myfirstapp D/skia: familyname=Roboto
08-04 23:41:23.482 4339-4339/com.example.myfirstapp D/skia: familyname=Roboto
08-04 23:41:23.484 4339-4339/com.example.myfirstapp D/skia: familyname=Noto Sans Lao UI
08-04 23:41:23.525 4339-4380/com.example.myfirstapp I/Adreno-EGL: <qeglDrvAPI_eglInitialize:379>: EGL 1.4 QUALCOMM build: (I7b941c52a8)
OpenGL ES Shader Compiler Version: E031.25.03.04
Build Date: 06/11/15 Thu
Local Branch:
Remote Branch:
Local Patches:
Reconstruct Branch:
08-04 23:41:23.526 4339-4380/com.example.myfirstapp I/OpenGLRenderer: Initialized EGL, version 1.4
08-04 23:41:23.535 4339-4380/com.example.myfirstapp D/OpenGLRenderer: Enabling debug mode 0
08-04 23:41:23.607 4339-4339/com.example.myfirstapp W/art: Before Android 4.1, method int android.support.v7.widget.ListViewCompat.lookForSelectablePosition(int, boolean) would have incorrectly overridden the package-private method in android.widget.ListView
08-04 23:41:23.634 4339-4380/com.example.myfirstapp D/skia: familyname=Roboto
08-04 23:41:23.708 4339-4339/com.example.myfirstapp I/Timeline: Timeline: Activity_idle id: android.os.BinderProxy@26611ad5 time:3471818
08-04 23:41:24.025 4339-4385/com.example.myfirstapp E/GoLog: INFO [08-05|03:41:24] Starting peer-to-peer node instance=GethDroid/v1.6.7-stable/android-arm/go1.8.3
08-04 23:41:24.025 4339-4385/com.example.myfirstapp E/GoLog: INFO [08-05|03:41:24] Allocated cache and file handles database=/data/data/com.example.myfirstapp/files/.ethereum/GethDroid/lightchaindata cache=16 handles=16
08-04 23:41:24.052 4339-4385/com.example.myfirstapp E/GoLog: INFO [08-05|03:41:24] Writing custom genesis block
08-04 23:41:24.186 4339-4385/com.example.myfirstapp E/GoLog: INFO [08-05|03:41:24] Initialised chain configuration config="{ChainID: 3 Homestead: 0 DAO: <nil> DAOSupport: true EIP150: 0 EIP155: 10 EIP158: 10 Metropolis: 9223372036854775807 Engine: ethash}"
08-04 23:41:24.189 4339-4385/com.example.myfirstapp E/GoLog: INFO [08-05|03:41:24] Disk storage enabled for ethash caches dir=/data/data/com.example.myfirstapp/files/.ethereum/GethDroid/ethash count=3
08-04 23:41:24.189 4339-4385/com.example.myfirstapp E/GoLog: INFO [08-05|03:41:24] Disk storage enabled for ethash DAGs dir=.ethash count=2
08-04 23:41:24.191 4339-4385/com.example.myfirstapp E/GoLog: INFO [08-05|03:41:24] Loaded most recent local header number=0 hash=419410…ca4a2d td=1048576
08-04 23:41:24.193 4339-4385/com.example.myfirstapp E/GoLog: INFO [08-05|03:41:24] Starting P2P networking
08-04 23:41:24.228 4339-4402/com.example.myfirstapp E/GoLog: WARN [08-05|03:41:24] Light client mode is an experimental feature
08-04 23:41:24.228 4339-4402/com.example.myfirstapp E/GoLog: INFO [08-05|03:41:24] RLPx listener up self="enode://aed5506b0c65d4ba898fa4f591e79ebbe06def8bc9b79635e8104d44fe2a82efbd1416a9eea102b2eb1bc80ab78ad30f5dba0d62beacc48f8eecb4ef5afb3183@[::]:59374?discport=0"
08-04 23:41:24.232 4339-4379/com.example.myfirstapp D/com.example.myfirstapp.MainActivity: My name: GethDroid/v1.6.7-stable/android-arm/go1.8.3
08-04 23:41:24.233 4339-4379/com.example.myfirstapp D/com.example.myfirstapp.MainActivity: My address: [::]:59374
08-04 23:41:24.233 4339-4379/com.example.myfirstapp D/com.example.myfirstapp.MainActivity: My protocols: [les]
What ever happened to the Android+ethereum subreddit idea? I'm surprised there isn't more demand for one.
I just created a subreddit - perhaps demand grows with availability ..
This is the URL:
https://www.reddit.com/r/andeth
Most helpful comment
@4n00p an async-task is not the right instrument for this - you use an async-task if you have some work on the background-thread and handle the result afterwards on the ui-thread - you should use a service here
And yes a place to discuss android<>ethereum would be great - I am thinking about a subreddit - what do you think?
This removes a lot of problems - but adds centralisation