java-sdk icon indicating copy to clipboard operation
java-sdk copied to clipboard

DynamicArray构建的empty数组,调用智能合约时,触发内部调用的getTypeAsString报错NullPointerException

Open AndyLvVip opened this issue 11 months ago • 3 comments

sdk版本:2.10.2-SNAPSHOT

通过DynamicArray.empty方法构建的空数组,调用智能合约时,触发内部调用的getTypeAsString报错NullPointerException

Image

Image

Image

原因初步分析:

通过empty方法构建的空数组,只初始化了type字段,而没有初始化typeClass,作者设计的empty方法只接收跟初始化type的意图应该是希望用户在构建空数组时,自己定义type,所以空数组时getTypeAsString()应该是直接返回用户定义的type,而不是通过typeClass来动态生成?

AndyLvVip avatar Feb 21 '25 08:02 AndyLvVip

能否提供一下调用时的合约函数参数以及入参?

kyonRay avatar Feb 25 '25 07:02 kyonRay

能否提供一下调用时的合约函数参数以及入参?

以下为测试重现的一些素材 智能合约: TestContract.sol

//SPDX-License-Identifier: GPL-3.0

pragma solidity >=0.6.0 <0.9.0;
pragma experimental ABIEncoderV2;

struct TestStruct {
    string text;
    string[] values;   
}

contract TestContract {
    
    function store(TestStruct memory test) public returns (uint256) {
        return test.values.length;
    }
    
}

智能合约对应java的contract文件 TestContract.java

import java.math.BigInteger;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import org.fisco.bcos.sdk.abi.FunctionReturnDecoder;
import org.fisco.bcos.sdk.abi.TypeReference;
import org.fisco.bcos.sdk.abi.datatypes.DynamicArray;
import org.fisco.bcos.sdk.abi.datatypes.DynamicStruct;
import org.fisco.bcos.sdk.abi.datatypes.Function;
import org.fisco.bcos.sdk.abi.datatypes.Type;
import org.fisco.bcos.sdk.abi.datatypes.Utf8String;
import org.fisco.bcos.sdk.abi.datatypes.generated.Uint256;
import org.fisco.bcos.sdk.abi.datatypes.generated.tuples.generated.Tuple1;
import org.fisco.bcos.sdk.client.Client;
import org.fisco.bcos.sdk.contract.Contract;
import org.fisco.bcos.sdk.crypto.CryptoSuite;
import org.fisco.bcos.sdk.crypto.keypair.CryptoKeyPair;
import org.fisco.bcos.sdk.model.CryptoType;
import org.fisco.bcos.sdk.model.TransactionReceipt;
import org.fisco.bcos.sdk.model.callback.TransactionCallback;
import org.fisco.bcos.sdk.transaction.model.exception.ContractException;

@SuppressWarnings("unchecked")
public class TestContract extends Contract {
    public static final String[] BINARY_ARRAY = {"608060405234801561001057600080fd5b506102ee806100206000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c80634c7d33a514610030575b600080fd5b61004a600480360381019061004591906101b3565b610060565b6040516100579190610203565b60405180910390f35b60008160200151519050919050565b600082601f83011261008057600080fd5b813561009361008e8261024b565b61021e565b9150818183526020840193506020810190508360005b838110156100d957813586016100bf88826100e3565b8452602084019350602083019250506001810190506100a9565b5050505092915050565b600082601f8301126100f457600080fd5b813561010761010282610273565b61021e565b9150808252602083016020830185838301111561012357600080fd5b61012e8382846102a9565b50505092915050565b60006040828403121561014957600080fd5b610153604061021e565b9050600082013567ffffffffffffffff81111561016f57600080fd5b61017b848285016100e3565b600083015250602082013567ffffffffffffffff81111561019b57600080fd5b6101a78482850161006f565b60208301525092915050565b6000602082840312156101c557600080fd5b600082013567ffffffffffffffff8111156101df57600080fd5b6101eb84828501610137565b91505092915050565b6101fd8161029f565b82525050565b600060208201905061021860008301846101f4565b92915050565b6000604051905081810181811067ffffffffffffffff8211171561024157600080fd5b8060405250919050565b600067ffffffffffffffff82111561026257600080fd5b602082029050602081019050919050565b600067ffffffffffffffff82111561028a57600080fd5b601f19601f8301169050602081019050919050565b6000819050919050565b8281833760008383015250505056fea2646970667358221220dfe29f3658fa934d4cdd57f0d6325a5a418b5b510faa9fed101a0fca0f34455e64736f6c634300060a0033"};

    public static final String BINARY = org.fisco.bcos.sdk.utils.StringUtils.joinAll("", BINARY_ARRAY);

    public static final String[] SM_BINARY_ARRAY = {"608060405234801561001057600080fd5b506102ee806100206000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c806392bac43614610030575b600080fd5b61004a600480360381019061004591906101b3565b610060565b6040516100579190610203565b60405180910390f35b60008160200151519050919050565b600082601f83011261008057600080fd5b813561009361008e8261024b565b61021e565b9150818183526020840193506020810190508360005b838110156100d957813586016100bf88826100e3565b8452602084019350602083019250506001810190506100a9565b5050505092915050565b600082601f8301126100f457600080fd5b813561010761010282610273565b61021e565b9150808252602083016020830185838301111561012357600080fd5b61012e8382846102a9565b50505092915050565b60006040828403121561014957600080fd5b610153604061021e565b9050600082013567ffffffffffffffff81111561016f57600080fd5b61017b848285016100e3565b600083015250602082013567ffffffffffffffff81111561019b57600080fd5b6101a78482850161006f565b60208301525092915050565b6000602082840312156101c557600080fd5b600082013567ffffffffffffffff8111156101df57600080fd5b6101eb84828501610137565b91505092915050565b6101fd8161029f565b82525050565b600060208201905061021860008301846101f4565b92915050565b6000604051905081810181811067ffffffffffffffff8211171561024157600080fd5b8060405250919050565b600067ffffffffffffffff82111561026257600080fd5b602082029050602081019050919050565b600067ffffffffffffffff82111561028a57600080fd5b601f19601f8301169050602081019050919050565b6000819050919050565b8281833760008383015250505056fea2646970667358221220ecb47a01b2a3561f2126a0b86bac118c202c890e9d65c3783b8dfc1447fbb52964736f6c634300060a0033"};

    public static final String SM_BINARY = org.fisco.bcos.sdk.utils.StringUtils.joinAll("", SM_BINARY_ARRAY);

    public static final String[] ABI_ARRAY = {"[{\"inputs\":[{\"components\":[{\"internalType\":\"string\",\"name\":\"text\",\"type\":\"string\"},{\"internalType\":\"string[]\",\"name\":\"values\",\"type\":\"string[]\"}],\"internalType\":\"struct TestStruct\",\"name\":\"test\",\"type\":\"tuple\"}],\"name\":\"store\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]"};

    public static final String ABI = org.fisco.bcos.sdk.utils.StringUtils.joinAll("", ABI_ARRAY);

    public static final String FUNC_STORE = "store";

    protected TestContract(String contractAddress, Client client, CryptoKeyPair credential) {
        super(getBinary(client.getCryptoSuite()), contractAddress, client, credential);
    }

    public static String getBinary(CryptoSuite cryptoSuite) {
        return (cryptoSuite.getCryptoTypeConfig() == CryptoType.ECDSA_TYPE ? BINARY : SM_BINARY);
    }

    public TransactionReceipt store(TestStruct test) {
        final Function function = new Function(
                FUNC_STORE, 
                Arrays.<Type>asList(test), 
                Collections.<TypeReference<?>>emptyList());
        return executeTransaction(function);
    }

    public byte[] store(TestStruct test, TransactionCallback callback) {
        final Function function = new Function(
                FUNC_STORE, 
                Arrays.<Type>asList(test), 
                Collections.<TypeReference<?>>emptyList());
        return asyncExecuteTransaction(function, callback);
    }

    public String getSignedTransactionForStore(TestStruct test) {
        final Function function = new Function(
                FUNC_STORE, 
                Arrays.<Type>asList(test), 
                Collections.<TypeReference<?>>emptyList());
        return createSignedTransaction(function);
    }

    public Tuple1<TestStruct> getStoreInput(TransactionReceipt transactionReceipt) {
        String data = transactionReceipt.getInput().substring(10);
        final Function function = new Function(FUNC_STORE, 
                Arrays.<Type>asList(), 
                Arrays.<TypeReference<?>>asList(new TypeReference<TestStruct>() {}));
        List<Type> results = FunctionReturnDecoder.decode(data, function.getOutputParameters());
        return new Tuple1<TestStruct>(

                (TestStruct) results.get(0)
                );
    }

    public Tuple1<BigInteger> getStoreOutput(TransactionReceipt transactionReceipt) {
        String data = transactionReceipt.getOutput();
        final Function function = new Function(FUNC_STORE, 
                Arrays.<Type>asList(), 
                Arrays.<TypeReference<?>>asList(new TypeReference<Uint256>() {}));
        List<Type> results = FunctionReturnDecoder.decode(data, function.getOutputParameters());
        return new Tuple1<BigInteger>(

                (BigInteger) results.get(0).getValue()
                );
    }

    public static TestContract load(String contractAddress, Client client, CryptoKeyPair credential) {
        return new TestContract(contractAddress, client, credential);
    }

    public static TestContract deploy(Client client, CryptoKeyPair credential) throws ContractException {
        return deploy(TestContract.class, client, credential, getBinary(client.getCryptoSuite()), "");
    }

    public static class TestStruct extends DynamicStruct {
        public String text;

        public List<String> values;

        public TestStruct(Utf8String text, DynamicArray<Utf8String> values) {
            super(text,values);
            this.text = text.getValue();
            this.values = values.getNativeValue();
        }

        public TestStruct(String text, List<String> values) {
            super(new org.fisco.bcos.sdk.abi.datatypes.Utf8String(text),new org.fisco.bcos.sdk.abi.datatypes.DynamicArray<org.fisco.bcos.sdk.abi.datatypes.Utf8String>(values.stream().map(obj -> new org.fisco.bcos.sdk.abi.datatypes.Utf8String(obj)).collect(java.util.stream.Collectors.toList())));
            this.text = text;
            this.values = values;
        }
    }
}

java UT的方法:

@Test
    public void store() {
        String hexPrivateKey = ""; //替换为密钥
        Client client = clientService.newClient(fiscoConfig.getGroupId(), hexPrivateKey);
        TestContract contract = TestContract.load(
                "0x....." //替换为智能合约的地址
                , client
                , client.getCryptoSuite().getCryptoKeyPair()
        );
        
        TestStruct struct = new TestStruct(new Utf8String(""), DynamicArray.empty("string[]"));
        contract.store(struct);
        System.out.println("--------------------");
        System.out.println(struct.getTypeAsString());
        System.out.println("--------------------");
    }

报错的堆栈信息如下:

java.lang.NullPointerException
 at java.base/java.lang.Class.isAssignableFrom(Native Method)
 at org.fisco.bcos.sdk.abi.datatypes.DynamicArray.getTypeAsString([DynamicArray.java:59](vscode-file://vscode-app/d:/Programs/Microsoft%20VS%20Code/resources/app/out/vs/code/electron-sandbox/workbench/workbench.html))
 at org.fisco.bcos.sdk.abi.datatypes.DynamicStruct.getTypeAsString([DynamicStruct.java:43](vscode-file://vscode-app/d:/Programs/Microsoft%20VS%20Code/resources/app/out/vs/code/electron-sandbox/workbench/workbench.html))
 at java.base/java.util.stream.ReferencePipeline$3$1.accept([ReferencePipeline.java:197](vscode-file://vscode-app/d:/Programs/Microsoft%20VS%20Code/resources/app/out/vs/code/electron-sandbox/workbench/workbench.html))
 at java.base/java.util.Spliterators$ArraySpliterator.forEachRemaining([Spliterators.java:1024](vscode-file://vscode-app/d:/Programs/Microsoft%20VS%20Code/resources/app/out/vs/code/electron-sandbox/workbench/workbench.html))
 at java.base/java.util.stream.AbstractPipeline.copyInto([AbstractPipeline.java:509](vscode-file://vscode-app/d:/Programs/Microsoft%20VS%20Code/resources/app/out/vs/code/electron-sandbox/workbench/workbench.html))
 at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto([AbstractPipeline.java:499](vscode-file://vscode-app/d:/Programs/Microsoft%20VS%20Code/resources/app/out/vs/code/electron-sandbox/workbench/workbench.html))
 at java.base/java.util.stream.ReduceOps$ReduceOp.evaluateSequential([ReduceOps.java:921](vscode-file://vscode-app/d:/Programs/Microsoft%20VS%20Code/resources/app/out/vs/code/electron-sandbox/workbench/workbench.html))
 at java.base/java.util.stream.AbstractPipeline.evaluate([AbstractPipeline.java:234](vscode-file://vscode-app/d:/Programs/Microsoft%20VS%20Code/resources/app/out/vs/code/electron-sandbox/workbench/workbench.html))
 at java.base/java.util.stream.ReferencePipeline.collect([ReferencePipeline.java:682](vscode-file://vscode-app/d:/Programs/Microsoft%20VS%20Code/resources/app/out/vs/code/electron-sandbox/workbench/workbench.html))
 at org.fisco.bcos.sdk.abi.FunctionEncoder.buildMethodSignature([FunctionEncoder.java:67](vscode-file://vscode-app/d:/Programs/Microsoft%20VS%20Code/resources/app/out/vs/code/electron-sandbox/workbench/workbench.html))
 at org.fisco.bcos.sdk.abi.FunctionEncoder.encode([FunctionEncoder.java:27](vscode-file://vscode-app/d:/Programs/Microsoft%20VS%20Code/resources/app/out/vs/code/electron-sandbox/workbench/workbench.html))
 at org.fisco.bcos.sdk.contract.Contract.executeTransaction([Contract.java:288](vscode-file://vscode-app/d:/Programs/Microsoft%20VS%20Code/resources/app/out/vs/code/electron-sandbox/workbench/workbench.html))
 at fx.blockchain.contracts.TestContract.store([TestContract.java:54](vscode-file://vscode-app/d:/Programs/Microsoft%20VS%20Code/resources/app/out/vs/code/electron-sandbox/workbench/workbench.html))
 at fx.blockchain.contract.TestContractTest.store([TestContractTest.java:41](vscode-file://vscode-app/d:/Programs/Microsoft%20VS%20Code/resources/app/out/vs/code/electron-sandbox/workbench/workbench.html))
 at java.base/java.util.ArrayList.forEach([ArrayList.java:1596](vscode-file://vscode-app/d:/Programs/Microsoft%20VS%20Code/resources/app/out/vs/code/electron-sandbox/workbench/workbench.html))
 at java.base/java.util.ArrayList.forEach([ArrayList.java:1596](vscode-file://vscode-app/d:/Programs/Microsoft%20VS%20Code/resources/app/out/vs/code/electron-sandbox/workbench/workbench.html))

AndyLvVip avatar Feb 26 '25 10:02 AndyLvVip

非常感谢提供样例,我们会在下个版本尽快修复这个问题。

kyonRay avatar Feb 27 '25 02:02 kyonRay