Skip to content

Commit 13015e5

Browse files
authored
Merge pull request #1988 from tonykwok1992/link-binary
Add function to link binary with reference libraries in wrappers contract deployment
2 parents a1f47f9 + c495a39 commit 13015e5

16 files changed

+427
-62
lines changed

codegen/src/main/java/org/web3j/codegen/SolidityFunctionWrapper.java

+71-25
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@
9090
public class SolidityFunctionWrapper extends Generator {
9191

9292
private static final String BINARY = "BINARY";
93+
private static final String LIBRARIES_LINKED_BINARY = "librariesLinkedBinary";
9394
private static final String WEB3J = "web3j";
9495
private static final String CREDENTIALS = "credentials";
9596
private static final String CONTRACT_GAS_PROVIDER = "contractGasProvider";
@@ -262,6 +263,8 @@ public void generateJavaFiles(
262263
buildLoad(className, TransactionManager.class, TRANSACTION_MANAGER, true));
263264
if (!bin.equals(Contract.BIN_NOT_PROVIDED)) {
264265
classBuilder.addMethods(buildDeployMethods(className, classBuilder, abi));
266+
classBuilder.addMethod(buildLinkLibraryMethod());
267+
classBuilder.addMethod(buildGetDeploymentBinaryMethod());
265268
}
266269

267270
addAddressesSupport(classBuilder, addresses);
@@ -360,11 +363,17 @@ private TypeSpec.Builder createClassBuilder(
360363

361364
String javadoc = CODEGEN_WARNING + getWeb3jVersion();
362365

363-
return TypeSpec.classBuilder(className)
364-
.addModifiers(Modifier.PUBLIC)
365-
.addJavadoc(javadoc)
366-
.superclass(contractClass)
367-
.addField(createBinaryDefinition(binary));
366+
TypeSpec.Builder classBuilder =
367+
TypeSpec.classBuilder(className)
368+
.addModifiers(Modifier.PUBLIC)
369+
.addJavadoc(javadoc)
370+
.superclass(contractClass)
371+
.addField(createBinaryDefinition(binary));
372+
373+
if (!binary.equals(Contract.BIN_NOT_PROVIDED)) {
374+
classBuilder.addField(createLibrariesLinkedBinaryField());
375+
}
376+
return classBuilder;
368377
}
369378

370379
private String getWeb3jVersion() {
@@ -380,6 +389,12 @@ private String getWeb3jVersion() {
380389
return "\n<p>Generated with web3j version " + version + ".\n";
381390
}
382391

392+
private FieldSpec createLibrariesLinkedBinaryField() {
393+
return FieldSpec.builder(String.class, LIBRARIES_LINKED_BINARY)
394+
.addModifiers(Modifier.PRIVATE, Modifier.STATIC)
395+
.build();
396+
}
397+
383398
private FieldSpec createBinaryDefinition(String binary) {
384399
if (binary.length() < 65534) {
385400
return FieldSpec.builder(String.class, BINARY)
@@ -653,6 +668,26 @@ private Set<String> getDuplicateFunctionNames(List<AbiDefinition> functionDefini
653668
return duplicateNames;
654669
}
655670

671+
private static MethodSpec buildGetDeploymentBinaryMethod() {
672+
MethodSpec.Builder toReturn =
673+
MethodSpec.methodBuilder("getDeploymentBinary")
674+
.addModifiers(Modifier.PRIVATE, Modifier.STATIC)
675+
.returns(ClassName.get(String.class));
676+
677+
CodeBlock codeBlock =
678+
CodeBlock.builder()
679+
.beginControlFlow("if ($L != null)", LIBRARIES_LINKED_BINARY)
680+
.addStatement("return $L", LIBRARIES_LINKED_BINARY)
681+
.nextControlFlow("else")
682+
.addStatement("return $L", BINARY)
683+
.endControlFlow()
684+
.build();
685+
686+
toReturn.addCode(codeBlock);
687+
688+
return toReturn.build();
689+
}
690+
656691
List<MethodSpec> buildDeployMethods(
657692
String className,
658693
TypeSpec.Builder classBuilder,
@@ -849,43 +884,39 @@ private static MethodSpec buildDeployWithParams(
849884
if (isPayable && !withGasProvider) {
850885
methodBuilder.addStatement(
851886
"return deployRemoteCall("
852-
+ "$L.class, $L, $L, $L, $L, $L, encodedConstructor, $L)",
887+
+ "$L.class, $L, $L, $L, $L, getDeploymentBinary(), encodedConstructor, $L)",
853888
className,
854889
WEB3J,
855890
authName,
856891
GAS_PRICE,
857892
GAS_LIMIT,
858-
BINARY,
859893
INITIAL_VALUE);
860894
methodBuilder.addAnnotation(Deprecated.class);
861895
} else if (isPayable && withGasProvider) {
862896
methodBuilder.addStatement(
863897
"return deployRemoteCall("
864-
+ "$L.class, $L, $L, $L, $L, encodedConstructor, $L)",
898+
+ "$L.class, $L, $L, $L, getDeploymentBinary(), encodedConstructor, $L)",
865899
className,
866900
WEB3J,
867901
authName,
868902
CONTRACT_GAS_PROVIDER,
869-
BINARY,
870903
INITIAL_VALUE);
871904
} else if (!isPayable && !withGasProvider) {
872905
methodBuilder.addStatement(
873-
"return deployRemoteCall($L.class, $L, $L, $L, $L, $L, encodedConstructor)",
906+
"return deployRemoteCall($L.class, $L, $L, $L, $L, getDeploymentBinary(), encodedConstructor)",
874907
className,
875908
WEB3J,
876909
authName,
877910
GAS_PRICE,
878-
GAS_LIMIT,
879-
BINARY);
911+
GAS_LIMIT);
880912
methodBuilder.addAnnotation(Deprecated.class);
881913
} else {
882914
methodBuilder.addStatement(
883-
"return deployRemoteCall($L.class, $L, $L, $L, $L, encodedConstructor)",
915+
"return deployRemoteCall($L.class, $L, $L, $L, getDeploymentBinary(), encodedConstructor)",
884916
className,
885917
WEB3J,
886918
authName,
887-
CONTRACT_GAS_PROVIDER,
888-
BINARY);
919+
CONTRACT_GAS_PROVIDER);
889920
}
890921

891922
return methodBuilder.build();
@@ -899,42 +930,38 @@ private static MethodSpec buildDeployNoParams(
899930
boolean withGasProvider) {
900931
if (isPayable && !withGasProvider) {
901932
methodBuilder.addStatement(
902-
"return deployRemoteCall($L.class, $L, $L, $L, $L, $L, \"\", $L)",
933+
"return deployRemoteCall($L.class, $L, $L, $L, $L, getDeploymentBinary(), \"\", $L)",
903934
className,
904935
WEB3J,
905936
authName,
906937
GAS_PRICE,
907938
GAS_LIMIT,
908-
BINARY,
909939
INITIAL_VALUE);
910940
methodBuilder.addAnnotation(Deprecated.class);
911941
} else if (isPayable && withGasProvider) {
912942
methodBuilder.addStatement(
913-
"return deployRemoteCall($L.class, $L, $L, $L, $L, \"\", $L)",
943+
"return deployRemoteCall($L.class, $L, $L, $L, getDeploymentBinary(), \"\", $L)",
914944
className,
915945
WEB3J,
916946
authName,
917947
CONTRACT_GAS_PROVIDER,
918-
BINARY,
919948
INITIAL_VALUE);
920949
} else if (!isPayable && !withGasProvider) {
921950
methodBuilder.addStatement(
922-
"return deployRemoteCall($L.class, $L, $L, $L, $L, $L, \"\")",
951+
"return deployRemoteCall($L.class, $L, $L, $L, $L, getDeploymentBinary(), \"\")",
923952
className,
924953
WEB3J,
925954
authName,
926955
GAS_PRICE,
927-
GAS_LIMIT,
928-
BINARY);
956+
GAS_LIMIT);
929957
methodBuilder.addAnnotation(Deprecated.class);
930958
} else {
931959
methodBuilder.addStatement(
932-
"return deployRemoteCall($L.class, $L, $L, $L, $L, \"\")",
960+
"return deployRemoteCall($L.class, $L, $L, $L, getDeploymentBinary(), \"\")",
933961
className,
934962
WEB3J,
935963
authName,
936-
CONTRACT_GAS_PROVIDER,
937-
BINARY);
964+
CONTRACT_GAS_PROVIDER);
938965
}
939966

940967
return methodBuilder.build();
@@ -1456,6 +1483,25 @@ List<MethodSpec> buildFunctions(
14561483
return results;
14571484
}
14581485

1486+
MethodSpec buildLinkLibraryMethod() {
1487+
MethodSpec.Builder methodBuilder =
1488+
MethodSpec.methodBuilder("linkLibraries")
1489+
.addModifiers(Modifier.PUBLIC, Modifier.STATIC)
1490+
.addParameter(
1491+
ParameterizedTypeName.get(
1492+
ClassName.get(List.class),
1493+
ClassName.get(Contract.LinkReference.class)),
1494+
"references")
1495+
.addStatement(
1496+
LIBRARIES_LINKED_BINARY
1497+
+ " = "
1498+
+ "linkBinaryWithReferences("
1499+
+ BINARY
1500+
+ ", references)");
1501+
1502+
return methodBuilder.build();
1503+
}
1504+
14591505
private void buildConstantFunction(
14601506
AbiDefinition functionDefinition,
14611507
MethodSpec.Builder methodBuilder,

codegen/src/main/java/org/web3j/codegen/unit/gen/MethodFilter.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,8 @@ public static List<Method> extractValidMethods(Class contract) {
3737
&& parametersAreMatching(m)
3838
&& !m.getName().toLowerCase().contains("event")
3939
&& !m.getName().equals("load")
40-
&& !m.getName().equals("kill"))
40+
&& !m.getName().equals("kill")
41+
&& !m.getName().equals("linkLibraries"))
4142
.collect(Collectors.toList());
4243
}
4344

codegen/src/test/java/org/web3j/codegen/ContractJsonParseTest.java

+23
Original file line numberDiff line numberDiff line change
@@ -14,17 +14,20 @@
1414

1515
import java.io.File;
1616
import java.net.URL;
17+
import java.util.Collections;
1718

1819
import org.junit.jupiter.api.BeforeEach;
1920
import org.junit.jupiter.api.Test;
2021

22+
import org.web3j.abi.datatypes.Address;
2123
import org.web3j.protocol.core.methods.response.AbiDefinition;
2224

2325
import static org.junit.jupiter.api.Assertions.assertEquals;
2426
import static org.junit.jupiter.api.Assertions.assertFalse;
2527
import static org.junit.jupiter.api.Assertions.assertTrue;
2628
import static org.web3j.codegen.TruffleJsonFunctionWrapperGenerator.Contract;
2729
import static org.web3j.codegen.TruffleJsonFunctionWrapperGenerator.loadContractDefinition;
30+
import static org.web3j.tx.Contract.linkBinaryWithReferences;
2831

2932
/** Test that we can parse Truffle Contract from JSON file. */
3033
public class ContractJsonParseTest {
@@ -80,4 +83,24 @@ public void testParseConvertLib() throws Exception {
8083
abi.getStateMutability(),
8184
"Expected the 'pure' for the state mutability setting");
8285
}
86+
87+
@Test
88+
public void testLinkBinaryWithReferences() throws Exception {
89+
Contract mc = parseContractJson(contractBaseDir, "MetaCoin", "MetaCoin");
90+
assertTrue(mc.getBytecode().contains("__ConvertLib____________________________"));
91+
92+
String linked =
93+
linkBinaryWithReferences(
94+
mc.getBytecode(),
95+
Collections.singletonList(
96+
new org.web3j.tx.Contract.LinkReference(
97+
"./ConvertLib.sol", "ConvertLib", Address.DEFAULT)));
98+
assertFalse(linked.contains("__ConvertLib____________________________"));
99+
assertEquals(
100+
mc.getBytecode()
101+
.replace(
102+
"__ConvertLib____________________________",
103+
Address.DEFAULT.toString().substring(2)),
104+
linked);
105+
}
83106
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/*
2+
* Copyright 2024 Web3 Labs Ltd.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
5+
* the License. You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
10+
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
11+
* specific language governing permissions and limitations under the License.
12+
*/
13+
package org.web3j.codegen;
14+
15+
import java.io.IOException;
16+
import java.util.Collections;
17+
import javax.tools.*;
18+
19+
import static org.junit.jupiter.api.Assertions.assertTrue;
20+
21+
public class GeneraterTestUtils {
22+
23+
public static void verifyGeneratedCode(String sourceFile) throws IOException {
24+
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
25+
DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<>();
26+
27+
try (StandardJavaFileManager fileManager =
28+
compiler.getStandardFileManager(diagnostics, null, null)) {
29+
Iterable<? extends JavaFileObject> compilationUnits =
30+
fileManager.getJavaFileObjectsFromStrings(
31+
Collections.singletonList(sourceFile));
32+
JavaCompiler.CompilationTask task =
33+
compiler.getTask(null, fileManager, diagnostics, null, null, compilationUnits);
34+
assertTrue(task.call(), "Generated contract contains compile time error");
35+
}
36+
}
37+
}

codegen/src/test/java/org/web3j/codegen/SolidityFunctionWrapperGeneratorTest.java

+12-5
Original file line numberDiff line numberDiff line change
@@ -143,12 +143,12 @@ public void testStructOnlyInArray() throws Exception {
143143

144144
@Test
145145
public void testStructOnlyInArrayCompareJavaFile() throws Exception {
146-
compareJavaFile("OnlyInArrayStruct");
146+
compareJavaFile("OnlyInArrayStruct", false);
147147
}
148148

149149
@Test
150150
public void testArraysInStructCompareJavaFileTest() throws Exception {
151-
compareJavaFile("ArraysInStruct");
151+
compareJavaFile("ArraysInStruct", false);
152152
}
153153

154154
@Test
@@ -199,14 +199,19 @@ public void testEventParametersNoNamed() throws Exception {
199199

200200
@Test
201201
public void testEventParametersNoNamedCompareJavaFile() throws Exception {
202-
compareJavaFile("EventParameters");
202+
compareJavaFile("EventParameters", false);
203203
}
204204

205-
private void compareJavaFile(String inputFileName) throws Exception {
205+
@Test
206+
public void testDeployMethodGenerated() throws Exception {
207+
compareJavaFile("MetaCoin", true);
208+
}
209+
210+
private void compareJavaFile(String inputFileName, boolean useBin) throws Exception {
206211
String contract = inputFileName.toLowerCase();
207212
String packagePath =
208213
generateCode(
209-
emptyList(), contract, inputFileName, JAVA_TYPES_ARG, false, false, false);
214+
emptyList(), contract, inputFileName, JAVA_TYPES_ARG, useBin, false, false);
210215
File fileActual = new File(tempDirPath, packagePath + "/" + inputFileName + ".java");
211216
File fileExpected =
212217
new File(
@@ -221,6 +226,8 @@ private void compareJavaFile(String inputFileName) throws Exception {
221226
assertEquals(
222227
new String(Files.readAllBytes(fileExpected.toPath())).replaceAll("(\r\n|\n)", ""),
223228
new String(Files.readAllBytes(fileActual.toPath())).replaceAll("(\r\n|\n)", ""));
229+
230+
verifyGeneratedCode(fileActual.getAbsolutePath());
224231
}
225232

226233
private void testCodeGenerationJvmTypes(String contractName, String inputFileName)

codegen/src/test/java/org/web3j/codegen/SolidityFunctionWrapperTest.java

+12
Original file line numberDiff line numberDiff line change
@@ -971,4 +971,16 @@ public void testBuildFunctionConstantSingleValueReturnAndTransaction() throws Ex
971971
assertEquals(expectedCall, methodSpecs.get(0).toString());
972972
assertEquals(expectedSend, methodSpecs.get(1).toString());
973973
}
974+
975+
@Test
976+
public void testBuildFunctionLinkBinaryWithReferences() throws Exception {
977+
MethodSpec methodSpec = solidityFunctionWrapper.buildLinkLibraryMethod();
978+
979+
String expected =
980+
"public static void linkLibraries(java.util.List<org.web3j.tx.Contract.LinkReference> references) {\n"
981+
+ " librariesLinkedBinary = linkBinaryWithReferences(BINARY, references);\n"
982+
+ "}\n";
983+
984+
assertEquals(methodSpec.toString(), (expected));
985+
}
974986
}

0 commit comments

Comments
 (0)