After I’ve expressed my concerns about the blockchain technology, let’s get a bit more practical with the blockchain. In particular, with Ethereum.
I needed to send a transaction with Java, so I looked at EthereumJ. You have three options:
- Full node – you enable syncing, which means the whole blockchain gets downloaded. It takes a lot of time, so I abandoned that approach
- “Light” node – you disable syncing, so you just become part of the network, but don’t fetch any parts of the chain. Not entirely sure, but I think this corresponds to the “light” mode of geth (the ethereum CLI). You are able to send messages (e.g. transaction messages) to other peers to process and store on the blockchain, but you yourself do not have the blockchain.
- Offline (no node) – just create and sign the transaction, compute its raw representation (in the ethereum RLP format) and push it to the blockchain via a centralized API, e.g. the etherscan.io API. Etherscan is itself a node on the network and it can perform all of the operations (so it serves as a proxy)
Before going further, maybe it’s worth pointing out a few general properties of the blockchain (the ethereum one and popular cryptocurrencies at least) – it is a distributed database, relying on a peer-to-peer (overlay) network, formed by whoever has a client software running (wallet or otherwise). Transactions are in the form of “I (private key owner) want to send this amount to that address”. Transactions can have additional data stored inside them, e.g. representing what they are about. Transactions then get verified by peers (currently using a Proof-of-work based consensus) and get stored on the blockchain, which means every connected peer gets the newly created blocks (each block consisting of multiple transactions). That’s the blockchain in short, and Ethereum is no exception.
Why you may want to send transactions? I can’t think of a simple and obvious use-case, maybe you just want to implement a better wallet than the existing ones. For example in my case I wanted to store the head of a hash chain on the blockchain so that it cannot be tampered with.
In my particular case I was more interested in storing a particular piece of data as part of the transaction, rather than the transaction itself, so I had two nodes that sent very small transactions to each other (randomly choosing sender and recipient). I know I could probably have done that with a smart contract instead, but “one step at a time”. The initial code can be found here, and is based heavily on the EthereumJ samples. Since EthereumJ uses spring internally, and my application uses spring, it took some extra effort to allow for two nodes, but that’s not so relevant to the task at hand. The most important piece of the code can be seen further below in this post, only slightly modified.
You should have a
user.conf file on the classpath with some defaults, and it can be based on the default ethereumj config. The more important part is the external user1 and user2 conf files (which in the general scenario can just be one conf file). Here’s a sample one, with the following important parameters:
peer.networkId– whether you are using the real production network (=1), or a test network (=3). Obviously, for anything than production you’d want a test network. On test networks you can get free ether by utilizing a faucet. In order to use a test network there are two more parameters below –
blockchain.config.name = ropstenand
genesis = ropsten.json. Note that there are more test networks at the moment, for experimenting with alternatives to proof-of-work.
peer.privateKey– this is the most important bit. It is your secret key which gives you control over your blockchain “account”. Only using that private key you can sign transactions (using an ellptic curve algorithm). The private key has a corresponding public key, which is basically your address on the network – if anyone wants to send funds, he sends them to your public key. But only you can then send funds from your account, as nobody else owns the private key. Which means you have to protect it. In this case it’s in plaintext in a file, which may not be ideal if you operate with big amounts of ether. Consider using some key-management solution (as outlined here)
peer.ip.list– this is optional, but preferable – you need to have a list of peers to connect to in order to bootstrap your client and make it part of the network. The peers there are connected to other peers, and so on, and so forth, so in the end it’s a single interconnected network. Note that in combination with the port number, that requires some additional network configuration if you are using that on a server/cluster/stack – you’d have to open some ports and allow outgoing and incoming connections.
database.dir– this is the directory where the blockchain and the list of discovered peers will be stored. It uses leveldb, and what I found out is that ethereumj uses an outdated leveldb which didn’t work on my machine. So I excluded them and manually used newer versions
sync.enabled– whether you want to fetch the blockchain or not. Normally you don’t need to, as it takes a lot of time, but that way you are not a full node and don’t contribute to the network.
As I noted earlier, I didn’t need a full node, I just needed to send a transaction. The light node would do (the difference should be simply switching sync.enabled from true to false), but after initially successfully connecting to peers, I started getting weird exceptions I didn’t have time to go into, so I couldn’t join the network anymore (maybe because of the crappy wifi I’m currently using).
Fortunately, there is a completely “offline” approach – use an external API to publish your transactions. All you need is your private key and a library (EthereumJ in this case) to prepare your transaction. So you can forget everything you read in the previous paragraphs. What you need is just the RLP encoded transaction after you have signed it. E.g.:
byte nonce = ByteUtil.intToBytes(getTransactionCount(senderAddress) + 1); byte gasPrice = getGasPrice(); Transaction tx = new Transaction( nonce, gasPrice, ByteUtil.longToBytesNoLeadZeroes(200000), receiverAddress, ByteUtil.bigIntegerToBytes(BigInteger.valueOf(1)), // 1 gwei data.getBytes(StandardCharsets.UTF_8), CHAIN_ID); tx.sign(ECKey.fromPrivate(senderPrivateKey)); byte rawTx = tx.getEncoded(); restTemplate.getForObject(etherscanUrl, String.class, "0x" + BaseEncoding.base16().encode(rawTx));
What are the parameters above?
nonce– this is a sequence number for transactions per user (=per private key). Each subsequent transaction should have a nonce that is the nonce of the previous + 1. That way nobody can replay the same transaction and drain the funds of the sender (the transaction that gets signed contains the nonce, so you cannot use the same raw transaction representation and just resubmit it). How to obtain the nonce? If you are connected to the Ethereum network, there’s a
ethereum.getRepository().getNonce(fromAddress);. However, in a disconnected scenario, you’d need to obtain the current number of transactions for the sender, and then increment it. This is done via the
eth_getTransactionCountendpoint. Note that it’s returned as hexadecimal, so you have to parse it, e.g.
- gas price, maximum gas price – these are used to cover the transaction costs (sending isn’t for free). You can read more here. You can obtain the current gas price by calling the “eth_gasPrice” API endpoint. Probably it’s a good idea to actually fetch the gas price periodically and cache it for a short period, rather than fetching it for every transaction. If you are connected to the network, you can obtain the gas price automatically.
receiverAddress– a byte array representing the public key of the recipient
value– how much ether you want to send. The smallest unit is actually a “gwei”, and the value is specified in gweis (a fraction of 1 ETH)
data– any additional data that you want to put in the transaction.
chainId– this is again related to which network you are using. Production=1, Ropsten test network=3. If you are curious why you have to encode it in a transaction, you can read here.
After that you sign the raw representation of the transaction with your private key (the raw representation is RLP (Recursive Length Prefix)). And then you send it to the API (you’d need a key for that, which you can get at Etherscan and include it in the URL). It’s almost identical to what you would’ve done if you were connected. But now you are relying on a central party (Etherscan) instead of becoming part of the network.
It may look “easy”, and when you’ve already done it and grasped it, it sounds like a piece of cake, but there are too many details that nobody abstracts from you, so you have to have the full picture before even being able to push a single transaction. What a nonce is, what a chainId is, what a test network is, how to get test ether (the top google result for a ropsten faucet doesn’t work at the moment, so you have to figure that out as well), then figure out whether you want to sync the chain or not, to be part of the network or not, to resolve weird connectivity issues and network configuration. And that’s not even mentioning smart contracts. I’m not saying it’s bad, it’s just not simple enough and that’s a barrier to wider adoption. That probably applies to most of programming, though. Anyway, I hope the above examples can get people started more easily.