From 275b3b59defbed73edb8bd3c080e19277e704712 Mon Sep 17 00:00:00 2001 From: kyonRay Date: Mon, 25 Dec 2023 17:48:10 +0800 Subject: [PATCH] (V3): adapt TransactionManager interface, add event subcribe feature, add getRawFunction feature. --- build.gradle | 2 +- .../org/fisco/bcos/codegen/CodeGenMain.java | 10 +- .../codegen/v3/wrapper/ContractGenerator.java | 16 +- .../codegen/v3/wrapper/ContractWrapper.java | 276 ++++++++++++++---- .../bcos/codegen/v3/test/CodeGenV3Test.java | 3 +- 5 files changed, 245 insertions(+), 62 deletions(-) diff --git a/build.gradle b/build.gradle index 07fd567..7e49b14 100644 --- a/build.gradle +++ b/build.gradle @@ -30,7 +30,7 @@ ext { junitVersion = '4.13.2' commonsLang3Version = '3.12.0' - javaSDKVersion3 = "3.3.0" + javaSDKVersion3 = "3.6.0-SNAPSHOT" javaSDKVersion2 = "2.9.1" slf4jVersion = "1.7.32" } diff --git a/src/main/java/org/fisco/bcos/codegen/CodeGenMain.java b/src/main/java/org/fisco/bcos/codegen/CodeGenMain.java index fc40ce4..df59062 100644 --- a/src/main/java/org/fisco/bcos/codegen/CodeGenMain.java +++ b/src/main/java/org/fisco/bcos/codegen/CodeGenMain.java @@ -104,9 +104,14 @@ static class PicocliRunner implements Runnable { @Option( names = {"-e", "--enableAsyncCall"}, - description = "enable async call.") + description = "enable async call, only V3 enable.") private boolean enableAsyncCall = false; + @Option( + names = {"-n", "--newTxManager"}, + description = "use new transaction manager interface, only V3 enable.") + private boolean useNewTransactionManager = false; + @Override public void run() { if (version.equals(Version.V2)) { @@ -125,7 +130,8 @@ public void run() { abiFile, destinationFileDir, packageName, - enableAsyncCall) + enableAsyncCall, + useNewTransactionManager) .generateJavaFiles(); } catch (Exception e) { org.fisco.bcos.codegen.v3.utils.CodeGenUtils.exitError(e); diff --git a/src/main/java/org/fisco/bcos/codegen/v3/wrapper/ContractGenerator.java b/src/main/java/org/fisco/bcos/codegen/v3/wrapper/ContractGenerator.java index d8ce5b8..b5cbc90 100644 --- a/src/main/java/org/fisco/bcos/codegen/v3/wrapper/ContractGenerator.java +++ b/src/main/java/org/fisco/bcos/codegen/v3/wrapper/ContractGenerator.java @@ -53,6 +53,7 @@ public class ContractGenerator { private String basePackageName; private boolean enableAsyncCall = false; + private boolean useNewTransactionManager = false; public ContractGenerator( File binFile, @@ -78,6 +79,18 @@ public ContractGenerator( this.enableAsyncCall = enableAsyncCall; } + public ContractGenerator( + File binFile, + File smBinFile, + File abiFile, + File destinationDir, + String basePackageName, + boolean enableAsyncCall, + boolean useNewTransactionManager) { + this(binFile, smBinFile, abiFile, destinationDir, basePackageName, enableAsyncCall); + this.useNewTransactionManager = useNewTransactionManager; + } + public void generateJavaFiles() throws CodeGenException, IOException, ClassNotFoundException { // get binary byte[] binary = CodeGenUtils.readBytes(this.binFile); @@ -103,7 +116,8 @@ public void generateJavaFiles() throws CodeGenException, IOException, ClassNotFo new String(abiBytes), destinationDir.toString(), basePackageName, - enableAsyncCall); + enableAsyncCall, + useNewTransactionManager); } private byte[] calculateWasmBytes(byte[] binary) throws IOException { diff --git a/src/main/java/org/fisco/bcos/codegen/v3/wrapper/ContractWrapper.java b/src/main/java/org/fisco/bcos/codegen/v3/wrapper/ContractWrapper.java index 94c6c2b..82b7c9b 100644 --- a/src/main/java/org/fisco/bcos/codegen/v3/wrapper/ContractWrapper.java +++ b/src/main/java/org/fisco/bcos/codegen/v3/wrapper/ContractWrapper.java @@ -52,6 +52,8 @@ import org.fisco.bcos.sdk.v3.model.TransactionReceipt; import org.fisco.bcos.sdk.v3.model.callback.CallCallback; import org.fisco.bcos.sdk.v3.model.callback.TransactionCallback; +import org.fisco.bcos.sdk.v3.transaction.manager.transactionv2.ProxySignTransactionManager; +import org.fisco.bcos.sdk.v3.transaction.manager.transactionv2.TransactionManager; import org.fisco.bcos.sdk.v3.transaction.model.exception.ContractException; import org.fisco.bcos.sdk.v3.utils.Collection; import org.fisco.bcos.sdk.v3.utils.StringUtils; @@ -87,6 +89,8 @@ public class ContractWrapper { private static final String FUNC_NAME_PREFIX = "FUNC_"; private static final String EVENT_ENCODER = "eventEncoder"; + private static final String TRANSACTION_MANAGER = "transactionManager"; + private static final String TUPLE_REGEX = "tuple\\.Tuple(\\d+)"; private static final Pattern TUPLE_PATTERN = Pattern.compile(TUPLE_REGEX); @@ -98,6 +102,7 @@ public class ContractWrapper { private static final List structsNamedTypeList = new ArrayList<>(); private boolean enableAsyncCall = false; + private boolean useNewTransactionManager = false; public ContractWrapper(boolean isWasm) { this.isWasm = isWasm; @@ -110,9 +115,11 @@ public void generateJavaFiles( String abi, String destinationDir, String basePackageName, - boolean enableAsyncCall) + boolean enableAsyncCall, + boolean useNewTransactionManager) throws IOException, ClassNotFoundException, UnsupportedOperationException { this.enableAsyncCall = enableAsyncCall; + this.useNewTransactionManager = useNewTransactionManager; String[] nameParts = contractName.split("_"); for (int i = 0; i < nameParts.length; ++i) { nameParts[i] = StringUtils.capitaliseFirstLetter(nameParts[i]); @@ -153,6 +160,9 @@ public void generateJavaFiles( .collect(Collectors.toList())); classBuilder.addMethods(this.buildFunctionDefinitions(classBuilder, abiDefinitions)); classBuilder.addMethod(buildLoad(className)); + if (useNewTransactionManager) { + classBuilder.addMethod(buildDefaultLoad(className)); + } classBuilder.addMethods(this.buildDeployMethods(isWasm, className, abiDefinitions)); this.write(basePackageName, classBuilder.build(), destinationDir); @@ -281,6 +291,8 @@ private List buildFunctionDefinitions( if (functionDefinition.getType().equals("function")) { MethodSpec ms = this.buildFunction(functionDefinition); methodSpecs.add(ms); + MethodSpec msRawFunction = buildRawFunctionReturn(functionDefinition); + methodSpecs.add(msRawFunction); if (functionDefinition.isConstant() && enableAsyncCall) { MethodSpec msCallback = this.buildFunctionWithCallback(functionDefinition); methodSpecs.add(msCallback); @@ -655,19 +667,36 @@ private static MethodSpec buildGetABIMethod() { return toReturn.build(); } - private static MethodSpec buildConstructor() { - MethodSpec.Builder toReturn = - MethodSpec.constructorBuilder() - .addModifiers(Modifier.PROTECTED) - .addParameter(String.class, CONTRACT_ADDRESS) - .addParameter(Client.class, CLIENT) - .addParameter(CryptoKeyPair.class, ContractWrapper.CREDENTIAL) - .addStatement( - "super($N, $N, $N, $N)", - getBinaryFuncDefinition(), - CONTRACT_ADDRESS, - CLIENT, - ContractWrapper.CREDENTIAL); + private MethodSpec buildConstructor() { + MethodSpec.Builder toReturn; + if (this.useNewTransactionManager) { + toReturn = + MethodSpec.constructorBuilder() + .addModifiers(Modifier.PROTECTED) + .addParameter(String.class, CONTRACT_ADDRESS) + .addParameter(Client.class, CLIENT) + .addParameter( + TransactionManager.class, ContractWrapper.TRANSACTION_MANAGER) + .addStatement( + "super($N, $N, $N, $N)", + getBinaryFuncDefinition(), + CONTRACT_ADDRESS, + CLIENT, + ContractWrapper.TRANSACTION_MANAGER); + } else { + toReturn = + MethodSpec.constructorBuilder() + .addModifiers(Modifier.PROTECTED) + .addParameter(String.class, CONTRACT_ADDRESS) + .addParameter(Client.class, CLIENT) + .addParameter(CryptoKeyPair.class, ContractWrapper.CREDENTIAL) + .addStatement( + "super($N, $N, $N, $N)", + getBinaryFuncDefinition(), + CONTRACT_ADDRESS, + CLIENT, + ContractWrapper.CREDENTIAL); + } return toReturn.build(); } @@ -684,43 +713,78 @@ private MethodSpec buildDeploy( } } - private static MethodSpec buildDeployWithParams( + private MethodSpec buildDeployWithParams( boolean isWasm, MethodSpec.Builder methodBuilder, String className, String inputParams) { - methodBuilder - .addStatement( - "byte[] encodedConstructor = $T.encodeConstructor(" - + "$T.<$T>asList($L)" - + ")", - isWasm - ? org.fisco.bcos.sdk.v3.codec.scale.FunctionEncoder.class - : org.fisco.bcos.sdk.v3.codec.abi.FunctionEncoder.class, - Arrays.class, - Type.class, - inputParams) - .addStatement( - "return deploy(" + "$L.class, $L, $L, $L, $L, encodedConstructor, $L)", - className, - CLIENT, - ContractWrapper.CREDENTIAL, - getBinaryFuncDefinition(), - getABIFuncDefinition(), - isWasm ? PATH : "null"); + methodBuilder.addStatement( + "byte[] encodedConstructor = $T.encodeConstructor(" + "$T.<$T>asList($L)" + ")", + isWasm + ? org.fisco.bcos.sdk.v3.codec.scale.FunctionEncoder.class + : org.fisco.bcos.sdk.v3.codec.abi.FunctionEncoder.class, + Arrays.class, + Type.class, + inputParams); + if (this.useNewTransactionManager) { + methodBuilder + .addStatement( + "$L contract = deploy(" + + "$L.class, $L, $L, $L, $L, encodedConstructor, $L)", + className, + className, + CLIENT, + ContractWrapper.CREDENTIAL, + getBinaryFuncDefinition(), + getABIFuncDefinition(), + isWasm ? PATH : "null") + .addStatement( + "contract.setTransactionManager(new $T($L))", + ProxySignTransactionManager.class, + CLIENT) + .addStatement("return contract"); + } else { + methodBuilder.addStatement( + "return deploy(" + "$L.class, $L, $L, $L, $L, encodedConstructor, $L)", + className, + CLIENT, + ContractWrapper.CREDENTIAL, + getBinaryFuncDefinition(), + getABIFuncDefinition(), + isWasm ? PATH : "null"); + } return methodBuilder.build(); } - private static MethodSpec buildDeployNoParams( + private MethodSpec buildDeployNoParams( boolean isWasm, MethodSpec.Builder methodBuilder, String className) { - methodBuilder.addStatement( - "return deploy($L.class, $L, $L, $L, $L, null, $L)", - className, - CLIENT, - ContractWrapper.CREDENTIAL, - getBinaryFuncDefinition(), - getABIFuncDefinition(), - isWasm ? PATH : "null"); + if (this.useNewTransactionManager) { + methodBuilder + .addStatement( + "$L contract = deploy($L.class, $L, $L, $L, $L, null, $L)", + className, + className, + CLIENT, + ContractWrapper.CREDENTIAL, + getBinaryFuncDefinition(), + getABIFuncDefinition(), + isWasm ? PATH : "null") + .addStatement( + "contract.setTransactionManager(new $T($L))", + ProxySignTransactionManager.class, + CLIENT) + .addStatement("return contract"); + } else { + + methodBuilder.addStatement( + "return deploy($L.class, $L, $L, $L, $L, null, $L)", + className, + CLIENT, + ContractWrapper.CREDENTIAL, + getBinaryFuncDefinition(), + getABIFuncDefinition(), + isWasm ? PATH : "null"); + } return methodBuilder.build(); } @@ -738,20 +802,54 @@ private static MethodSpec.Builder getDeployMethodSpec(boolean isWasm, String cla return methodSpec; } - private static MethodSpec buildLoad(String className) { + private MethodSpec buildLoad(String className) { + MethodSpec.Builder toReturn; + if (this.useNewTransactionManager) { + toReturn = + MethodSpec.methodBuilder("load") + .addModifiers(Modifier.PUBLIC, Modifier.STATIC) + .returns(TypeVariableName.get(className, Type.class)) + .addParameter(String.class, CONTRACT_ADDRESS) + .addParameter(Client.class, CLIENT) + .addParameter( + TransactionManager.class, ContractWrapper.TRANSACTION_MANAGER) + .addStatement( + "return new $L($L, $L, $L)", + className, + CONTRACT_ADDRESS, + CLIENT, + ContractWrapper.TRANSACTION_MANAGER); + } else { + toReturn = + MethodSpec.methodBuilder("load") + .addModifiers(Modifier.PUBLIC, Modifier.STATIC) + .returns(TypeVariableName.get(className, Type.class)) + .addParameter(String.class, CONTRACT_ADDRESS) + .addParameter(Client.class, CLIENT) + .addParameter(CryptoKeyPair.class, ContractWrapper.CREDENTIAL) + .addStatement( + "return new $L($L, $L, $L)", + className, + CONTRACT_ADDRESS, + CLIENT, + ContractWrapper.CREDENTIAL); + } + return toReturn.build(); + } + + private MethodSpec buildDefaultLoad(String className) { MethodSpec.Builder toReturn = MethodSpec.methodBuilder("load") .addModifiers(Modifier.PUBLIC, Modifier.STATIC) .returns(TypeVariableName.get(className, Type.class)) .addParameter(String.class, CONTRACT_ADDRESS) .addParameter(Client.class, CLIENT) - .addParameter(CryptoKeyPair.class, ContractWrapper.CREDENTIAL) .addStatement( "return new $L($L, $L, $L)", className, CONTRACT_ADDRESS, CLIENT, - ContractWrapper.CREDENTIAL); + "new ProxySignTransactionManager(" + CLIENT + ")"); return toReturn.build(); } @@ -1250,6 +1348,73 @@ private MethodSpec buildFunctionWithOutputDecoder( return methodBuilder.build(); } + private MethodSpec buildRawFunctionReturn(ABIDefinition functionDefinition) + throws ClassNotFoundException { + String functionName = functionDefinition.getName(); + + if (!SourceVersion.isName(functionName)) { + functionName = "_" + functionName; + } + + MethodSpec.Builder methodBuilder = + MethodSpec.methodBuilder( + "getMethod" + + org.apache.commons.lang3.StringUtils.capitalize( + functionName) + + "RawFunction") + .addModifiers(Modifier.PUBLIC); + + String inputParams = this.addParameters(methodBuilder, functionDefinition.getInputs()); + + List outputParameterTypes = buildTypeNames(functionDefinition.getOutputs()); + + methodBuilder.addException(ContractException.class); + if (outputParameterTypes.isEmpty()) { + methodBuilder.addStatement( + "throw new RuntimeException" + + "(\"cannot call constant function with void return type\")"); + } else if (outputParameterTypes.size() == 1) { + TypeName typeName = outputParameterTypes.get(0); + TypeName nativeReturnTypeName; + ABIDefinition.NamedType outputType = functionDefinition.getOutputs().get(0); + if (outputType.getType().equals("tuple")) { + nativeReturnTypeName = structClassNameMap.get(outputType.structIdentifier()); + } else if (outputType.getType().startsWith("tuple") + && outputType.getType().contains("[")) { + TypeName argument = + ((ParameterizedTypeName) buildStructArrayTypeName(outputType)) + .typeArguments.get(0); + nativeReturnTypeName = + ParameterizedTypeName.get( + ClassName.get(List.class), ClassName.get("", argument.toString())); + } else { + nativeReturnTypeName = this.getWrapperRawType(typeName); + } + + methodBuilder.returns(nativeReturnTypeName); + + methodBuilder.addStatement( + "final $T function = " + + "new $T($N, \n$T.<$T>asList($L), " + + "\n$T.<$T>asList(new $T<$T>() {}))", + Function.class, + Function.class, + funcNameToConst(functionName), + Arrays.class, + Type.class, + inputParams, + Arrays.class, + TypeReference.class, + TypeReference.class, + typeName); + CodeBlock.Builder callCode = CodeBlock.builder(); + callCode.addStatement("return function"); + + methodBuilder.returns(Function.class).addCode(callCode.build()); + } + return methodBuilder.build(); + } + private void buildConstantFunction( ABIDefinition functionDefinition, MethodSpec.Builder methodBuilder, @@ -1509,27 +1674,24 @@ private MethodSpec buildSubscribeEventFunction(String eventName) throws ClassNot MethodSpec.Builder getEventMethodBuilder = MethodSpec.methodBuilder(generatedFunctionName) .addModifiers(Modifier.PUBLIC) - .addParameter(String.class, FROM_BLOCK) - .addParameter(String.class, TO_BLOCK); + .addParameter(BigInteger.class, FROM_BLOCK) + .addParameter(BigInteger.class, TO_BLOCK); this.addParameter(getEventMethodBuilder, "string[]", OTHER_TOPICS); - // FIXME: implement event sub - // getEventMethodBuilder.addParameter(EventCallback.class, CALLBACK_VALUE); + getEventMethodBuilder.addParameter(EventSubCallback.class, CALLBACK_VALUE); getEventMethodBuilder.addStatement( "String topic0 = $N.encode(" + this.buildEventDefinitionName(eventName) + ")", EVENT_ENCODER); getEventMethodBuilder.addStatement( - "subscribeEvent(ABI,BINARY" + "subscribeEvent(topic0" + "," - + "topic0" + + OTHER_TOPICS + "," + FROM_BLOCK + "," + TO_BLOCK + "," - + OTHER_TOPICS - + "," + CALLBACK_VALUE + ")"); @@ -1549,8 +1711,7 @@ private MethodSpec buildDefaultSubscribeEventLog(String eventName) { "String topic0 = $N.encode(" + buildEventDefinitionName(eventName) + ")", EVENT_ENCODER); - getEventMethodBuilder.addStatement( - "subscribeEvent(ABI,BINARY" + ",topic0" + "," + CALLBACK_VALUE + ")"); + getEventMethodBuilder.addStatement("subscribeEvent(topic0" + "," + CALLBACK_VALUE + ")"); return getEventMethodBuilder.build(); } @@ -1658,7 +1819,8 @@ private List buildEventFunctions( methods.add( this.buildEventTransactionReceiptFunction( responseClassName, functionName, indexedParameters, nonIndexedParameters)); - + methods.add(buildSubscribeEventFunction(functionName)); + methods.add(buildDefaultSubscribeEventLog(functionName)); return methods; } diff --git a/src/test/java/org/fisco/bcos/codegen/v3/test/CodeGenV3Test.java b/src/test/java/org/fisco/bcos/codegen/v3/test/CodeGenV3Test.java index 9308638..cec4bc6 100644 --- a/src/test/java/org/fisco/bcos/codegen/v3/test/CodeGenV3Test.java +++ b/src/test/java/org/fisco/bcos/codegen/v3/test/CodeGenV3Test.java @@ -162,7 +162,8 @@ private void codeGenTest(String abiFileName, String codeFilePath, String contrac DEFAULT_PACKAGE, "-o", javaOutPut, - "-e") + "-e", + "-n") .toArray(new String[0])); JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); DiagnosticCollector collector = new DiagnosticCollector<>();