Week19- 11.14
Day1 Java-Solidity-类型映射
基本类型
The basic types in solidity
such as the uint256
, bytes
, byte32[]
can be shown in the following.
Solidity Type | web3j.abi type | conflux-Java-sdk Type | Example |
---|---|---|---|
uintxxx | Uintxxx | BigInteger | new Uint256(new BigInteger("111")) |
address | Address | Address(cfx:xxxx) | new org.web3j.abi.Address(new Address("xxxxx")) |
bool | Bool | Boolean | new Bool(true) |
string | Utf8String | String | new Utf8String("heyman") |
bytesxx | Bytesxx | byte[] | new Bytes32("111".getBytes()) |
bytes | DynamicBytes | byte[] | new DynamicBytes("111".getBytes()) |
Static Array (address[2]) | StaticArray2 | new StaticArray2<>(org.web3j.abi.datatypes.Address.class, xxx) | |
Dynamic Array (address[]) | DynamicArray | new DynamicArray<>(org.web3j.abi.datatypes.Address.class, xxx) |
结构体
以下举了一个例子
struct Foo {
Address[] addresses;
}
public static class BasicAddressesStruct extends DynamicStruct {
public List<org.web3j.abi.datatypes.Address> addr;
public BasicAddressesStruct(List<org.web3j.abi.datatypes.Address> addr) {
super(new org.web3j.abi.datatypes.DynamicArray<org.web3j.abi.datatypes.Address>(addr));
this.addr = addr;
}
public BasicAddressesStruct(DynamicArray<org.web3j.abi.datatypes.Address> addr) {
super(addr);
this.addr = addr.getValue();
}
}
需要注意的是,若结构体中包含动态类型,如bytes[]
, string
等,创建的类需要继承DynamicStruct,否则,需要继承StaticStruct
Day2 Decode响应
当我们查询合约时,返回的是一串hexstring。 本节开始将告诉大家如何将这一串hexstring转为相应的类型
单个基本类型
contractCall.callAndGet(Utf8String.class,"text", node, key)
多个基本类型
以java-sdk的posRegister的内置合约的getVotes
方法为例
用一个TupleDecoder去对hexstring进行decode
BigInteger[] res = new BigInteger[2];
String rawData = this.call("getVotes", new Bytes32(Numeric.hexStringToByteArray(identifier))).sendAndGet();
rawData = Numeric.cleanHexPrefix(rawData);
TupleDecoder decoder = new TupleDecoder(rawData);
res[0] = decoder.nextUint256();
res[1] = decoder.nextUint256();
decoder还支持address和bytes之间的decode,具体可见
或者通过web3j的FunctionReturnDecoder进行decode
String rawData = this.call("getVotes", new Bytes32(Numeric.hexStringToByteArray(identifier))).sendAndGet();
List outputParameters = new ArrayList<TypeReference<Type>>();
outputParameters.add(new TypeReference<Uint256>() {});
outputParameters.add(new TypeReference<Uint256>() {});
List<Type> list = FunctionReturnDecoder.decode(rawData, outputParameters);
Day3 结构体decode响应
结构体的解析方法跟多个基本类型的第二种方法一致,不同的是需要自定义一个结构体类。 以下举个例子
struct price{
Uint256 base
Uint256 premium
}
public static class Price extends StaticStruct {
public BigInteger base;
public BigInteger premium;
public Price(Uint256 base, Uint256 premium) {
super(base,premium);
this.base = base.getValue();
this.premium = premium.getValue();
}
}
需要注意的是,由于该price结构体内部的成员均为Uint256,为定长类型,所以该结构体类继承的是StaticStruct。若其中包含不定长类型,则需要继承DynamicStruct
static void decodeStruct() {
String structData = "0x00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000008f03f1a3f10c05e7cccf75c1fd10168e06659be7000000000000000000000000000000000000000000000000000000000000000568656c6c6f000000000000000000000000000000000000000000000000000000";
TypeReference ts = new TypeReference<Price>() {};
List<Type> list = DefaultFunctionReturnDecoder.decode(structData, Arrays.asList(ts));
System.out.println(((Price)list.get(0)).base);
}
Day4 结构体参数调用问题反馈
Web3j对结构体中嵌套数组的类型支持有问题,当结构体中包含了DynamicArray
类型或是StaticArray
类型时,用以下语句去调用合约会报错
//struct BasicAddresses{
// address[] addr;
//}
String hash = account.call(opt, contract_address, "write", basicAddresses);
通过测试,我们发现,该问题主要是由MethodSignature
不同导致的,该signature的不同会导致methodid的不同,最后会导致encode产生的rawdata不用。
为了解决该问题,本教程提供了一个折衷的办法,大致的思路就是自己手动去生成一个methodid。由拼接思路可得,我们提供一个正确的methodid,再与其他的参数进行拼接,得到正确的rawdata。
具体的为重写web3j的DefaultFunctionEncoder.java中的encodeFunction:
@Override
public String encodeFunction(final Function function, String signature) {
String methodId = buildMethodId(signature);
final StringBuilder result = new StringBuilder(methodId);
return encodeParameters(parameters, result);
}
// methodSignature的格式如下:方法名(参数)。其中,参数类型为结构体的表示为(xxx)。如:writeBasicAddressesStruct((address[]))
public static String buildMethodId(final String methodSignature) {
final byte[] input = methodSignature.getBytes();
final byte[] hash = Hash.sha3(input);
return Numeric.toHexString(hash).substring(0, 10);
}
其中,Function可以由以下例子进行构造:
Function f = new Function(
"writeBasicAddressesStruct",
Arrays.asList(struct),
Collections.emptyList()
);
再得到rawdata后就可以通过以下例子进行调用:
String hash = acc.callWithData(new Address(addr), t);
Day5 web3j合约交互问题补充
因为web3j中存在的问题,目前web3j中的codegen会产生错误的代码以及用getlog的方式去获取日志会报 java.lang.UnsupportedOperationException: Array types must be wrapped in a TypeReference
的错误
具体的问题描述可以查看https://github.com/web3j/web3j/issues/1726
该问题也是源于对数组的支持不太好,需要等待web3j修复该bug
No Comments