Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Release 22.7.7 #4545

Merged
merged 8 commits into from
Oct 19, 2022
Prev Previous commit
Next Next commit
Make GraphQL scalar parsing compatible with variables (#4522)
Our current GraphQL scalar parsing interacts poorly with the variables
support in the library.  Revise the parsing so it works correctly.

Signed-off-by: Danno Ferrin <danno.ferrin@gmail.com>
  • Loading branch information
shemnon authored and fab-10 committed Oct 19, 2022
commit 694fd1e4bf0de575b885ca7a5795406a2b0de434
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
package org.hyperledger.besu.ethereum.api.graphql.internal;

import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.Quantity;

import graphql.language.IntValue;
Expand All @@ -28,156 +27,239 @@
import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.bytes.Bytes32;
import org.apache.tuweni.units.bigints.UInt256;
import org.apache.tuweni.units.bigints.UInt256Value;

public class Scalars {

private static final Coercing<Object, Object> ADDRESS_COERCING =
new Coercing<Object, Object>() {
private Scalars() {}

private static final Coercing<Address, String> ADDRESS_COERCING =
new Coercing<Address, String>() {
Address convertImpl(final Object input) {
if (input instanceof Address) {
return (Address) input;
} else if (input instanceof Bytes) {
if (((Bytes) input).size() <= 20) {
return Address.wrap((Bytes) input);
} else {
return null;
}
} else if (input instanceof StringValue) {
return convertImpl(((StringValue) input).getValue());
} else if (input instanceof String) {
try {
return Address.fromHexStringStrict((String) input);
} catch (IllegalArgumentException iae) {
return null;
}
} else {
return null;
}
}

@Override
public String serialize(final Object input) throws CoercingSerializeException {
if (input instanceof Address) {
return input.toString();
Address result = convertImpl(input);
if (result != null) {
return result.toHexString();
} else {
throw new CoercingSerializeException("Unable to serialize " + input + " as an Address");
}
throw new CoercingSerializeException("Unable to serialize " + input + " as an Address");
}

@Override
public String parseValue(final Object input) throws CoercingParseValueException {
if (input instanceof Address) {
return input.toString();
public Address parseValue(final Object input) throws CoercingParseValueException {
Address result = convertImpl(input);
if (result != null) {
return result;
} else {
throw new CoercingParseValueException(
"Unable to parse variable value " + input + " as an Address");
}
throw new CoercingParseValueException(
"Unable to parse variable value " + input + " as an Address");
}

@Override
public Address parseLiteral(final Object input) throws CoercingParseLiteralException {
if (!(input instanceof StringValue)) {
throw new CoercingParseLiteralException("Value is not any Address : '" + input + "'");
}
String inputValue = ((StringValue) input).getValue();
try {
return Address.fromHexStringStrict(inputValue);
} catch (final IllegalArgumentException e) {
Address result = convertImpl(input);
if (result != null) {
return result;
} else {
throw new CoercingParseLiteralException("Value is not any Address : '" + input + "'");
}
}
};

private static final Coercing<Object, Object> BIG_INT_COERCING =
new Coercing<Object, Object>() {
private static final Coercing<String, String> BIG_INT_COERCING =
new Coercing<String, String>() {

String convertImpl(final Object input) {
if (input instanceof String) {
try {
return Bytes.fromHexStringLenient((String) input).toShortHexString();
} catch (IllegalArgumentException iae) {
return null;
}
} else if (input instanceof Bytes) {
return ((Bytes) input).toShortHexString();
} else if (input instanceof StringValue) {
return convertImpl(((StringValue) input).getValue());
} else if (input instanceof IntValue) {
return UInt256.valueOf(((IntValue) input).getValue()).toShortHexString();
} else {
return null;
}
}

@Override
public String serialize(final Object input) throws CoercingSerializeException {
if (input instanceof UInt256Value) {
return ((UInt256Value) input).toShortHexString();
var result = convertImpl(input);
if (result != null) {
return result;
} else {
throw new CoercingSerializeException("Unable to serialize " + input + " as an BigInt");
}
throw new CoercingSerializeException("Unable to serialize " + input + " as an BigInt");
}

@Override
public String parseValue(final Object input) throws CoercingParseValueException {
if (input instanceof UInt256Value) {
return ((UInt256Value) input).toShortHexString();
var result = convertImpl(input);
if (result != null) {
return result;
} else {
throw new CoercingParseValueException(
"Unable to parse variable value " + input + " as an BigInt");
}
throw new CoercingParseValueException(
"Unable to parse variable value " + input + " as an BigInt");
}

@Override
public UInt256 parseLiteral(final Object input) throws CoercingParseLiteralException {
try {
if (input instanceof StringValue) {
return UInt256.fromHexString(((StringValue) input).getValue());
} else if (input instanceof IntValue) {
return UInt256.valueOf(((IntValue) input).getValue());
}
} catch (final IllegalArgumentException e) {
// fall through
public String parseLiteral(final Object input) throws CoercingParseLiteralException {
var result = convertImpl(input);
if (result != null) {
return result;
} else {
throw new CoercingParseLiteralException("Value is not any BigInt : '" + input + "'");
}
throw new CoercingParseLiteralException("Value is not any BigInt : '" + input + "'");
}
};

private static final Coercing<Object, Object> BYTES_COERCING =
new Coercing<Object, Object>() {
private static final Coercing<Bytes, String> BYTES_COERCING =
new Coercing<Bytes, String>() {

Bytes convertImpl(final Object input) {
if (input instanceof Bytes) {
return (Bytes) input;
} else if (input instanceof StringValue) {
return convertImpl(((StringValue) input).getValue());
} else if (input instanceof String) {
if (!Quantity.isValid((String) input)) {
throw new CoercingParseLiteralException(
"Bytes value '" + input + "' is not prefixed with 0x");
}
try {
return Bytes.fromHexStringLenient((String) input);
} catch (IllegalArgumentException iae) {
return null;
}
} else {
return null;
}
}

@Override
public String serialize(final Object input) throws CoercingSerializeException {
if (input instanceof Bytes) {
return input.toString();
var result = convertImpl(input);
if (result != null) {
return result.toHexString();
} else {
throw new CoercingSerializeException("Unable to serialize " + input + " as an Bytes");
}
throw new CoercingSerializeException("Unable to serialize " + input + " as an Bytes");
}

@Override
public String parseValue(final Object input) throws CoercingParseValueException {
if (input instanceof Bytes) {
return input.toString();
public Bytes parseValue(final Object input) throws CoercingParseValueException {
var result = convertImpl(input);
if (result != null) {
return result;
} else {
throw new CoercingParseValueException(
"Unable to parse variable value " + input + " as an Bytes");
}
throw new CoercingParseValueException(
"Unable to parse variable value " + input + " as an Bytes");
}

@Override
public Bytes parseLiteral(final Object input) throws CoercingParseLiteralException {
if (!(input instanceof StringValue)) {
throw new CoercingParseLiteralException("Value is not any Bytes : '" + input + "'");
}
String inputValue = ((StringValue) input).getValue();
if (!Quantity.isValid(inputValue)) {
throw new CoercingParseLiteralException(
"Bytes value '" + inputValue + "' is not prefixed with 0x");
}
try {
return Bytes.fromHexStringLenient(inputValue);
} catch (final IllegalArgumentException e) {
var result = convertImpl(input);
if (result != null) {
return result;
} else {
throw new CoercingParseLiteralException("Value is not any Bytes : '" + input + "'");
}
}
};

private static final Coercing<Object, Object> BYTES32_COERCING =
new Coercing<Object, Object>() {
private static final Coercing<Bytes32, String> BYTES32_COERCING =
new Coercing<Bytes32, String>() {

Bytes32 convertImpl(final Object input) {
if (input instanceof Bytes32) {
return (Bytes32) input;
} else if (input instanceof Bytes) {
if (((Bytes) input).size() <= 32) {
return Bytes32.leftPad((Bytes) input);
} else {
return null;
}
} else if (input instanceof StringValue) {
return convertImpl((((StringValue) input).getValue()));
} else if (input instanceof String) {
if (!Quantity.isValid((String) input)) {
throw new CoercingParseLiteralException(
"Bytes32 value '" + input + "' is not prefixed with 0x");
} else {
try {
return Bytes32.fromHexStringLenient((String) input);
} catch (IllegalArgumentException iae) {
return null;
}
}
} else {
return null;
}
}

@Override
public String serialize(final Object input) throws CoercingSerializeException {
if (input instanceof Hash) {
return ((Hash) input).toString();
}
if (input instanceof Bytes32) {
return input.toString();
var result = convertImpl(input);
if (result == null) {
throw new CoercingSerializeException("Unable to serialize " + input + " as an Bytes32");
} else {
return result.toHexString();
}
throw new CoercingSerializeException("Unable to serialize " + input + " as an Bytes32");
}

@Override
public String parseValue(final Object input) throws CoercingParseValueException {
if (input instanceof Bytes32) {
return input.toString();
public Bytes32 parseValue(final Object input) throws CoercingParseValueException {
var result = convertImpl(input);
if (result == null) {
throw new CoercingParseValueException(
"Unable to parse variable value " + input + " as an Bytes32");
} else {
return result;
}
throw new CoercingParseValueException(
"Unable to parse variable value " + input + " as an Bytes32");
}

@Override
public Bytes32 parseLiteral(final Object input) throws CoercingParseLiteralException {
if (!(input instanceof StringValue)) {
throw new CoercingParseLiteralException("Value is not any Bytes32 : '" + input + "'");
}
String inputValue = ((StringValue) input).getValue();
if (!Quantity.isValid(inputValue)) {
throw new CoercingParseLiteralException(
"Bytes32 value '" + inputValue + "' is not prefixed with 0x");
}
try {
return Bytes32.fromHexStringLenient(inputValue);
} catch (final IllegalArgumentException e) {
var result = convertImpl(input);
if (result == null) {
throw new CoercingParseLiteralException("Value is not any Bytes32 : '" + input + "'");
} else {
return result;
}
}
};

private static final Coercing<Object, Object> LONG_COERCING =
new Coercing<Object, Object>() {
private static final Coercing<Number, Number> LONG_COERCING =
new Coercing<Number, Number>() {
@Override
public Number serialize(final Object input) throws CoercingSerializeException {
if (input instanceof Number) {
Expand Down Expand Up @@ -210,7 +292,7 @@ public Number parseValue(final Object input) throws CoercingParseValueException
}

@Override
public Object parseLiteral(final Object input) throws CoercingParseLiteralException {
public Number parseLiteral(final Object input) throws CoercingParseLiteralException {
try {
if (input instanceof IntValue) {
return ((IntValue) input).getValue().longValue();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,11 @@ public static Collection<String> specs() {
specs.add("graphql_tooComplex");
specs.add("graphql_tooComplexSchema");

specs.add("graphql_variable_address");
specs.add("graphql_variable_bytes");
specs.add("graphql_variable_bytes32");
specs.add("graphql_variable_long");

return specs;
}

Expand All @@ -128,7 +133,13 @@ private void graphQLCall(final String name) throws IOException {
EthGraphQLHttpBySpecTest.class.getResource(testSpecFile), Charsets.UTF_8);
final JsonObject spec = new JsonObject(json);
final String rawRequestBody = spec.getString("request");
final RequestBody requestBody = RequestBody.create(rawRequestBody, GRAPHQL);
final String rawVariables = spec.getString("variables");
final RequestBody requestBody =
rawVariables == null
? RequestBody.create(rawRequestBody, GRAPHQL)
: RequestBody.create(
"{ \"query\":\"" + rawRequestBody + "\", \"variables\": " + rawVariables + "}",
JSON);
final Request request = new Request.Builder().post(requestBody).url(baseUrl).build();

importBlocks(1, BLOCKS.size());
Expand Down
Loading