[Ethereum] Not able to decode the input data from transaction using web3j

raw-transactionweb3j

I am creating transactions using web3j and passing some private data in that transaction. The transaction is also getting mined . I have subscribed to the mined blocks, where I am fetching the transactions added in the mined block. I want to retrieve the input data passed earlier, but unable to get it. Please help me here.

Code for transacting using web3j:

RawTransactionManager rawTransactionManager =  new RawTransactionManager(web3j ,credentials,100,1000 * 15);

EthSendTransaction send = rawTransactionManager.sendTransaction(gasPrice, Transfer.GAS_LIMIT, toAddress, "<some private data>", BigInteger.valueOf(1));

String hash = send.getTransactionHash();

I also get the hash properly. Then, I subscribed to the blocks as follows:

Subscription subscriptionToBlocks = web3j.blockObservable(true).subscribe(block -> {
        List<TransactionResult> transactions = block.getBlock().getTransactions();
        if(transactions.size > 0){
            transactions.forEach(tx -> {
                  EthBlock.TransactionObject transaction = (EthBlock.TransactionObject) tx.get();
                  System.out.println("transaction data:"+transaction.getInput());
        }

But this results in hex string, however, i want it decrypted again to process it further. Let me know how can i get the original data that was sent

Best Answer

Presumably your <some private data> is ASCII encoded and Ethereum converts everything in byte code (machine readable) and returns everything in hexadecimal (base16) which mess up the encoding.

So the solution consist in encoding your message in ASCII hex before sending the transaction.

public static String ASCIItoHEX(String ascii)  { 
    // Initialize final String 
    String hex = ""; 

    // Make a loop to iterate through 
    // every character of ascii string 
    for (int i = 0; i < ascii.length(); i++) { 

        // take a char from 
        // position i of string 
        char ch = ascii.charAt(i); 

        // cast char to integer and 
        // find its ascii value 
        int in = (int)ch; 

        // change this ascii value 
        // integer to hexadecimal value 
        String part = Integer.toHexString(in); 

        // add this hexadecimal value 
        // to final string. 
        hex += part; 
    } 
    // return the final string hex 
    return hex; 
} 

So when you send you transaction, you only need to convert your message in Hex:

RawTransactionManager rawTransactionManager =  new RawTransactionManager(web3j, credentials, 4, 1000 * 15);
EthSendTransaction send = rawTransactionManager.sendTransaction(BigInteger.valueOf(1000000000000L), BigInteger.valueOf(100000L), "0xDD6325C45aE6fAbD028D19fa1539663Df14813a8", ASCIItoHEX("hello"), BigInteger.valueOf(1));
String hash = send.getTransactionHash();

You can see now the input data is correct: https://rinkeby.etherscan.io/tx/0xd3b67f1e67c4607cb0d6a2f02066d1d382843da0619d9f02bb8da5f1fc0bb66a


When you get the transaction after it's being mined, you only need to do the opposite:

String hexString = transaction.getInput();

// Remove the prefix 0x 
if(hexString.startsWith("0x")) {
    hexString = hexString.substring(2);
}

// Convert Base16 into a byte array 
byte[] byteArray = new BigInteger(hexString, 16).toByteArray();

// Pass the byte array to a String will re-encode it in ASCII.
String asciiString = new String(byteArray);

System.out.println(hexString+"="+asciiString);

68656c6c6f=hello

Useful links