以太坊常见问题和错误

在线工具推荐: Three.js AI纹理开发包 - YOLO合成数据生成器 - GLTF/GLB在线编辑 - 3D模型格式在线转换 - 可编程3D场景编辑器

web3j中字符串如何转换Bytes32?我想用web3j发送bytes32类型的参数到SmartContract函数,它总是抛出异常。 先来看一段代码:

public String solFunction(String str) {
    byte[] byteValue = DatatypeConverter.parseHexBinary(str);
    Bytes32 strInBytes = new Bytes32(byteValue);
    try {
        Uint256 value = contract.showPoint(strInBytes).get();
        return value.getValue().toString();
    } catch (InterruptedException | ExecutionException e) {
        e.printStackTrace();
    }
    return null;
}

// web3j generated java code for solidity program
public Future<Uint256> showPoint(Bytes32 byteValue) {
        Function function = new Function("showPoint", 
                Arrays.<Type>asList(rewardType), 
                Arrays.<TypeReference<?>>asList(new TypeReference<Uint256>() {}));
        return executeCallSingleValueReturnAsync(function);
    }

我已经检查了web3j的Numeric datatype转换,并给出了解决方案。

Input byte array must be in range 0 < M <= 32 and length must match type

我的以太坊智能合约代码:

contract MyContract {
    address public owner; // Store owner address
    mapping (address => mapping (bytes32 => uint)) value;

    function MyContract (uint initValue, bytes32 chkByte) {
        owner = msg.sender;
        reward[msg.sender][chkByte] = initValue;
    }

    function showAvailReward(bytes32 chkByte) constant returns(uint) {
            return value[msg.sender][chkByte];
        }
}

问题的解决

主要问题是Bytes32(byte[])只支持32位长度的byte[]。同样记住Numeric.hexStringToByteArray(strValueInHex)将任何HexString转换为byte[]

处理过程:

String => Hex => 32 length Hex (ie. 64 length HexString) => byte[] => Bytes32

注意:00 等于1个Hex长度或者2个String长度。

字符串到64位长的HexString:

// String to 64 length HexString (equivalent to 32 Hex lenght)
public static String asciiToHex(String asciiValue)
{
    char[] chars = asciiValue.toCharArray();
    StringBuffer hex = new StringBuffer();
    for (int i = 0; i < chars.length; i++)
    {
        hex.append(Integer.toHexString((int) chars[i]));
    }

    return hex.toString() + "".join("", Collections.nCopies(32 - (hex.length()/2), "00"));
}

64位长的HexString到32位长的byte[]:

byte[] myStringInByte = Numeric.hexStringToByteArray(asciiToHex("myString"));

32位长的byte[]Bytes32:

Bytes32 myStringInBytes32 = new Bytes32(myStringInByte);

现在myStringInBytes32被接受为web3j的以太坊智能合约功能。在我的案例中solFunction(String str)修改代码如下:

public String solFunction(String str) {
    String strInHex = asciiToHex(str);
    Bytes32 strInBytes32 = new Bytes32(Numeric.hexStringToByteArray(strInHex));
    try {
        Uint256 value = contract.showPoint(strInBytes32).get();
        return value.getValue().toString();
    } catch (InterruptedException | ExecutionException e) {
        e.printStackTrace();
    }
    return null;
}

如果你的solidity函数在Bytes32中返回数据,那么下面是如何从返回的Bytes32数据中获取值:

String dataInString = hexToASCII(Numeric.toHexStringNoPrefix(dataInBytes32);

函数hexToASCII

public static String hexToASCII(String hexValue)
    {
        StringBuilder output = new StringBuilder("");
        for (int i = 0; i < hexValue.length(); i += 2)
        {
            String str = hexValue.substring(i, i + 2);
            output.append((char) Integer.parseInt(str, 16));
        }
        return output.toString();
    }

Convert Hex to ASCII and ASCII to Hex June 5, 2014 by Lokesh Gupta

更简单的方法

string 到32位长的byte32:

public static Bytes32 stringToBytes32(String string) {
        byte[] byteValue = string.getBytes();
        byte[] byteValueLen32 = new byte[32];
        System.arraycopy(byteValue, 0, byteValueLen32, 0, byteValue.length);
        return new Bytes32(byteValueLen32);
    }

32位长的byte32到string:

StringUtils.newStringUsAscii(varTypeBytes32.getValue());