Skip to content

Commit

Permalink
Merge pull request #398 from argentlabs/dynamic_gas_for_contract
Browse files Browse the repository at this point in the history
Allow for dynamic gas prices and limits rather than using static values for all remote contract calls [READY]
  • Loading branch information
conor10 authored Apr 29, 2018
2 parents 744ce98 + 956f064 commit c932610
Show file tree
Hide file tree
Showing 17 changed files with 369 additions and 150 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
Expand Down Expand Up @@ -73,6 +75,7 @@ public class SolidityFunctionWrapper extends Generator {
private static final String START_BLOCK = "startBlock";
private static final String END_BLOCK = "endBlock";
private static final String WEI_VALUE = "weiValue";
private static final String FUNC_NAME_PREFIX = "FUNC_";

private static final ClassName LOG = ClassName.get(Log.class);
private static final Logger LOGGER = LoggerFactory.getLogger(SolidityFunctionWrapper.class);
Expand Down Expand Up @@ -121,6 +124,7 @@ void generateJavaFiles(
classBuilder.addMethod(buildConstructor(Credentials.class, CREDENTIALS));
classBuilder.addMethod(buildConstructor(TransactionManager.class,
TRANSACTION_MANAGER));
classBuilder.addFields(buildFuncNameConstants(abi));
classBuilder.addMethods(
buildFunctionDefinitions(className, classBuilder, abi));
classBuilder.addMethod(buildLoad(className, Credentials.class, CREDENTIALS));
Expand Down Expand Up @@ -247,7 +251,7 @@ private List<MethodSpec> buildFunctionDefinitions(
methodSpecs.add(buildFunction(functionDefinition));

} else if (functionDefinition.getType().equals("event")) {
buildEventFunctions(functionDefinition, classBuilder);
methodSpecs.addAll(buildEventFunctions(functionDefinition, classBuilder));

} else if (functionDefinition.getType().equals("constructor")) {
constructor = true;
Expand Down Expand Up @@ -276,6 +280,29 @@ private List<MethodSpec> buildFunctionDefinitions(
return methodSpecs;
}

Iterable<FieldSpec> buildFuncNameConstants(List<AbiDefinition> functionDefinitions) {
List<FieldSpec> fields = new ArrayList<>();
Set<String> fieldNames = new HashSet<>();
fieldNames.add(Contract.FUNC_DEPLOY);

for (AbiDefinition functionDefinition : functionDefinitions) {
if (functionDefinition.getType().equals("function")) {
String funcName = functionDefinition.getName();

if (!fieldNames.contains(funcName)) {
FieldSpec field = FieldSpec.builder(String.class,
funcNameToConst(funcName),
Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL)
.initializer("$S", funcName)
.build();
fields.add(field);
fieldNames.add(funcName);
}
}
}
return fields;
}

private static MethodSpec buildConstructor(Class authType, String authName) {
return MethodSpec.constructorBuilder()
.addModifiers(Modifier.PROTECTED)
Expand Down Expand Up @@ -599,9 +626,9 @@ private void buildConstantFunction(
methodBuilder.returns(buildRemoteCall(nativeReturnTypeName));

methodBuilder.addStatement("final $T function = "
+ "new $T($S, \n$T.<$T>asList($L), "
+ "new $T($N, \n$T.<$T>asList($L), "
+ "\n$T.<$T<?>>asList(new $T<$T>() {}))",
Function.class, Function.class, functionName,
Function.class, Function.class, funcNameToConst(functionName),
Arrays.class, Type.class, inputParams,
Arrays.class, TypeReference.class,
TypeReference.class, typeName);
Expand Down Expand Up @@ -690,9 +717,9 @@ private void buildTransactionFunction(

methodBuilder.returns(buildRemoteCall(TypeName.get(TransactionReceipt.class)));

methodBuilder.addStatement("final $T function = new $T(\n$S, \n$T.<$T>asList($L), \n$T"
methodBuilder.addStatement("final $T function = new $T(\n$N, \n$T.<$T>asList($L), \n$T"
+ ".<$T<?>>emptyList())",
Function.class, Function.class, functionName,
Function.class, Function.class, funcNameToConst(functionName),
Arrays.class, Type.class, inputParams, Collections.class,
TypeReference.class);
if (functionDefinition.isPayable()) {
Expand Down Expand Up @@ -837,10 +864,9 @@ MethodSpec buildEventTransactionReceiptFunction(
return transactionMethodBuilder.build();
}

void buildEventFunctions(
List<MethodSpec> buildEventFunctions(
AbiDefinition functionDefinition,
TypeSpec.Builder classBuilder) throws ClassNotFoundException {

String functionName = functionDefinition.getName();
List<AbiDefinition.NamedType> inputs = functionDefinition.getInputs();
String responseClassName = Strings.capitaliseFirstLetter(functionName) + "EventResponse";
Expand Down Expand Up @@ -869,14 +895,15 @@ void buildEventFunctions(
classBuilder.addType(buildEventResponseObject(responseClassName, indexedParameters,
nonIndexedParameters));

classBuilder.addMethod(buildEventTransactionReceiptFunction(responseClassName,
List<MethodSpec> methods = new ArrayList<>();
methods.add(buildEventTransactionReceiptFunction(responseClassName,
functionName, indexedParameters, nonIndexedParameters));

classBuilder.addMethod(buildEventObservableFunction(responseClassName, functionName,
methods.add(buildEventObservableFunction(responseClassName, functionName,
indexedParameters, nonIndexedParameters));

classBuilder.addMethod(buildDefaultEventObservableFunction(responseClassName,
methods.add(buildDefaultEventObservableFunction(responseClassName,
functionName));
return methods;
}

CodeBlock buildTypedResponse(
Expand Down Expand Up @@ -985,7 +1012,7 @@ private static void buildVariableLengthReturnFunctionConstructor(
List<Object> objects = new ArrayList<>();
objects.add(Function.class);
objects.add(Function.class);
objects.add(functionName);
objects.add(funcNameToConst(functionName));

objects.add(Arrays.class);
objects.add(Type.class);
Expand All @@ -1003,7 +1030,7 @@ private static void buildVariableLengthReturnFunctionConstructor(
", ",
typeName -> "new $T<$T>() {}");

methodBuilder.addStatement("final $T function = new $T($S, \n$T.<$T>asList($L), \n$T"
methodBuilder.addStatement("final $T function = new $T($N, \n$T.<$T>asList($L), \n$T"
+ ".<$T<?>>asList("
+ asListParams + "))", objects.toArray());
}
Expand Down Expand Up @@ -1120,6 +1147,10 @@ private List<AbiDefinition> loadContractDefinition(String abi) throws IOExceptio
return Arrays.asList(abiDefinition);
}

private static String funcNameToConst(String funcName) {
return FUNC_NAME_PREFIX + funcName.toUpperCase();
}

private static class NamedTypeName {
private final TypeName typeName;
private final String name;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ public void testGreeterGeneration() throws Exception {
}

@Test
public void testContractsGeneration() throws Exception {
public void testHumanStandardTokenGeneration() throws Exception {
testCodeGenerationJvmTypes("contracts", "HumanStandardToken");
testCodeGenerationSolidityTypes("contracts", "HumanStandardToken");
}
Expand Down Expand Up @@ -123,7 +123,10 @@ private void verifyGeneratedCode(String sourceFile) throws IOException {
.getJavaFileObjectsFromStrings(Arrays.asList(sourceFile));
JavaCompiler.CompilationTask task = compiler.getTask(
null, fileManager, diagnostics, null, null, compilationUnits);
assertTrue("Generated contract contains compile time error", task.call());
boolean result = task.call();

System.out.println(diagnostics.getDiagnostics());
assertTrue("Generated contract contains compile time error", result);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ public void testBuildFunctionTransaction() throws Exception {
String expected =
"public org.web3j.protocol.core.RemoteCall<org.web3j.protocol.core.methods.response.TransactionReceipt> functionName(java.math.BigInteger param) {\n"
+ " final org.web3j.abi.datatypes.Function function = new org.web3j.abi.datatypes.Function(\n"
+ " \"functionName\", \n"
+ " FUNC_FUNCTIONNAME, \n"
+ " java.util.Arrays.<org.web3j.abi.datatypes.Type>asList(new org.web3j.abi.datatypes.generated.Uint8(param)), \n"
+ " java.util.Collections.<org.web3j.abi.TypeReference<?>>emptyList());\n"
+ " return executeRemoteCallTransaction(function);\n"
Expand Down Expand Up @@ -211,7 +211,7 @@ public void testBuildPayableFunctionTransaction() throws Exception {
String expected =
"public org.web3j.protocol.core.RemoteCall<org.web3j.protocol.core.methods.response.TransactionReceipt> functionName(java.math.BigInteger param, java.math.BigInteger weiValue) {\n"
+ " final org.web3j.abi.datatypes.Function function = new org.web3j.abi.datatypes.Function(\n"
+ " \"functionName\", \n"
+ " FUNC_FUNCTIONNAME, \n"
+ " java.util.Arrays.<org.web3j.abi.datatypes.Type>asList(new org.web3j.abi.datatypes.generated.Uint8(param)), \n"
+ " java.util.Collections.<org.web3j.abi.TypeReference<?>>emptyList());\n"
+ " return executeRemoteCallTransaction(function, weiValue);\n"
Expand All @@ -238,7 +238,7 @@ public void testBuildFunctionConstantSingleValueReturn() throws Exception {
//CHECKSTYLE:OFF
String expected =
"public org.web3j.protocol.core.RemoteCall<java.math.BigInteger> functionName(java.math.BigInteger param) {\n"
+ " final org.web3j.abi.datatypes.Function function = new org.web3j.abi.datatypes.Function(\"functionName\", \n"
+ " final org.web3j.abi.datatypes.Function function = new org.web3j.abi.datatypes.Function(FUNC_FUNCTIONNAME, \n"
+ " java.util.Arrays.<org.web3j.abi.datatypes.Type>asList(new org.web3j.abi.datatypes.generated.Uint8(param)), \n"
+ " java.util.Arrays.<org.web3j.abi.TypeReference<?>>asList(new org.web3j.abi.TypeReference<org.web3j.abi.datatypes.generated.Int8>() {}));\n"
+ " return executeRemoteCallSingleValueReturn(function, java.math.BigInteger.class);\n"
Expand All @@ -265,7 +265,7 @@ public void testBuildFunctionConstantSingleValueRawListReturn() throws Exception
//CHECKSTYLE:OFF
String expected =
"public org.web3j.protocol.core.RemoteCall<java.util.List> functionName(java.math.BigInteger param) {\n"
+ " final org.web3j.abi.datatypes.Function function = new org.web3j.abi.datatypes.Function(\"functionName\", \n"
+ " final org.web3j.abi.datatypes.Function function = new org.web3j.abi.datatypes.Function(FUNC_FUNCTIONNAME, \n"
+ " java.util.Arrays.<org.web3j.abi.datatypes.Type>asList(new org.web3j.abi.datatypes.generated.Uint8(param)), \n"
+ " java.util.Arrays.<org.web3j.abi.TypeReference<?>>asList(new org.web3j.abi.TypeReference<org.web3j.abi.datatypes.DynamicArray<org.web3j.abi.datatypes.Address>>() {}));\n"
+ " return new org.web3j.protocol.core.RemoteCall<java.util.List>(\n"
Expand Down Expand Up @@ -316,7 +316,7 @@ public void testBuildFunctionConstantMultipleValueReturn() throws Exception {

//CHECKSTYLE:OFF
String expected = "public org.web3j.protocol.core.RemoteCall<org.web3j.tuples.generated.Tuple2<java.math.BigInteger, java.math.BigInteger>> functionName(java.math.BigInteger param1, java.math.BigInteger param2) {\n"
+ " final org.web3j.abi.datatypes.Function function = new org.web3j.abi.datatypes.Function(\"functionName\", \n"
+ " final org.web3j.abi.datatypes.Function function = new org.web3j.abi.datatypes.Function(FUNC_FUNCTIONNAME, \n"
+ " java.util.Arrays.<org.web3j.abi.datatypes.Type>asList(new org.web3j.abi.datatypes.generated.Uint8(param1), \n"
+ " new org.web3j.abi.datatypes.generated.Uint32(param2)), \n"
+ " java.util.Arrays.<org.web3j.abi.TypeReference<?>>asList(new org.web3j.abi.TypeReference<org.web3j.abi.datatypes.generated.Int8>() {}, new org.web3j.abi.TypeReference<org.web3j.abi.datatypes.generated.Int32>() {}));\n"
Expand Down Expand Up @@ -356,7 +356,8 @@ public void testBuildEventConstantMultipleValueReturn() throws Exception {
false);
TypeSpec.Builder builder = TypeSpec.classBuilder("testClass");

solidityFunctionWrapper.buildEventFunctions(functionDefinition, builder);
builder.addMethods(
solidityFunctionWrapper.buildEventFunctions(functionDefinition, builder));

//CHECKSTYLE:OFF
String expected =
Expand Down Expand Up @@ -422,4 +423,31 @@ public void testBuildEventConstantMultipleValueReturn() throws Exception {
assertThat(builder.build().toString(), is(expected));
}

@Test
public void testBuildFuncNameConstants() throws Exception {
AbiDefinition functionDefinition = new AbiDefinition(
false,
Arrays.asList(
new AbiDefinition.NamedType("param", "uint8")),
"functionName",
Collections.emptyList(),
"function",
true);
TypeSpec.Builder builder = TypeSpec.classBuilder("testClass");

builder.addFields(solidityFunctionWrapper
.buildFuncNameConstants(Collections.singletonList(functionDefinition)));


//CHECKSTYLE:OFF
String expected =
"class testClass {\n" +
" public static final java.lang.String FUNC_FUNCTIONNAME = \"functionName\";\n" +
"}\n";
//CHECKSTYLE:ON


assertThat(builder.build().toString(), is(expected));
}

}
5 changes: 3 additions & 2 deletions core/src/main/java/org/web3j/ens/EnsResolver.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import org.web3j.tx.ClientTransactionManager;
import org.web3j.tx.ManagedTransaction;
import org.web3j.tx.TransactionManager;
import org.web3j.tx.gas.DefaultGasProvider;
import org.web3j.utils.Numeric;

/**
Expand Down Expand Up @@ -122,14 +123,14 @@ PublicResolver lookupResolver(String ensName) throws Exception {

ENS ensRegistry = ENS.load(
registryContract, web3j, transactionManager,
ManagedTransaction.GAS_PRICE, org.web3j.tx.Contract.GAS_LIMIT);
DefaultGasProvider.GAS_PRICE, DefaultGasProvider.GAS_LIMIT);

byte[] nameHash = NameHash.nameHashAsBytes(ensName);

String resolverAddress = ensRegistry.resolver(nameHash).send();
PublicResolver resolver = PublicResolver.load(
resolverAddress, web3j, transactionManager,
ManagedTransaction.GAS_PRICE, org.web3j.tx.Contract.GAS_LIMIT);
DefaultGasProvider.GAS_PRICE, DefaultGasProvider.GAS_LIMIT);

return resolver;
}
Expand Down
Loading

1 comment on commit c932610

@Arvindkumar3
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you please provide code sample to get dynamic gas price in contract

Please sign in to comment.