我们需要监听某个事件 需要根据event 的topic[0] 来筛选。所以当我们要去监听一个 日志时就需要知道topic[0]的值
List logs = web3j.ethGetLogs(new EthFilter(DefaultBlockParameter.valueOf(new BigInteger(start.toString())), DefaultBlockParameter.valueOf(new BigInteger(end.toString()))
, contract).addOptionalTopics(transferTopic)).send().getLogs();
然后这个topic[0] 可以使用
List> parameters = new ArrayList<>();
parameters.add(new TypeReference(true) {
});
parameters.add(new TypeReference(true) {
});
Event event = new Event("name", parameters);
topic[0] = EventEncoder.encode(event);
正常情况都是正常的 但是当日志里面有一个我们自己定义的结构体 就发现不对了
public static String encode(Event event) {
String methodSignature = buildMethodSignature(event.getName(), event.getParameters());
return buildEventSignature(methodSignature);
}
static String buildMethodSignature(
String methodName, List> parameters) {
StringBuilder result = new StringBuilder();
result.append(methodName);
result.append("(");
String params =
parameters.stream().map(p -> Utils.getTypeName(p)).collect(Collectors.joining(","));
result.append(params);
result.append(")");
return result.toString();
}
public static String buildEventSignature(String methodSignature) {
byte[] input = methodSignature.getBytes();
byte[] hash = Hash.sha3(input);
return Numeric.toHexString(hash);
}
看上面代码发现 以event Transfer(address indexed from, address indexed to,uint256 indexed id ); 其实这个topic[0] = keccak256("Transfer(address, address,uint256)") 如果有自己定义的机构体怎么表示?
如果我们用 EventEncoder.encode(event) 方法 ; Utils.getTypeName(p) 它会找到我们再代码里面定义的类名 然后拼接去 keccak256,这是不对的 。
因为 event的topic[0] 和方法签名有点类似 就去看看方法签名时怎么处理的 (DefaultFunctionEncoder)
public String encodeFunction(final Function function) {
final List parameters = function.getInputParameters();
final String methodSignature = buildMethodSignature(function.getName(), parameters);
final String methodId = buildMethodId(methodSignature);
final StringBuilder result = new StringBuilder();
result.append(methodId);
return encodeParameters(parameters, result);
}
protected static String buildMethodSignature(
final String methodName, final List parameters) {
final StringBuilder result = new StringBuilder();
result.append(methodName);
result.append("(");
final String params =
parameters.stream().map(Type::getTypeAsString).collect(Collectors.joining(","));
result.append(params);
result.append(")");
return result.toString();
}
这里拿的是 Type::getTypeAsString 方法
struct NFT {
address collection;
uint256 tokenId;
}
那 NFT 的getTypeAsString 的结果就是 (address,uint256) 如果是 NFT [] 那就是 (address,uint256)[] 如果是结构体套结构体就是一次递归。
event Name(address user,NFT[] nfts);
那么 Name 的 topic[0] 就是 keccak256("Name(address,(address,uint256)[])");
其实文档有写 但是写的不太明白 我没有看懂!