Skip to content

Commit 841b84c

Browse files
committed
Contract add structure type
1 parent bc06180 commit 841b84c

135 files changed

Lines changed: 3676 additions & 994 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
/*
2+
* Copyright 2019 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 com.peersafe.abi;
14+
15+
import java.math.BigInteger;
16+
import java.util.List;
17+
18+
import com.peersafe.abi.datatypes.DynamicStruct;
19+
import com.peersafe.abi.datatypes.Function;
20+
import com.peersafe.abi.datatypes.StaticArray;
21+
import com.peersafe.abi.datatypes.StaticStruct;
22+
import com.peersafe.abi.datatypes.Type;
23+
import com.peersafe.abi.datatypes.Uint;
24+
import static com.peersafe.abi.Utils.staticStructNestedPublicFieldsFlatList;
25+
26+
public class DefaultFunctionEncoder extends FunctionEncoder {
27+
28+
@Override
29+
public String encodeFunction(final Function function) {
30+
final List<Type> parameters = function.getInputParameters();
31+
32+
final String methodSignature = buildMethodSignature(function.getName(), parameters);
33+
final String methodId = buildMethodId(methodSignature);
34+
35+
final StringBuilder result = new StringBuilder();
36+
result.append(methodId);
37+
38+
return encodeParameters(parameters, result);
39+
}
40+
41+
@Override
42+
public String encodeParameters(final List<Type> parameters) {
43+
return encodeParameters(parameters, new StringBuilder());
44+
}
45+
46+
private static String encodeParameters(
47+
final List<Type> parameters, final StringBuilder result) {
48+
49+
int dynamicDataOffset = getLength(parameters) * Type.MAX_BYTE_LENGTH;
50+
final StringBuilder dynamicData = new StringBuilder();
51+
52+
for (Type parameter : parameters) {
53+
final String encodedValue = TypeEncoder.encode(parameter);
54+
55+
if (TypeEncoder.isDynamic(parameter)) {
56+
final String encodedDataOffset =
57+
TypeEncoder.encodeNumeric(new Uint(BigInteger.valueOf(dynamicDataOffset)));
58+
result.append(encodedDataOffset);
59+
dynamicData.append(encodedValue);
60+
dynamicDataOffset += encodedValue.length() >> 1;
61+
} else {
62+
result.append(encodedValue);
63+
}
64+
}
65+
result.append(dynamicData);
66+
67+
return result.toString();
68+
}
69+
70+
@SuppressWarnings("unchecked")
71+
private static int getLength(final List<Type> parameters) {
72+
int count = 0;
73+
for (final Type type : parameters) {
74+
if (type instanceof StaticArray
75+
&& StaticStruct.class.isAssignableFrom(
76+
((StaticArray) type).getComponentType())) {
77+
count +=
78+
staticStructNestedPublicFieldsFlatList(
79+
((StaticArray) type).getComponentType())
80+
.size()
81+
* ((StaticArray) type).getValue().size();
82+
} else if (type instanceof StaticArray
83+
&& DynamicStruct.class.isAssignableFrom(
84+
((StaticArray) type).getComponentType())) {
85+
count++;
86+
} else if (type instanceof StaticArray) {
87+
count += ((StaticArray) type).getValue().size();
88+
} else {
89+
count++;
90+
}
91+
}
92+
return count;
93+
}
94+
}
Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
/*
2+
* Copyright 2019 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 com.peersafe.abi;
14+
15+
import java.util.ArrayList;
16+
import java.util.Collections;
17+
import java.util.List;
18+
19+
import org.web3j.utils.Numeric;
20+
import org.web3j.utils.Strings;
21+
22+
import com.peersafe.abi.datatypes.Array;
23+
import com.peersafe.abi.datatypes.Bytes;
24+
import com.peersafe.abi.datatypes.BytesType;
25+
import com.peersafe.abi.datatypes.DynamicArray;
26+
import com.peersafe.abi.datatypes.DynamicBytes;
27+
import com.peersafe.abi.datatypes.DynamicStruct;
28+
import com.peersafe.abi.datatypes.StaticArray;
29+
import com.peersafe.abi.datatypes.StaticStruct;
30+
import com.peersafe.abi.datatypes.Type;
31+
import com.peersafe.abi.datatypes.Utf8String;
32+
import com.peersafe.abi.datatypes.generated.Bytes32;
33+
import static com.peersafe.abi.TypeDecoder.MAX_BYTE_LENGTH_FOR_HEX_STRING;
34+
import static com.peersafe.abi.TypeDecoder.isDynamic;
35+
import static com.peersafe.abi.Utils.getParameterizedTypeFromArray;
36+
import static com.peersafe.abi.Utils.staticStructNestedPublicFieldsFlatList;
37+
38+
39+
40+
/**
41+
* Ethereum Contract Application Binary Interface (ABI) encoding for functions. Further details are
42+
* available <a href="https://github.com/ethereum/wiki/wiki/Ethereum-Contract-ABI">here</a>.
43+
*/
44+
public class DefaultFunctionReturnDecoder extends FunctionReturnDecoder {
45+
46+
public List<Type> decodeFunctionResult(
47+
String rawInput, List<TypeReference<Type>> outputParameters) {
48+
49+
String input = Numeric.cleanHexPrefix(rawInput);
50+
51+
if (Strings.isEmpty(input)) {
52+
return Collections.emptyList();
53+
} else {
54+
return build(input, outputParameters);
55+
}
56+
}
57+
58+
@SuppressWarnings("unchecked")
59+
public <T extends Type> Type decodeEventParameter(
60+
String rawInput, TypeReference<T> typeReference) {
61+
62+
String input = Numeric.cleanHexPrefix(rawInput);
63+
64+
try {
65+
Class<T> type = typeReference.getClassType();
66+
67+
if (Bytes.class.isAssignableFrom(type)) {
68+
Class<Bytes> bytesClass = (Class<Bytes>) Class.forName(type.getName());
69+
return TypeDecoder.decodeBytes(input, bytesClass);
70+
} else if (Array.class.isAssignableFrom(type)
71+
|| BytesType.class.isAssignableFrom(type)
72+
|| Utf8String.class.isAssignableFrom(type)) {
73+
return TypeDecoder.decodeBytes(input, Bytes32.class);
74+
} else {
75+
return TypeDecoder.decode(input, type);
76+
}
77+
} catch (ClassNotFoundException e) {
78+
throw new UnsupportedOperationException("Invalid class reference provided", e);
79+
}
80+
}
81+
82+
private static List<Type> build(String input, List<TypeReference<Type>> outputParameters) {
83+
List<Type> results = new ArrayList<>(outputParameters.size());
84+
85+
int offset = 0;
86+
for (TypeReference<?> typeReference : outputParameters) {
87+
try {
88+
int hexStringDataOffset = getDataOffset(input, offset, typeReference);
89+
90+
@SuppressWarnings("unchecked")
91+
Class<Type> classType = (Class<Type>) typeReference.getClassType();
92+
93+
Type result;
94+
if (DynamicStruct.class.isAssignableFrom(classType)) {
95+
result =
96+
TypeDecoder.decodeDynamicStruct(
97+
input, hexStringDataOffset, typeReference);
98+
offset += MAX_BYTE_LENGTH_FOR_HEX_STRING;
99+
100+
} else if (DynamicArray.class.isAssignableFrom(classType)) {
101+
result =
102+
TypeDecoder.decodeDynamicArray(
103+
input, hexStringDataOffset, typeReference);
104+
offset += MAX_BYTE_LENGTH_FOR_HEX_STRING;
105+
106+
} else if (typeReference instanceof TypeReference.StaticArrayTypeReference) {
107+
int length = ((TypeReference.StaticArrayTypeReference) typeReference).getSize();
108+
result =
109+
TypeDecoder.decodeStaticArray(
110+
input, hexStringDataOffset, typeReference, length);
111+
offset += length * MAX_BYTE_LENGTH_FOR_HEX_STRING;
112+
113+
} else if (StaticStruct.class.isAssignableFrom(classType)) {
114+
result =
115+
TypeDecoder.decodeStaticStruct(
116+
input, hexStringDataOffset, typeReference);
117+
offset +=
118+
staticStructNestedPublicFieldsFlatList(classType).size()
119+
* MAX_BYTE_LENGTH_FOR_HEX_STRING;
120+
} else if (StaticArray.class.isAssignableFrom(classType)) {
121+
int length =
122+
Integer.parseInt(
123+
classType
124+
.getSimpleName()
125+
.substring(StaticArray.class.getSimpleName().length()));
126+
result =
127+
TypeDecoder.decodeStaticArray(
128+
input, hexStringDataOffset, typeReference, length);
129+
if (DynamicStruct.class.isAssignableFrom(
130+
getParameterizedTypeFromArray(typeReference))) {
131+
offset += MAX_BYTE_LENGTH_FOR_HEX_STRING;
132+
} else if (StaticStruct.class.isAssignableFrom(
133+
getParameterizedTypeFromArray(typeReference))) {
134+
offset +=
135+
staticStructNestedPublicFieldsFlatList(
136+
getParameterizedTypeFromArray(
137+
typeReference))
138+
.size()
139+
* length
140+
* MAX_BYTE_LENGTH_FOR_HEX_STRING;
141+
} else {
142+
offset += length * MAX_BYTE_LENGTH_FOR_HEX_STRING;
143+
}
144+
} else {
145+
result = TypeDecoder.decode(input, hexStringDataOffset, classType);
146+
offset += MAX_BYTE_LENGTH_FOR_HEX_STRING;
147+
}
148+
results.add(result);
149+
150+
} catch (ClassNotFoundException e) {
151+
throw new UnsupportedOperationException("Invalid class reference provided", e);
152+
}
153+
}
154+
return results;
155+
}
156+
157+
public static <T extends Type> int getDataOffset(
158+
String input, int offset, TypeReference<?> typeReference)
159+
throws ClassNotFoundException {
160+
@SuppressWarnings("unchecked")
161+
Class<Type> type = (Class<Type>) typeReference.getClassType();
162+
if (DynamicBytes.class.isAssignableFrom(type)
163+
|| Utf8String.class.isAssignableFrom(type)
164+
|| DynamicArray.class.isAssignableFrom(type)
165+
|| hasDynamicOffsetInStaticArray(typeReference, offset)) {
166+
return TypeDecoder.decodeUintAsInt(input, offset) << 1;
167+
} else {
168+
return offset;
169+
}
170+
}
171+
172+
/**
173+
* Checks if the parametrized type is offsetted in case of static array containing structs.
174+
*
175+
* @param typeReference of static array
176+
* @return true, if static array elements have dynamic offsets
177+
* @throws ClassNotFoundException if class type cannot be determined
178+
*/
179+
private static boolean hasDynamicOffsetInStaticArray(TypeReference<?> typeReference, int offset)
180+
throws ClassNotFoundException {
181+
@SuppressWarnings("unchecked")
182+
Class<Type> type = (Class<Type>) typeReference.getClassType();
183+
try {
184+
return StaticArray.class.isAssignableFrom(type)
185+
&& (DynamicStruct.class.isAssignableFrom(
186+
getParameterizedTypeFromArray(typeReference))
187+
|| isDynamic(getParameterizedTypeFromArray(typeReference)));
188+
} catch (ClassCastException e) {
189+
return false;
190+
}
191+
}
192+
}
Lines changed: 29 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
package com.peersafe.abi;
22

3-
import java.util.ArrayList;
43
import java.util.List;
54
import java.util.stream.Collectors;
65

76
import com.peersafe.abi.datatypes.Event;
87
import com.peersafe.abi.datatypes.Type;
8+
99
import org.web3j.crypto.Hash;
1010
import org.web3j.utils.Numeric;
1111

@@ -17,39 +17,32 @@
1717
*/
1818
public class EventEncoder {
1919

20-
private EventEncoder() { }
21-
22-
public static String encode(Event function) {
23-
List<TypeReference<Type>> indexedParameters = function.getIndexedParameters();
24-
List<TypeReference<Type>> nonIndexedParameters = function.getNonIndexedParameters();
25-
26-
String methodSignature = buildMethodSignature(function.getName(),
27-
indexedParameters, nonIndexedParameters);
28-
29-
return buildEventSignature(methodSignature);
30-
}
31-
32-
static <T extends Type> String buildMethodSignature(
33-
String methodName, List<TypeReference<T>> indexParameters,
34-
List<TypeReference<T>> nonIndexedParameters) {
35-
36-
List<TypeReference<T>> parameters = new ArrayList<>(indexParameters);
37-
parameters.addAll(nonIndexedParameters);
38-
39-
StringBuilder result = new StringBuilder();
40-
result.append(methodName);
41-
result.append("(");
42-
String params = parameters.stream()
43-
.map(p -> Utils.getTypeName(p))
44-
.collect(Collectors.joining(","));
45-
result.append(params);
46-
result.append(")");
47-
return result.toString();
48-
}
49-
50-
public static String buildEventSignature(String methodSignature) {
51-
byte[] input = methodSignature.getBytes();
52-
byte[] hash = Hash.sha3(input);
53-
return Numeric.toHexString(hash);
54-
}
20+
private EventEncoder() {}
21+
22+
public static String encode(Event event) {
23+
24+
String methodSignature = buildMethodSignature(event.getName(), event.getParameters());
25+
26+
return buildEventSignature(methodSignature);
27+
}
28+
29+
static <T extends Type> String buildMethodSignature(
30+
String methodName, List<TypeReference<T>> parameters) {
31+
32+
33+
StringBuilder result = new StringBuilder();
34+
result.append(methodName);
35+
result.append("(");
36+
String params =
37+
parameters.stream().map(p -> Utils.getTypeName(p)).collect(Collectors.joining(","));
38+
result.append(params);
39+
result.append(")");
40+
return result.toString();
41+
}
42+
43+
public static String buildEventSignature(String methodSignature) {
44+
byte[] input = methodSignature.getBytes();
45+
byte[] hash = Hash.sha3(input);
46+
return Numeric.toHexString(hash);
47+
}
5548
}

0 commit comments

Comments
 (0)