[Ethereum] Web3j test accounts and Credentials object

web3j

I launch the ethereum blockchain by running testrpc. That is creating 10 test accounts with sufficient funds.
When I use web3 with node.js to to deploy a new smart contract, I can use:

MyContract.new(['MyProps'],{data: byteCode, from: web3.eth.accounts[0], gas: 4800000})

When I use web3 with Java, I need a Credentials object. The following line seems not to work, because the deployment returns that the account has not sufficient funds.

String account = web3.ethAccounts().send().getAccounts().get(0);
Credentials c = Credentials.create(account);
Contract_sol_Contract contract = Contract_sol_Contract.deploy(web3, c, new BigInteger("240000"),new BigInteger("2400000"), props).send();

-->sender doesn't have enough funds to send tx. The upfront cost is: 576 and the sender's account only has: 0

Obviously, the Credentials object is not correct. As far as I understand, the private key must be passed and I used the public address.

  1. How can I access the private address in Java web3j?
  2. Why is it sufficient in web3 (node.js) to use the public address for the deployment of the contract?

Thanks in advance,
Marco

Best Answer

Here is a more complete program than the one you provided. The only undefined part is Contract_sol_Contract, which you did not define. Notice how privateKey and publicKey are computed.

import org.web3j.crypto.Credentials;
import org.web3j.crypto.ECKeyPair;
import org.web3j.protocol.Web3j;
import org.web3j.protocol.http.HttpService;

import java.io.IOException;
import java.math.BigInteger;

public class SO3 {
    public SO3() throws IOException {
        Web3j web3 = Web3j.build(new HttpService("http://localhost:8545"));
        String account = web3.ethAccounts().send().getAccounts().get(0);
        Credentials credentials = Credentials.create(account);
        ECKeyPair keyPair = credentials.getEcKeyPair();
        BigInteger privateKey = keyPair.getPrivateKey();
        BigInteger publicKey = keyPair.getPublicKey();
        Contract_sol_Contract contract = Contract_sol_Contract.deploy(web3, credentials, new BigInteger("240000"), new BigInteger("2400000"), props).send();
    }
}

I think that the reason that web3j deviated from web3 in requiring just the public or private key is because providing less information is a better security practice. The web3 accounts docs has this warning: The accounts private key. This should never be shared or stored unencrypted in localstorage! Also make sure to null the memory after usage. This means passing around the entire accounts object is discouraged.

Seems the web3 authors knew they created a security issue because earlier on that same page they give this big fat warning: This package has NOT been audited and might potentially be unsafe. Take precautions to clear memory properly, store the private keys safely, and test transaction receiving and sending functionality properly before using in production!.