Web3j 继承StaticStruct的类所有属性必须为Public <DynamicArray<StaticStruct>>

news/2024/7/21 12:11:35 标签: web3

Web3j 继承StaticStruct的类所有属性必须为Public,属性的顺序和数量必须和solidity 里面的struct 属性相同,否则属性少了或者多了的时候会出现错位

Web3j 继承StaticStruct的类所有属性不能为private,因为web3j 是通过长度去截取返回值解析成对应的属性进行赋值的。要获取一个list对象时,web3j是按一个类的所有public属性个数去截取总长度的,再进行解析赋值到没一个属性里

StaticStruct类

import lombok.Data;
import org.web3j.abi.datatypes.Address;
import org.web3j.abi.datatypes.StaticStruct;
import org.web3j.abi.datatypes.Type;
import org.web3j.abi.datatypes.generated.Uint256;

@Data
public class ChildStaticStruct extends StaticStruct {

    public Uint256 attr1;
    public Uint256 attr2;
    public Address attr3;

    public ChildStaticStruct(Uint256 attr1, Uint256 attr2, Address attr3) {
         super(new Type[]{attr1,attr2,attr3});
    }
}
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.web3j.abi.FunctionEncoder;
import org.web3j.abi.FunctionReturnDecoder;
import org.web3j.abi.TypeReference;
import org.web3j.abi.datatypes.Address;
import org.web3j.abi.datatypes.DynamicArray;
import org.web3j.abi.datatypes.Function;
import org.web3j.abi.datatypes.Type;
import org.web3j.protocol.Web3j;
import org.web3j.protocol.core.DefaultBlockParameterName;
import org.web3j.protocol.core.methods.request.Transaction;
import org.web3j.protocol.core.methods.response.EthCall;

import java.io.IOException;
import java.util.Arrays;
import java.util.List;

public class TestContract {
    private static final Logger logger = LoggerFactory.getLogger(TestContract.class);
    private String address;
    private Web3j web3j;
    public TestContract(String address, Web3j web3j) {
        this.address = address;
        this.web3j = web3j;
    }

    public List<ChildStaticStruct> getStaticStructList(String address) throws IOException {
        List<Type> inputParameters = Arrays.asList( new Address(address));
        List<TypeReference<?>> outputParameters = Arrays.asList(new TypeReference<DynamicArray<ChildStaticStruct>>(){});
        Function function = new Function("getStaticStructList",inputParameters,outputParameters);
        Transaction transaction = Transaction.createEthCallTransaction(null,address, FunctionEncoder.encode(function));
        EthCall response = web3j.ethCall(transaction, DefaultBlockParameterName.LATEST).send();
        List<Type> output = FunctionReturnDecoder.decode(response.getValue(),function.getOutputParameters());
        List<ChildStaticStruct> results = (List<ChildStaticStruct>)output.get(0).getValue();
        return results;
    }
}

web3j的TypeDecoder 里的decodeArrayElements 验证了是否为StructType子类,

在currOffset += getSingleElementLength(input, currOffset, cls) * 64)判断了截取的长度

if (StructType.class.isAssignableFrom(cls)) {
                elements = new ArrayList(length);
                currOffset = 0;

                for(currOffset = offset; currOffset < length; currOffset += getSingleElementLength(input, currOffset, cls) * 64) {
                    if (DynamicStruct.class.isAssignableFrom(cls)) {
                        value = decodeDynamicStruct(input, offset + DefaultFunctionReturnDecoder.getDataOffset(input, currOffset, typeReference), TypeReference.create(cls));
                    } else {
                        value = decodeStaticStruct(input, currOffset, TypeReference.create(cls));
                    }

                    elements.add(value);
                    ++currOffset;
                }

                String typeName = Utils.getSimpleTypeName(cls);
                return (Type)consumer.apply(elements, typeName);
            } 

getSingleElementLength 验证了截取长度是根据public属性数量去截取Utils.staticStructNestedPublicFieldsFlatList(type).size(),pirvate计算长度

static <T extends Type> int getSingleElementLength(String input, int offset, Class<T> type) {
        if (input.length() == offset) {
            return 0;
        } else if (!DynamicBytes.class.isAssignableFrom(type) && !Utf8String.class.isAssignableFrom(type)) {
            return StaticStruct.class.isAssignableFrom(type) ? Utils.staticStructNestedPublicFieldsFlatList(type).size() : 1;
        } else {
            return decodeUintAsInt(input, offset) / 32 + 2;
        }
    }

 staticStructNestedPublicFieldsFlatList方面里面通过Modifier.isPublic(field.getModifiers())过滤了public  

public static List<Field> staticStructNestedPublicFieldsFlatList(Class<Type> classType) {
        return (List)staticStructsNestedFieldsFlatList(classType).stream().filter((field) -> {
            return Modifier.isPublic(field.getModifiers());
        }).collect(Collectors.toList());
    }

Modifier 里面比较了Public

public static boolean isPublic(int mod) {
        return (mod & PUBLIC) != 0;
    }


http://www.niftyadmin.cn/n/5004925.html

相关文章

为何一黄金代理资格难求

由于新冠疫情导致了供应链的问题&#xff0c;美国的通胀水平不断刷写40年来的新高&#xff0c;加上乌克兰与俄罗斯的地缘危机暂时没有得到全面的解决&#xff0c;黄金成为了对冲基金最受欢迎的避险资产&#xff0c;其价格走势一直受到支撑。 现货现黄金是贵金属市场上最为成熟的…

Verilog 代码规范

搬自https://hitsz-cslab.gitee.io/cpu/home/codingstyle/ 1. 标题命名规范 1.1 标题文件命名规范 仿真文件应使用后缀“_sim”&#xff0c;如modulename_sim&#xff1b; 测试文件应使用后缀“_tb”&#xff0c;如modulename_tb。 1.2 模块命名规范 一个文件只定义一个m…

Java面试题:线程的run()和start()有什么区别?

线程的 run() 方法和 start() 方法是 Java 多线程中的两个重 要方法。 1. run() 方法是线程的执行体&#xff0c;线程启动后会执行 run() 方法中的代码&#xff0c;当 run() 方法执行完毕后&#xff0c;线程便终止了。 2. start() 方法用于启动一个新线程&#xff0c;它会…

Vue + Element UI 前端篇(一):搭建开发环境

Vue Element UI 实现权限管理系统 前端篇&#xff08;一&#xff09;&#xff1a;搭建开发环境 技术基础 开发之前&#xff0c;请先熟悉下面的4个文档 vue.js2.0中文, 优秀的JS框架vue-router, vue.js 配套路由vuex&#xff0c;vue.js 应用状态管理库Element&#xff0c;饿…

VIRTIO-BLK代码分析(3)数据流处理

VIRTIO-BLK整个过程数据流如下所示&#xff1a; IO请求发送过程 虚拟机中通过FIO等下发IO请求&#xff0c;IO请求通过VFS/filesystem&#xff0c;然后到BLOCK层&#xff0c;传递给virtio-blk驱动&#xff0c;virtio-blk驱动通过virtio_queue_rq()下发IO请求&#xff0c;并通过v…

【linux命令讲解大全】046.whereis 命令的使用方法与功能解析

文章目录 whereis补充说明语法选项参数实例 从零学 python whereis 查找二进制程序、代码等相关文件路径 补充说明 whereis 命令用来定位指令的二进制程序、源代码文件和 man 手册页等相关文件的路径。 whereis 命令只能用于程序名的搜索&#xff0c;而且只搜索二进制文件&…

目前无法建立VS2013与Qt的连接???

因为下载组件的时候&#xff0c;没有哪个选项&#xff0c;还是没有MSVC2013

程序与进程

一、程序是怎么被执行的 1.在程序中&#xff0c;由引导代码去调用程序中得main函数&#xff0c;而这个过程由链接器完成&#xff0c;链接器将引导代码链接到我们的应用程序构成可执行文件。 2.程序运行需要通过操作系统的加载器来实现&#xff0c;加载器是操作系统中的程序&a…