Create Account On Android

import geth dependency to Android Studio

apply plugin: 'com.android.application'

android {
    ...
}

dependencies {
    ...
    compile 'org.ethereum:geth:1.7.0'
}

Library bundles section of Mobile: Introduction

create account

I can use KeyStore of geth library to create account. I have to give newAccount() a password, then it will create the private key, and using my password to encrypt the private key with AES-128 to the key store file. That key store file includes JSON content, it has account address and encrypted private key.

  • MainActivity.java
import org.ethereum.geth.Account;
import org.ethereum.geth.Geth;
import org.ethereum.geth.KeyStore;

public class MainActivity extends AppCompatActivity {
    private KeyStore keyStore;
    private Account account;

    ...

    private void createAccountDemo() throws Exception {
        createKeyStore(new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) +  "/ETH/privatechain/keystore").getPath());
        account = createAccount("a1234567");
        Log.d("main", account.getURL());
        Log.d("main", "account address is " + account.getAddress().getHex());
    }

    private void createKeyStore(String keyStoreFolderPath) {
        keyStore = new KeyStore(keyStoreFolderPath, Geth.LightScryptN, Geth.LightScryptP);
    }

    private Account createAccount(String password) throws Exception {
        return keyStore.newAccount(password);
    }
}
  • LogCat
keystore:///storage/emulated/0/Download/ETH/privatechain/keystore/UTC--2017-10-02T07-02-09.341966351Z--eda1370b372a909aaec04e56ac395f1faa5b585d
account address is 0xEDA1370B372a909AAEC04E56ac395F1FAa5B585d
  • key store file
{
    "address":"eda1370b372a909aaec04e56ac395f1faa5b585d",
    "crypto":{
        "cipher":"aes-128-ctr",
        "ciphertext":"a05359e5c053798ff0c6318f3c93d5f155b6a906767457a29c508b7bae4d9d96",
        "cipherparams":{
            "iv":"43856647487d92a5edc791fd495693af"
        },
        "kdf":"scrypt",
        "kdfparams":{
            "dklen":32,
            "n":4096,
            "p":6,
            "r":8,
            "salt":"200ba5f2f7d8ee0316f830f315e5450d480cb59fa9ccec999fce32995b8ddeb2"
        },
        "mac":"11f9e7746e2f066a48334ca725fec102a8972e470701f122bbcb8fd1e11ba436"
    },
    "id":"5f1ec8a3-62ff-4d43-90af-63edd1c8aa29",
    "version":3
}

Accounts on Android (Java) section of Mobile: Account management

geth - GoDoc for mobile

start node on Android to sync with my private chain

copy static-nodes.json to device folder

${android storage}/ETH/prviatechain/GethDroid/static-nodes.json

[
    "enode://540e892d76e86b3221aed4858613d7a9b96a1199db4c00901803dfc4abb59e1be359bd33281b91abb126aeb048c79a0720f80a5688c07b3ee4e16fcd5f44a83b@192.168.200.207:30303?discport=30304"
]

kelsoson Jul 25commented on go-ethereum issue 3789, said that "the static-nodes.json must be under the

$filesDir/.ethereum/GethDroid/static-nodes.jsonin order to get picked."

set the network id

private static final long PRIVATE_CHAIN_NETWORK_ID = 56821;

set the genesis block

Make the /Users/yen/Desktop/privateChain/privateChain.json to be one line, so that I can avoid the newline character problem.

public class PrivateChain {
    public static final String genesis = "{ \"config\": { \"chainId\": 56821, \"homesteadBlock\": 1, \"eip150Block\": 2, \"eip150Hash\": \"0x0000000000000000000000000000000000000000000000000000000000000000\", \"eip155Block\": 3, \"eip158Block\": 3, \"clique\": { \"period\": 3, \"epoch\": 30000 } }, \"nonce\": \"0x0\", \"timestamp\": \"0x59cf588f\", \"extraData\": \"0x0000000000000000000000000000000000000000000000000000000000000000726794b16f6c5b0be0b78d7713a876ed3da8be1a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\", \"gasLimit\": \"0x47b760\", \"difficulty\": \"0x1\", \"mixHash\": \"0x0000000000000000000000000000000000000000000000000000000000000000\", \"coinbase\": \"0x0000000000000000000000000000000000000000\", \"alloc\": { \"c077f8420d5b6c125897d9c5e21293ff6f77855c\": { \"balance\": \"0x200000000000000000000000000000000000000000000000000000000000000\" } }, \"number\": \"0x0\", \"gasUsed\": \"0x0\", \"parentHash\": \"0x0000000000000000000000000000000000000000000000000000000000000000\" }";
}
  • MainActivity.java
public class MainActivity extends AppCompatActivity {
    private static final long PRIVATE_CHAIN_NETWORK_ID = 56821;

    ...

    private void startNode2CheckBalance() throws Exception {
        createKeyStore(new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) + "/" + "ETH" + "/privatechain/keystore").getPath());
        Accounts accounts = keyStore.getAccounts();
        account = accounts.get(0);

        final Context ctx = new Context();

        NodeConfig nodeConfig = Geth.newNodeConfig();
        nodeConfig.setEthereumNetworkID(PRIVATE_CHAIN_NETWORK_ID);
        nodeConfig.setEthereumGenesis(PrivateChain.genesis);
        nodeConfig.setEthereumDatabaseCache(512);
        nodeConfig.setMaxPeers(10);
        nodeConfig.setWhisperEnabled(true);
        nodeConfig.setEthereumEnabled(true);
        final Node node = Geth.newNode(new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) + "/" + "ETH" + "/privatechain").getPath(), nodeConfig);

        try {
            node.start();

            NodeInfo info = node.getNodeInfo();
            Log.d("main", "name is " + info.getName());
            Log.d("main", "address is " + info.getListenerAddress());
            Log.d("main", "protocols is " + info.getProtocols());
            Log.d("main", "ID is " + info.getID());
            Log.d("main", "ListenerPort is " + info.getListenerPort());
            Log.d("main", "DiscoveryPort is " + info.getDiscoveryPort());
            Log.d("main", "IP is " + info.getIP());
            Log.d("main", "enode is " + info.getEnode());

            final EthereumClient ec = node.getEthereumClient();
            Log.d("main", "Latest block: " + ec.getBlockByNumber(ctx, -1).getNumber() + ", syncing");

            NewHeadHandler handler = new NewHeadHandler() {
                @Override
                public void onError(String error) {
                    Log.d("main", "NewHeadHandler: " + error);
                }

                @Override
                public void onNewHead(final Header header) {
                    try {
                        Log.d("main", "#" + header.getNumber() + ": " + header.getHash().getHex().substring(0, 10));
                        PeerInfo peerInfo = node.getPeersInfo().get(0);
                        Log.d("main", "peers amount " + node.getPeersInfo().size() + "; " + peerInfo.getName() + "; " + peerInfo.getID() + "; " + peerInfo.getRemoteAddress());
                        Log.d("main", "balance of android node " + account.getAddress().getHex() + " is " + ec.getBalanceAt(ctx, account.getAddress(), -1).getInt64());
                        Log.d("main", "balance of server node 0x726794b16f6c5b0be0b78d7713a876ed3da8be1a is " + ec.getBalanceAt(ctx, new Address("0x726794b16f6c5b0be0b78d7713a876ed3da8be1a"), -1).getInt64());
                        Log.d("main", "balance of miner2 node 0xc077f8420d5b6c125897d9c5e21293ff6f77855c is " + ec.getBalanceAt(ctx, new Address("0xc077f8420d5b6c125897d9c5e21293ff6f77855c"), -1).getInt64());
                        Log.d("main", "balance of light node 0x52ea0215068f436f837788686aa4b25de1a98f07 is " + ec.getBalanceAt(ctx, new Address("0x52ea0215068f436f837788686aa4b25de1a98f07"), -1).getInt64());

                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            };
            ec.subscribeNewHead(ctx, handler, 16);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

Mobile Clients: Libraries and Inproc Ethereum Nodes

  • LogCat
E/GoLog: INFO [10-02|07:50:17] Starting peer-to-peer node               instance=GethDroid/v1.7.0-stable/android-386/go1.9
E/GoLog: INFO [10-02|07:50:17] Allocated cache and file handles         database=/storage/emulated/0/Download/ETH/privatechain/GethDroid/lightchaindata cache=512 handles=16
E/GoLog: INFO [10-02|07:50:17] Writing custom genesis block 
E/GoLog: INFO [10-02|07:50:17] Initialised chain configuration          config="{ChainID: 56821 Homestead: 1 DAO: <nil> DAOSupport: false EIP150: 2 EIP155: 3 EIP158: 3 Byzantium: <nil> Engine: clique}"
E/GoLog: INFO [10-02|07:50:17] Loaded most recent local header          number=0 hash=ffaa00…d07f18 td=1
E/GoLog: INFO [10-02|07:50:17] Starting P2P networking 
E/GoLog: WARN [10-02|07:50:18] Light client mode is an experimental feature E/GoLog: INFO [10-02|07:50:18] RLPx listener up                         self="enode://b916a97604eb9119798646149f3075393a9fad22df0a3206ae0d4a13dd2645c165fc0cf7e54e4006a54e36e69b5517abfdeee9f2fe327e290f15b2e54c3abd25@[::]:60934?discport=0"
E/GoLog: INFO [10-02|07:50:18] started whisper v.5.0 

D/main: name is GethDroid/v1.7.0-stable/android-386/go1.9
D/main: address is [::]:60934
D/main: protocols is [les shh]
D/main: ID is b916a97604eb9119798646149f3075393a9fad22df0a3206ae0d4a13dd2645c165fc0cf7e54e4006a54e36e69b5517abfdeee9f2fe327e290f15b2e54c3abd25
D/main: ListenerPort is 60934
D/main: DiscoveryPort is 0
D/main: IP is ::
D/main: enode is enode://b916a97604eb9119798646149f3075393a9fad22df0a3206ae0d4a13dd2645c165fc0cf7e54e4006a54e36e69b5517abfdeee9f2fe327e290f15b2e54c3abd25@[::]:60934?discport=0
D/main: Latest block: 0, syncing
  • check peers on server node console
> net.peerCount
3
> admin.peers

[{
    caps: ["les/1"],
    id: "66bd5b4e4801c069bd01cc3760a18d3c8f72fb2f433a680f8d2f77ce18d5ad0af7327a668b7c855675be0996367e76fc0f2b0f6de977ffdeaa9756cc99824ed7",
    name: "Geth/light/v1.7.0-stable-6c6c7b2a/darwin-amd64/go1.7.1",
    network: {
      localAddress: "192.168.200.207:30303",
      remoteAddress: "192.168.200.207:62107"
    },
    protocols: {
      les: {
        difficulty: 121,
        head: "2b8e637d11798c28a88d5a3623f8ca92fd39987c15abd6bc0a65e2ef85bdd53d",
        version: 1
      }
    }
}, {
    caps: ["eth/62", "eth/63"],
    id: "acf05a7cc42e6504ca63e57c7cb70e7c0ec05c45cb38fe4691c9b71ec125b003751fbe00f2a6c6a4868fa1b17c50552687b7ec06677f9a19cca00411994994ac",
    name: "Geth/miner2/v1.7.0-stable-6c6c7b2a/darwin-amd64/go1.7.1",
    network: {
      localAddress: "192.168.200.207:30303",
      remoteAddress: "192.168.200.207:62102"
    },
    protocols: {
      eth: {
        difficulty: 121,
        head: "0x2b8e637d11798c28a88d5a3623f8ca92fd39987c15abd6bc0a65e2ef85bdd53d",
        version: 63
      }
    }
}, {
    caps: ["les/1", "shh/5"],
    id: "b916a97604eb9119798646149f3075393a9fad22df0a3206ae0d4a13dd2645c165fc0cf7e54e4006a54e36e69b5517abfdeee9f2fe327e290f15b2e54c3abd25",
    name: "GethDroid/v1.7.0-stable/android-386/go1.9",
    network: {
      localAddress: "192.168.200.207:30303",
      remoteAddress: "192.168.200.207:64348"
    },
    protocols: {
      les: {
        difficulty: 1,
        head: "ffaa00ed88c5cdc8b510dc5fbf5676d7373e040563c7133c9556eb8d21d07f18",
        version: 1
      }
    }
}]

When start mine on server and miner2 nodes, the android node will sync the header of blocks.

E/GoLog: INFO [10-02|07:51:44] Block synchronisation started 
E/GoLog: INFO [10-02|07:51:44] Imported new block headers               count=120 elapsed=199.023ms number=120 hash=0d6418…b49f0e ignored=0

D/main: #1: 0x467bdf1a

D/main: peers amount 1; Geth/server/v1.7.0-stable-6c6c7b2a/darwin-amd64/go1.7.1; 540e892d76e86b3221aed4858613d7a9b96a1199db4c00901803dfc4abb59e1be359bd33281b91abb126aeb048c79a0720f80a5688c07b3ee4e16fcd5f44a83b; 192.168.200.207:30303
D/main: balance of android node 0xEDA1370B372a909AAEC04E56ac395F1FAa5B585d is 0
D/main: balance of server node 0x726794b16f6c5b0be0b78d7713a876ed3da8be1a is 1000000000000000000
D/main: balance of miner2 node 0xc077f8420d5b6c125897d9c5e21293ff6f77855c is 8447878073709551616
D/main: balance of light node 0x52ea0215068f436f837788686aa4b25de1a98f07 is 8998866000000000000

D/main: #2: 0x4027082e
D/main: #3: 0xeb71adf2
...
D/main: #120: 0x0d641802

E/GoLog: INFO [10-02|07:51:50] Imported new block headers               count=2   elapsed=2.908ms   number=122 hash=d5a7fd…d8d2fd ignored=0

results matching ""

    No results matching ""