GraphQL Support for withdrawals (#5496)

Add support for withdrawals in GraphQL, including needed changes to
testing infrastructure for shanghai-era blocks.
Also align existing adapters with graphql schema optionality.

Signed-off-by: Danno Ferrin <danno.ferrin@gmail.com>
pull/5517/head
Danno Ferrin 2 years ago committed by GitHub
parent 925b915cd9
commit cc2150d537
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 3
      CHANGELOG.md
  2. 166
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/Scalars.java
  3. 22
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/AccountAdapter.java
  4. 121
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/BlockAdapterBase.java
  5. 22
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/EmptyAccountAdapter.java
  6. 20
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/LogAdapter.java
  7. 8
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/NormalBlockAdapter.java
  8. 25
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/PendingStateAdapter.java
  9. 14
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/SyncStateAdapter.java
  10. 50
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/TransactionAdapter.java
  11. 4
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/UncleBlockAdapter.java
  12. 43
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/WithdrawalAdapter.java
  13. 61
      ethereum/api/src/main/resources/schema.graphqls
  14. 75
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/AbstractEthGraphQLHttpServiceTest.java
  15. 25
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/BlockDataFetcherTest.java
  16. 12
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/EthGraphQLHttpBySpecTest.java
  17. 59
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/scalar/AddressScalarTest.java
  18. 55
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/scalar/BigIntScalarTest.java
  19. 56
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/scalar/Bytes32ScalarTest.java
  20. 56
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/scalar/BytesScalarTest.java
  21. 76
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/scalar/LongScalarTest.java
  22. 20
      ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/graphql/block_withdrawals.json
  23. 15
      ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/graphql/block_withdrawals_pre_shanghai.json
  24. 2
      ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/graphql/eth_blockNumber.json
  25. 2
      ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/graphql/eth_call_BlockLatest.json
  26. 2
      ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/graphql/eth_call_from_contract.json
  27. 2
      ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/graphql/eth_estimateGas_contractDeploy.json
  28. 2
      ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/graphql/eth_estimateGas_from_contract.json
  29. 2
      ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/graphql/eth_estimateGas_noParams.json
  30. 4
      ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/graphql/eth_getBalance_invalidAccountLatest.json
  31. 4
      ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/graphql/eth_getBalance_toobig_bn.json
  32. 29
      ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/graphql/eth_getBlock_shanghai.json
  33. 2
      ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/graphql/eth_getTransactionCount.json
  34. 19
      ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/graphql/eth_getTransaction_type2.json
  35. 3
      ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/graphql/graphql_blocks_byFrom.json
  36. 2
      ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/graphql/graphql_pending.json
  37. 24
      testutil/src/main/java/org/hyperledger/besu/testutil/BlockTestUtil.java
  38. BIN
      testutil/src/main/resources/hive/testBlockchain.blocks
  39. 22
      testutil/src/main/resources/hive/testGenesis.json

@ -6,7 +6,8 @@
### Additions and Improvements
- Allow Ethstats connection url to specify ws:// or wss:// scheme. [#5494](https://github.com/hyperledger/besu/issues/5494)
-
- Add support for Shanghai changes to the GraphQL service [#5496](https://github.com/hyperledger/besu/pull/5496)
### Bug Fixes
### Download Links

@ -17,8 +17,13 @@ package org.hyperledger.besu.ethereum.api.graphql.internal;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.Quantity;
import java.util.Locale;
import graphql.GraphQLContext;
import graphql.execution.CoercedVariables;
import graphql.language.IntValue;
import graphql.language.StringValue;
import graphql.language.Value;
import graphql.schema.Coercing;
import graphql.schema.CoercingParseLiteralException;
import graphql.schema.CoercingParseValueException;
@ -35,19 +40,19 @@ public class 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 (input instanceof Address address) {
return address;
} else if (input instanceof Bytes bytes) {
if (((Bytes) input).size() <= 20) {
return Address.wrap((Bytes) input);
return Address.wrap(bytes);
} else {
return null;
}
} else if (input instanceof StringValue) {
return convertImpl(((StringValue) input).getValue());
} else if (input instanceof String) {
} else if (input instanceof StringValue stringValue) {
return convertImpl(stringValue.getValue());
} else if (input instanceof String string) {
try {
return Address.fromHexStringStrict((String) input);
return Address.fromHexStringStrict(string);
} catch (IllegalArgumentException iae) {
return null;
}
@ -57,7 +62,9 @@ public class Scalars {
}
@Override
public String serialize(final Object input) throws CoercingSerializeException {
public String serialize(
final Object input, final GraphQLContext graphQLContext, final Locale locale)
throws CoercingSerializeException {
Address result = convertImpl(input);
if (result != null) {
return result.toHexString();
@ -67,7 +74,9 @@ public class Scalars {
}
@Override
public Address parseValue(final Object input) throws CoercingParseValueException {
public Address parseValue(
final Object input, final GraphQLContext graphQLContext, final Locale locale)
throws CoercingParseValueException {
Address result = convertImpl(input);
if (result != null) {
return result;
@ -78,7 +87,12 @@ public class Scalars {
}
@Override
public Address parseLiteral(final Object input) throws CoercingParseLiteralException {
public Address parseLiteral(
final Value<?> input,
final CoercedVariables variables,
final GraphQLContext graphQLContext,
final Locale locale)
throws CoercingParseLiteralException {
Address result = convertImpl(input);
if (result != null) {
return result;
@ -92,25 +106,27 @@ public class Scalars {
new Coercing<String, String>() {
String convertImpl(final Object input) {
if (input instanceof String) {
if (input instanceof String string) {
try {
return Bytes.fromHexStringLenient((String) input).toShortHexString();
return Bytes.fromHexStringLenient(string).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 if (input instanceof Bytes bytes) {
return bytes.toShortHexString();
} else if (input instanceof StringValue stringValue) {
return convertImpl(stringValue.getValue());
} else if (input instanceof IntValue intValue) {
return UInt256.valueOf(intValue.getValue()).toShortHexString();
} else {
return null;
}
}
@Override
public String serialize(final Object input) throws CoercingSerializeException {
public String serialize(
final Object input, final GraphQLContext graphQLContext, final Locale locale)
throws CoercingSerializeException {
var result = convertImpl(input);
if (result != null) {
return result;
@ -120,7 +136,9 @@ public class Scalars {
}
@Override
public String parseValue(final Object input) throws CoercingParseValueException {
public String parseValue(
final Object input, final GraphQLContext graphQLContext, final Locale locale)
throws CoercingParseValueException {
var result = convertImpl(input);
if (result != null) {
return result;
@ -131,7 +149,12 @@ public class Scalars {
}
@Override
public String parseLiteral(final Object input) throws CoercingParseLiteralException {
public String parseLiteral(
final Value<?> input,
final CoercedVariables variables,
final GraphQLContext graphQLContext,
final Locale locale)
throws CoercingParseLiteralException {
var result = convertImpl(input);
if (result != null) {
return result;
@ -145,12 +168,12 @@ public class Scalars {
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)) {
if (input instanceof Bytes bytes) {
return bytes;
} else if (input instanceof StringValue stringValue) {
return convertImpl(stringValue.getValue());
} else if (input instanceof String string) {
if (!Quantity.isValid(string)) {
throw new CoercingParseLiteralException(
"Bytes value '" + input + "' is not prefixed with 0x");
}
@ -165,7 +188,9 @@ public class Scalars {
}
@Override
public String serialize(final Object input) throws CoercingSerializeException {
public String serialize(
final Object input, final GraphQLContext graphQLContext, final Locale locale)
throws CoercingSerializeException {
var result = convertImpl(input);
if (result != null) {
return result.toHexString();
@ -175,7 +200,9 @@ public class Scalars {
}
@Override
public Bytes parseValue(final Object input) throws CoercingParseValueException {
public Bytes parseValue(
final Object input, final GraphQLContext graphQLContext, final Locale locale)
throws CoercingParseValueException {
var result = convertImpl(input);
if (result != null) {
return result;
@ -186,7 +213,12 @@ public class Scalars {
}
@Override
public Bytes parseLiteral(final Object input) throws CoercingParseLiteralException {
public Bytes parseLiteral(
final Value<?> input,
final CoercedVariables variables,
final GraphQLContext graphQLContext,
final Locale locale)
throws CoercingParseLiteralException {
var result = convertImpl(input);
if (result != null) {
return result;
@ -200,18 +232,18 @@ public class Scalars {
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) {
if (input instanceof Bytes32 bytes32) {
return bytes32;
} else if (input instanceof Bytes bytes) {
if (bytes.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)) {
} else if (input instanceof StringValue stringValue) {
return convertImpl(stringValue.getValue());
} else if (input instanceof String string) {
if (!Quantity.isValid(string)) {
throw new CoercingParseLiteralException(
"Bytes32 value '" + input + "' is not prefixed with 0x");
} else {
@ -227,7 +259,9 @@ public class Scalars {
}
@Override
public String serialize(final Object input) throws CoercingSerializeException {
public String serialize(
final Object input, final GraphQLContext graphQLContext, final Locale locale)
throws CoercingSerializeException {
var result = convertImpl(input);
if (result == null) {
throw new CoercingSerializeException("Unable to serialize " + input + " as an Bytes32");
@ -237,7 +271,9 @@ public class Scalars {
}
@Override
public Bytes32 parseValue(final Object input) throws CoercingParseValueException {
public Bytes32 parseValue(
final Object input, final GraphQLContext graphQLContext, final Locale locale)
throws CoercingParseValueException {
var result = convertImpl(input);
if (result == null) {
throw new CoercingParseValueException(
@ -248,7 +284,12 @@ public class Scalars {
}
@Override
public Bytes32 parseLiteral(final Object input) throws CoercingParseLiteralException {
public Bytes32 parseLiteral(
final Value<?> input,
final CoercedVariables variables,
final GraphQLContext graphQLContext,
final Locale locale)
throws CoercingParseLiteralException {
var result = convertImpl(input);
if (result == null) {
throw new CoercingParseLiteralException("Value is not any Bytes32 : '" + input + "'");
@ -259,13 +300,15 @@ public class Scalars {
};
private static final Coercing<Number, Number> LONG_COERCING =
new Coercing<Number, Number>() {
new Coercing<>() {
@Override
public Number serialize(final Object input) throws CoercingSerializeException {
if (input instanceof Number) {
return (Number) input;
} else if (input instanceof String) {
final String value = ((String) input).toLowerCase();
public Number serialize(
final Object input, final GraphQLContext graphQLContext, final Locale locale)
throws CoercingSerializeException {
if (input instanceof Number number) {
return number;
} else if (input instanceof String string) {
final String value = string.toLowerCase();
if (value.startsWith("0x")) {
return Bytes.fromHexStringLenient(value).toLong();
} else {
@ -276,11 +319,13 @@ public class Scalars {
}
@Override
public Number parseValue(final Object input) throws CoercingParseValueException {
if (input instanceof Number) {
return (Number) input;
} else if (input instanceof String) {
final String value = ((String) input).toLowerCase();
public Number parseValue(
final Object input, final GraphQLContext graphQLContext, final Locale locale)
throws CoercingParseValueException {
if (input instanceof Number number) {
return number;
} else if (input instanceof String string) {
final String value = string.toLowerCase();
if (value.startsWith("0x")) {
return Bytes.fromHexStringLenient(value).toLong();
} else {
@ -292,12 +337,17 @@ public class Scalars {
}
@Override
public Number parseLiteral(final Object input) throws CoercingParseLiteralException {
public Number parseLiteral(
final Value<?> input,
final CoercedVariables variables,
final GraphQLContext graphQLContext,
final Locale locale)
throws CoercingParseLiteralException {
try {
if (input instanceof IntValue) {
return ((IntValue) input).getValue().longValue();
} else if (input instanceof StringValue) {
final String value = ((StringValue) input).getValue().toLowerCase();
if (input instanceof IntValue intValue) {
return intValue.getValue().longValue();
} else if (input instanceof StringValue stringValue) {
final String value = stringValue.getValue().toLowerCase();
if (value.startsWith("0x")) {
return Bytes.fromHexStringLenient(value).toLong();
} else {

@ -41,24 +41,26 @@ public class AccountAdapter extends AdapterBase {
this.address = address;
}
public Optional<Address> getAddress() {
return Optional.of(address);
public Address getAddress() {
return address;
}
public Optional<Wei> getBalance() {
return account.map(AccountState::getBalance).or(() -> Optional.of(Wei.ZERO));
public Wei getBalance() {
return account.map(AccountState::getBalance).orElse(Wei.ZERO);
}
public Optional<Long> getTransactionCount() {
return account.map(AccountState::getNonce).or(() -> Optional.of(0L));
public Long getTransactionCount() {
return account.map(AccountState::getNonce).orElse(0L);
}
public Optional<Bytes> getCode() {
return account.map(AccountState::getCode);
public Bytes getCode() {
return account.map(AccountState::getCode).orElse(Bytes.EMPTY);
}
public Optional<Bytes32> getStorage(final DataFetchingEnvironment environment) {
public Bytes32 getStorage(final DataFetchingEnvironment environment) {
final Bytes32 slot = environment.getArgument("slot");
return account.map(account -> account.getStorageValue(UInt256.fromBytes(slot)));
return account
.map(a -> (Bytes32) a.getStorageValue(UInt256.fromBytes(slot)))
.orElse(Bytes32.ZERO);
}
}

@ -25,6 +25,7 @@ import org.hyperledger.besu.ethereum.api.query.TransactionWithMetadata;
import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.core.Difficulty;
import org.hyperledger.besu.ethereum.core.LogWithMetadata;
import org.hyperledger.besu.ethereum.mainnet.ImmutableTransactionValidationParams;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import org.hyperledger.besu.ethereum.mainnet.TransactionValidationParams;
import org.hyperledger.besu.ethereum.rlp.BytesValueRLPOutput;
@ -39,7 +40,7 @@ import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.function.Function;
import com.google.common.primitives.Longs;
import graphql.schema.DataFetchingEnvironment;
@ -64,29 +65,29 @@ public class BlockAdapterBase extends AdapterBase {
return block.map(NormalBlockAdapter::new);
}
public Optional<Bytes32> getHash() {
return Optional.of(header.getHash());
public Bytes32 getHash() {
return header.getHash();
}
public Optional<Bytes> getNonce() {
public Bytes getNonce() {
final long nonce = header.getNonce();
final byte[] bytes = Longs.toByteArray(nonce);
return Optional.of(Bytes.wrap(bytes));
return Bytes.wrap(bytes);
}
public Optional<Bytes32> getTransactionsRoot() {
return Optional.of(header.getTransactionsRoot());
public Bytes32 getTransactionsRoot() {
return header.getTransactionsRoot();
}
public Optional<Bytes32> getStateRoot() {
return Optional.of(header.getStateRoot());
public Bytes32 getStateRoot() {
return header.getStateRoot();
}
public Optional<Bytes32> getReceiptsRoot() {
return Optional.of(header.getReceiptsRoot());
public Bytes32 getReceiptsRoot() {
return header.getReceiptsRoot();
}
public Optional<AdapterBase> getMiner(final DataFetchingEnvironment environment) {
public AdapterBase getMiner(final DataFetchingEnvironment environment) {
final BlockchainQueries query = getBlockchainQueries(environment);
long blockNumber = header.getNumber();
@ -98,60 +99,61 @@ public class BlockAdapterBase extends AdapterBase {
return query
.getAndMapWorldState(blockNumber, ws -> Optional.ofNullable(ws.get(header.getCoinbase())))
.map(account -> (AdapterBase) new AccountAdapter(account))
.or(() -> Optional.of(new EmptyAccountAdapter(header.getCoinbase())));
.orElseGet(() -> new EmptyAccountAdapter(header.getCoinbase()));
}
public Optional<Bytes> getExtraData() {
return Optional.of(header.getExtraData());
public Bytes getExtraData() {
return header.getExtraData();
}
public Optional<Wei> getBaseFeePerGas() {
return header.getBaseFee();
}
public Optional<Long> getGasLimit() {
return Optional.of(header.getGasLimit());
public Long getGasLimit() {
return header.getGasLimit();
}
public Optional<Long> getGasUsed() {
return Optional.of(header.getGasUsed());
public Long getGasUsed() {
return header.getGasUsed();
}
public Optional<Long> getTimestamp() {
return Optional.of(header.getTimestamp());
public Long getTimestamp() {
return header.getTimestamp();
}
public Optional<Bytes> getLogsBloom() {
return Optional.of(header.getLogsBloom());
public Bytes getLogsBloom() {
return header.getLogsBloom();
}
public Optional<Bytes32> getMixHash() {
return Optional.of(header.getMixHash());
public Bytes32 getMixHash() {
return header.getMixHash();
}
public Optional<Difficulty> getDifficulty() {
return Optional.of(header.getDifficulty());
public Difficulty getDifficulty() {
return header.getDifficulty();
}
public Optional<Bytes32> getOmmerHash() {
return Optional.of(header.getOmmersHash());
public Bytes32 getOmmerHash() {
return header.getOmmersHash();
}
public Optional<Long> getNumber() {
final long bn = header.getNumber();
return Optional.of(bn);
public Long getNumber() {
return header.getNumber();
}
public Optional<AccountAdapter> getAccount(final DataFetchingEnvironment environment) {
public AccountAdapter getAccount(final DataFetchingEnvironment environment) {
final BlockchainQueries query = getBlockchainQueries(environment);
final long bn = header.getNumber();
return query.getAndMapWorldState(
bn,
ws -> {
final Address address = environment.getArgument("address");
return Optional.of(new AccountAdapter(ws.get(address)));
});
return query
.getAndMapWorldState(
bn,
ws -> {
final Address address = environment.getArgument("address");
return Optional.of(new AccountAdapter(ws.get(address)));
})
.get();
}
public List<LogAdapter> getLogs(final DataFetchingEnvironment environment) {
@ -168,7 +170,7 @@ public class BlockAdapterBase extends AdapterBase {
if (topic.isEmpty()) {
transformedTopics.add(Collections.singletonList(null));
} else {
transformedTopics.add(topic.stream().map(LogTopic::of).collect(Collectors.toList()));
transformedTopics.add(topic.stream().map(LogTopic::of).toList());
}
}
final LogsQuery query =
@ -185,9 +187,9 @@ public class BlockAdapterBase extends AdapterBase {
return results;
}
public Optional<Long> getEstimateGas(final DataFetchingEnvironment environment) {
public Long getEstimateGas(final DataFetchingEnvironment environment) {
final Optional<CallResult> result = executeCall(environment);
return result.map(CallResult::getGasUsed);
return result.map(CallResult::getGasUsed).orElse(0L);
}
public Optional<CallResult> getCall(final DataFetchingEnvironment environment) {
@ -240,12 +242,14 @@ public class BlockAdapterBase extends AdapterBase {
data,
Optional.empty());
ImmutableTransactionValidationParams.Builder transactionValidationParams =
ImmutableTransactionValidationParams.builder()
.from(TransactionValidationParams.transactionSimulator());
transactionValidationParams.isAllowExceedingBalance(true);
final Optional<TransactionSimulatorResult> opt =
transactionSimulator.process(
param,
TransactionValidationParams.transactionSimulator(),
OperationTracer.NO_TRACING,
bn);
param, transactionValidationParams.build(), OperationTracer.NO_TRACING, bn);
if (opt.isPresent()) {
final TransactionSimulatorResult result = opt.get();
long status = 0;
@ -259,13 +263,13 @@ public class BlockAdapterBase extends AdapterBase {
return Optional.empty();
}
Optional<Bytes> getRawHeader() {
Bytes getRawHeader() {
final BytesValueRLPOutput rlpOutput = new BytesValueRLPOutput();
header.writeTo(rlpOutput);
return Optional.of(rlpOutput.encoded());
return rlpOutput.encoded();
}
Optional<Bytes> getRaw(final DataFetchingEnvironment environment) {
Bytes getRaw(final DataFetchingEnvironment environment) {
final BlockchainQueries query = getBlockchainQueries(environment);
return query
.getBlockchain()
@ -275,6 +279,23 @@ public class BlockAdapterBase extends AdapterBase {
final BytesValueRLPOutput rlpOutput = new BytesValueRLPOutput();
blockBody.writeWrappedBodyTo(rlpOutput);
return rlpOutput.encoded();
});
})
.orElse(Bytes.EMPTY);
}
Optional<Bytes32> getWithdrawalsRoot() {
return header.getWithdrawalsRoot().map(Function.identity());
}
Optional<List<WithdrawalAdapter>> getWithdrawals(final DataFetchingEnvironment environment) {
final BlockchainQueries query = getBlockchainQueries(environment);
return query
.getBlockchain()
.getBlockBody(header.getBlockHash())
.flatMap(
blockBody ->
blockBody
.getWithdrawals()
.map(wl -> wl.stream().map(WithdrawalAdapter::new).toList()));
}
}

@ -17,8 +17,6 @@ package org.hyperledger.besu.ethereum.api.graphql.internal.pojoadapter;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Wei;
import java.util.Optional;
import graphql.schema.DataFetchingEnvironment;
import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.bytes.Bytes32;
@ -32,27 +30,27 @@ public class EmptyAccountAdapter extends AccountAdapter {
}
@Override
public Optional<Address> getAddress() {
return Optional.of(address);
public Address getAddress() {
return address;
}
@Override
public Optional<Wei> getBalance() {
return Optional.of(Wei.ZERO);
public Wei getBalance() {
return Wei.ZERO;
}
@Override
public Optional<Long> getTransactionCount() {
return Optional.of(0L);
public Long getTransactionCount() {
return 0L;
}
@Override
public Optional<Bytes> getCode() {
return Optional.of(Bytes.EMPTY);
public Bytes getCode() {
return Bytes.EMPTY;
}
@Override
public Optional<Bytes32> getStorage(final DataFetchingEnvironment environment) {
return Optional.of(Bytes32.ZERO);
public Bytes32 getStorage(final DataFetchingEnvironment environment) {
return Bytes32.ZERO;
}
}

@ -35,8 +35,8 @@ public class LogAdapter extends AdapterBase {
this.logWithMetadata = logWithMetadata;
}
public Optional<Integer> getIndex() {
return Optional.of(logWithMetadata.getLogIndex());
public Integer getIndex() {
return logWithMetadata.getLogIndex();
}
public List<LogTopic> getTopics() {
@ -44,18 +44,18 @@ public class LogAdapter extends AdapterBase {
return new ArrayList<>(topics);
}
public Optional<Bytes> getData() {
return Optional.of(logWithMetadata.getData());
public Bytes getData() {
return logWithMetadata.getData();
}
public Optional<TransactionAdapter> getTransaction(final DataFetchingEnvironment environment) {
public TransactionAdapter getTransaction(final DataFetchingEnvironment environment) {
final BlockchainQueries query = getBlockchainQueries(environment);
final Hash hash = logWithMetadata.getTransactionHash();
final Optional<TransactionWithMetadata> tran = query.transactionByHash(hash);
return tran.map(TransactionAdapter::new);
return tran.map(TransactionAdapter::new).orElseThrow();
}
public Optional<AccountAdapter> getAccount(final DataFetchingEnvironment environment) {
public AccountAdapter getAccount(final DataFetchingEnvironment environment) {
final BlockchainQueries query = getBlockchainQueries(environment);
long blockNumber = logWithMetadata.getBlockNumber();
final Long bn = environment.getArgument("block");
@ -63,7 +63,9 @@ public class LogAdapter extends AdapterBase {
blockNumber = bn;
}
return query.getAndMapWorldState(
blockNumber, ws -> Optional.of(new AccountAdapter(ws.get(logWithMetadata.getLogger()))));
return query
.getAndMapWorldState(
blockNumber, ws -> Optional.of(new AccountAdapter(ws.get(logWithMetadata.getLogger()))))
.get();
}
}

@ -42,8 +42,8 @@ public class NormalBlockAdapter extends BlockAdapterBase {
return Optional.of(blockWithMetaData.getTransactions().size());
}
public Optional<Difficulty> getTotalDifficulty() {
return Optional.of(blockWithMetaData.getTotalDifficulty());
public Difficulty getTotalDifficulty() {
return blockWithMetaData.getTotalDifficulty();
}
public Optional<Integer> getOmmerCount() {
@ -65,7 +65,7 @@ public class NormalBlockAdapter extends BlockAdapterBase {
public Optional<UncleBlockAdapter> getOmmerAt(final DataFetchingEnvironment environment) {
final BlockchainQueries query = getBlockchainQueries(environment);
final int index = environment.getArgument("index");
final int index = ((Number) environment.getArgument("index")).intValue();
final List<Hash> ommers = blockWithMetaData.getOmmers();
if (ommers.size() > index) {
final Hash hash = blockWithMetaData.getHeader().getHash();
@ -85,7 +85,7 @@ public class NormalBlockAdapter extends BlockAdapterBase {
}
public Optional<TransactionAdapter> getTransactionAt(final DataFetchingEnvironment environment) {
final int index = environment.getArgument("index");
final int index = ((Number) environment.getArgument("index")).intValue();
final List<TransactionWithMetadata> trans = blockWithMetaData.getTransactions();
if (trans.size() > index) {

@ -21,15 +21,17 @@ import org.hyperledger.besu.ethereum.api.query.BlockchainQueries;
import org.hyperledger.besu.ethereum.api.query.TransactionWithMetadata;
import org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction;
import org.hyperledger.besu.ethereum.eth.transactions.PendingTransactions;
import org.hyperledger.besu.ethereum.mainnet.ImmutableTransactionValidationParams;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import org.hyperledger.besu.ethereum.mainnet.TransactionValidationParams;
import org.hyperledger.besu.ethereum.transaction.CallParameter;
import org.hyperledger.besu.ethereum.transaction.TransactionSimulator;
import org.hyperledger.besu.ethereum.transaction.TransactionSimulatorResult;
import org.hyperledger.besu.evm.tracing.OperationTracer;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
import graphql.schema.DataFetchingEnvironment;
import org.apache.tuweni.bytes.Bytes;
@ -53,13 +55,12 @@ public class PendingStateAdapter extends AdapterBase {
.map(PendingTransaction::getTransaction)
.map(TransactionWithMetadata::new)
.map(TransactionAdapter::new)
.collect(Collectors.toList());
.toList();
}
// until the miner can expose the current "proposed block" we have no
// speculative environment, so estimate against latest.
public Optional<AccountAdapter> getAccount(
final DataFetchingEnvironment dataFetchingEnvironment) {
public AccountAdapter getAccount(final DataFetchingEnvironment dataFetchingEnvironment) {
final BlockchainQueries blockchainQuery =
dataFetchingEnvironment.getGraphQlContext().get(GraphQLContextType.BLOCKCHAIN_QUERIES);
final Address addr = dataFetchingEnvironment.getArgument("address");
@ -67,7 +68,8 @@ public class PendingStateAdapter extends AdapterBase {
final long latestBlockNumber = blockchainQuery.latestBlock().get().getHeader().getNumber();
return blockchainQuery
.getAndMapWorldState(latestBlockNumber, ws -> Optional.ofNullable(ws.get(addr)))
.map(AccountAdapter::new);
.map(AccountAdapter::new)
.orElseGet(() -> new AccountAdapter(null));
}
// until the miner can expose the current "proposed block" we have no
@ -111,7 +113,18 @@ public class PendingStateAdapter extends AdapterBase {
final CallParameter param =
new CallParameter(from, to, gasParam, gasPriceParam, valueParam, data);
final Optional<TransactionSimulatorResult> opt = transactionSimulator.processAtHead(param);
ImmutableTransactionValidationParams.Builder transactionValidationParams =
ImmutableTransactionValidationParams.builder()
.from(TransactionValidationParams.transactionSimulator());
transactionValidationParams.isAllowExceedingBalance(true);
final Optional<TransactionSimulatorResult> opt =
transactionSimulator.process(
param,
transactionValidationParams.build(),
OperationTracer.NO_TRACING,
query.getBlockchain().getChainHeadHeader());
if (opt.isPresent()) {
final TransactionSimulatorResult result = opt.get();
long status = 0;

@ -16,8 +16,6 @@ package org.hyperledger.besu.ethereum.api.graphql.internal.pojoadapter;
import org.hyperledger.besu.plugin.data.SyncStatus;
import java.util.Optional;
@SuppressWarnings("unused") // reflected by GraphQL
public class SyncStateAdapter {
private final SyncStatus syncStatus;
@ -26,15 +24,15 @@ public class SyncStateAdapter {
this.syncStatus = syncStatus;
}
public Optional<Long> getStartingBlock() {
return Optional.of(syncStatus.getStartingBlock());
public Long getStartingBlock() {
return syncStatus.getStartingBlock();
}
public Optional<Long> getCurrentBlock() {
return Optional.of(syncStatus.getCurrentBlock());
public Long getCurrentBlock() {
return syncStatus.getCurrentBlock();
}
public Optional<Long> getHighestBlock() {
return Optional.of(syncStatus.getHighestBlock());
public Long getHighestBlock() {
return syncStatus.getHighestBlock();
}
}

@ -28,7 +28,6 @@ import org.hyperledger.besu.ethereum.rlp.BytesValueRLPOutput;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import javax.annotation.Nonnull;
import graphql.schema.DataFetchingEnvironment;
@ -58,35 +57,37 @@ public class TransactionAdapter extends AdapterBase {
return transactionReceiptWithMetadata;
}
public Optional<Hash> getHash() {
return Optional.of(transactionWithMetadata.getTransaction().getHash());
public Hash getHash() {
return transactionWithMetadata.getTransaction().getHash();
}
public Optional<Integer> getType() {
return Optional.of(transactionWithMetadata.getTransaction().getType().ordinal());
}
public Optional<Long> getNonce() {
final long nonce = transactionWithMetadata.getTransaction().getNonce();
return Optional.of(nonce);
public Long getNonce() {
return transactionWithMetadata.getTransaction().getNonce();
}
public Optional<Integer> getIndex() {
return transactionWithMetadata.getTransactionIndex();
}
public Optional<AccountAdapter> getFrom(final DataFetchingEnvironment environment) {
public AccountAdapter getFrom(final DataFetchingEnvironment environment) {
final BlockchainQueries query = getBlockchainQueries(environment);
Long blockNumber = environment.getArgument("block");
if (blockNumber == null) {
blockNumber = transactionWithMetadata.getBlockNumber().orElseGet(query::headBlockNumber);
}
return query.getAndMapWorldState(
blockNumber,
mutableWorldState ->
Optional.of(
new AccountAdapter(
mutableWorldState.get(transactionWithMetadata.getTransaction().getSender()))));
return query
.getAndMapWorldState(
blockNumber,
mutableWorldState ->
Optional.of(
new AccountAdapter(
mutableWorldState.get(
transactionWithMetadata.getTransaction().getSender()))))
.get();
}
public Optional<AccountAdapter> getTo(final DataFetchingEnvironment environment) {
@ -105,12 +106,12 @@ public class TransactionAdapter extends AdapterBase {
.map(address -> new AccountAdapter(address, ws.get(address))));
}
public Optional<Wei> getValue() {
return Optional.of(transactionWithMetadata.getTransaction().getValue());
public Wei getValue() {
return transactionWithMetadata.getTransaction().getValue();
}
public Optional<Wei> getGasPrice() {
return transactionWithMetadata.getTransaction().getGasPrice();
public Wei getGasPrice() {
return transactionWithMetadata.getTransaction().getGasPrice().orElse(Wei.ZERO);
}
public Optional<Wei> getMaxPriorityFeePerGas() {
@ -126,12 +127,17 @@ public class TransactionAdapter extends AdapterBase {
.map(rwm -> rwm.getTransaction().getEffectiveGasPrice(rwm.getBaseFee()));
}
public Optional<Long> getGas() {
return Optional.of(transactionWithMetadata.getTransaction().getGasLimit());
public Optional<Wei> getEffectiveTip(final DataFetchingEnvironment environment) {
return getReceipt(environment)
.map(rwm -> rwm.getTransaction().getEffectivePriorityFeePerGas(rwm.getBaseFee()));
}
public Long getGas() {
return transactionWithMetadata.getTransaction().getGasLimit();
}
public Optional<Bytes> getInputData() {
return Optional.of(transactionWithMetadata.getTransaction().getPayload());
public Bytes getInputData() {
return transactionWithMetadata.getTransaction().getPayload();
}
public Optional<NormalBlockAdapter> getBlock(final DataFetchingEnvironment environment) {
@ -212,7 +218,7 @@ public class TransactionAdapter extends AdapterBase {
return transactionWithMetadata
.getTransaction()
.getAccessList()
.map(l -> l.stream().map(AccessListEntryAdapter::new).collect(Collectors.toList()))
.map(l -> l.stream().map(AccessListEntryAdapter::new).toList())
.orElse(List.of());
}

@ -33,8 +33,8 @@ class UncleBlockAdapter extends BlockAdapterBase {
return Optional.of(0);
}
public Optional<UInt256> getTotalDifficulty() {
return Optional.of(UInt256.ZERO);
public UInt256 getTotalDifficulty() {
return UInt256.ZERO;
}
public Optional<Integer> getOmmerCount() {

@ -0,0 +1,43 @@
/*
* Copyright contributors to Hyperledger Besu
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.ethereum.api.graphql.internal.pojoadapter;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.plugin.data.Withdrawal;
public class WithdrawalAdapter {
Withdrawal withdrawal;
public WithdrawalAdapter(final Withdrawal withdrawal) {
this.withdrawal = withdrawal;
}
public Long getIndex() {
return withdrawal.getIndex().toLong();
}
public Long getValidator() {
return withdrawal.getValidatorIndex().toLong();
}
public Address getAddress() {
return withdrawal.getAddress();
}
public Long getAmount() {
return withdrawal.getAmount().getAsBigInteger().longValue();
}
}

@ -69,7 +69,7 @@ type Block {
TransactionCount is the number of transactions in this block. if
transactions are not available for this block, this field will be null.
"""
transactionCount: Int
transactionCount: Long
"""
StateRoot is the keccak256 hash of the state trie after this block was processed.
@ -132,7 +132,7 @@ type Block {
OmmerCount is the number of ommers (AKA uncles) associated with this
block. If ommers are unavailable, this field will be null.
"""
ommerCount: Int
ommerCount: Long
"""
Ommers is a list of ommer (AKA uncle) blocks associated with this block.
@ -146,7 +146,7 @@ type Block {
OmmerAt returns the ommer (AKA uncle) at the specified index. If ommers
are unavailable, or the index is out of bounds, this field will be null.
"""
ommerAt(index: Int!): Block
ommerAt(index: Long!): Block
"""
OmmerHash is the keccak256 hash of all the ommers (AKA uncles)
@ -165,13 +165,13 @@ type Block {
transactions are unavailable for this block, or if the index is out of
bounds, this field will be null.
"""
transactionAt(index: Int!): Transaction
transactionAt(index: Long!): Transaction
"""Logs returns a filtered set of logs from this block."""
logs(filter: BlockFilterCriteria!): [Log!]!
"""Account fetches an Ethereum account at the current block's state."""
account(address: Address!): Account
account(address: Address!): Account!
"""Call executes a local call operation at the current block's state."""
call(data: CallData!): CallResult
@ -187,6 +187,18 @@ type Block {
"""Raw is the RLP encoding of the block."""
raw: Bytes!
"""
WithdrawalsRoot is the keccak256 hash of the root of the trie of withdrawals in this block.
If withdrawals are unavailable for this block, this field will be null.
"""
withdrawalsRoot: Bytes32
"""
Withdrawals is a list of withdrawals associated with this block. If
withdrawals are unavailable for this block, this field will be null.
"""
withdrawals: [Withdrawal!]
}
"""
@ -205,7 +217,7 @@ input BlockFilterCriteria {
of topics. Topics matches a prefix of that list. An empty element array matches any
topic. Non-empty elements represent an alternative that matches any of the
contained topics.
Examples:
- [] or nil matches any topic list
- [[A]] matches topic A in first position
@ -296,7 +308,7 @@ input FilterCriteria {
of topics. Topics matches a prefix of that list. An empty element array matches any
topic. Non-empty elements represent an alternative that matches any of the
contained topics.
Examples:
- [] or nil matches any topic list
- [[A]] matches topic A in first position
@ -310,7 +322,7 @@ input FilterCriteria {
"""Log is an Ethereum event log."""
type Log {
"""Index is the index of this log in the block."""
index: Int!
index: Long!
"""
Account is the account which generated this log - this will always
@ -328,7 +340,11 @@ type Log {
transaction: Transaction!
}
"""Long is a 64 bit unsigned integer."""
"""
Long is a 64 bit unsigned integer. Input is accepted as either a JSON number or as a string.
Strings may be either decimal or 0x-prefixed hexadecimal. Output values are all
0x-prefixed hexadecimal.
"""
scalar Long
type Mutation {
@ -339,13 +355,13 @@ type Mutation {
"""Pending represents the current pending state."""
type Pending {
"""TransactionCount is the number of transactions in the pending state."""
transactionCount: Int!
transactionCount: Long!
"""Transactions is a list of transactions in the current pending state."""
transactions: [Transaction!]
"""Account fetches an Ethereum account for the pending state."""
account(address: Address!): Account
account(address: Address!): Account!
"""Call executes a local call operation for the pending state."""
call(data: CallData!): CallResult
@ -426,7 +442,7 @@ type Transaction {
Index is the index of this transaction in the parent block. This will
be null if the transaction has not yet been mined.
"""
index: Int
index: Long
"""
From is the account that sent this transaction - this will always be
@ -521,7 +537,7 @@ type Transaction {
v: BigInt!
"""Envelope transaction support"""
type: Int
type: Long
accessList: [AccessTuple!]
"""
@ -536,10 +552,21 @@ type Transaction {
this is equivalent to TxType || ReceiptEncoding.
"""
rawReceipt: Bytes!
}
""" IsPrivate is an indicator of a GoQuorum private transaction"""
isPrivate: Boolean
""" PrivateInputData is the actual payload of a GoQuorum private transaction"""
privateInputData: Bytes
"""EIP-4895"""
type Withdrawal {
"""
Index is a monotonically increasing identifier issued by consensus layer.
"""
index: Long!
"""Validator is index of the validator associated with withdrawal."""
validator: Long!
"""Address recipient of the withdrawn amount."""
address: Address!
"""Amount is the withdrawal value in Gwei."""
amount: Long!
}

@ -14,21 +14,14 @@
*/
package org.hyperledger.besu.ethereum.api.graphql;
import static org.hyperledger.besu.ethereum.core.InMemoryKeyValueStorageProvider.createInMemoryWorldStateArchive;
import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.ethereum.ProtocolContext;
import org.hyperledger.besu.ethereum.api.ImmutableApiConfiguration;
import org.hyperledger.besu.ethereum.api.query.BlockchainQueries;
import org.hyperledger.besu.ethereum.blockcreation.PoWMiningCoordinator;
import org.hyperledger.besu.ethereum.chain.GenesisState;
import org.hyperledger.besu.ethereum.chain.MutableBlockchain;
import org.hyperledger.besu.ethereum.core.Block;
import org.hyperledger.besu.ethereum.core.BlockHeaderFunctions;
import org.hyperledger.besu.ethereum.core.BlockImporter;
import org.hyperledger.besu.ethereum.core.BlockchainSetupUtil;
import org.hyperledger.besu.ethereum.core.DefaultSyncStatus;
import org.hyperledger.besu.ethereum.core.InMemoryKeyValueStorageProvider;
import org.hyperledger.besu.ethereum.core.ProtocolScheduleFixture;
import org.hyperledger.besu.ethereum.core.Synchronizer;
import org.hyperledger.besu.ethereum.core.Transaction;
import org.hyperledger.besu.ethereum.eth.EthProtocol;
@ -36,31 +29,20 @@ import org.hyperledger.besu.ethereum.eth.manager.EthScheduler;
import org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction;
import org.hyperledger.besu.ethereum.eth.transactions.PendingTransactions;
import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool;
import org.hyperledger.besu.ethereum.mainnet.HeaderValidationMode;
import org.hyperledger.besu.ethereum.mainnet.MainnetBlockHeaderFunctions;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec;
import org.hyperledger.besu.ethereum.mainnet.ValidationResult;
import org.hyperledger.besu.ethereum.p2p.rlpx.wire.Capability;
import org.hyperledger.besu.ethereum.transaction.TransactionInvalidReason;
import org.hyperledger.besu.ethereum.util.RawBlockIterator;
import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive;
import org.hyperledger.besu.ethereum.worldstate.DataStorageFormat;
import org.hyperledger.besu.plugin.data.SyncStatus;
import org.hyperledger.besu.plugin.data.TransactionType;
import org.hyperledger.besu.testutil.BlockTestUtil;
import java.net.URL;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import com.google.common.base.Charsets;
import com.google.common.io.Resources;
import graphql.GraphQL;
import io.vertx.core.Vertx;
import okhttp3.MediaType;
@ -76,13 +58,7 @@ import org.mockito.Mockito;
public abstract class AbstractEthGraphQLHttpServiceTest {
@ClassRule public static final TemporaryFolder folder = new TemporaryFolder();
private static ProtocolSchedule PROTOCOL_SCHEDULE;
static List<Block> BLOCKS;
private static Block GENESIS_BLOCK;
private static GenesisState GENESIS_CONFIG;
private static BlockchainSetupUtil blockchainSetupUtil;
private final Vertx vertx = Vertx.vertx();
@ -95,29 +71,12 @@ public abstract class AbstractEthGraphQLHttpServiceTest {
final MediaType JSON = MediaType.parse("application/json; charset=utf-8");
protected static final MediaType GRAPHQL = MediaType.parse("application/graphql; charset=utf-8");
private ProtocolContext context;
@BeforeClass
public static void setupConstants() throws Exception {
PROTOCOL_SCHEDULE = ProtocolScheduleFixture.MAINNET;
final URL blocksUrl = BlockTestUtil.getTestBlockchainUrl();
final URL genesisJsonUrl = BlockTestUtil.getTestGenesisUrl();
final BlockHeaderFunctions blockHeaderFunctions = new MainnetBlockHeaderFunctions();
BLOCKS = new ArrayList<>();
try (final RawBlockIterator iterator =
new RawBlockIterator(Paths.get(blocksUrl.toURI()), blockHeaderFunctions)) {
while (iterator.hasNext()) {
BLOCKS.add(iterator.next());
}
}
final String genesisJson = Resources.toString(genesisJsonUrl, Charsets.UTF_8);
GENESIS_BLOCK = BLOCKS.get(0);
GENESIS_CONFIG = GenesisState.fromJson(genesisJson, PROTOCOL_SCHEDULE);
public static void setupConstants() {
blockchainSetupUtil =
BlockchainSetupUtil.createForEthashChain(
BlockTestUtil.getHiveTestChainResources(), DataStorageFormat.FOREST);
blockchainSetupUtil.importAllBlocks();
}
@Before
@ -151,12 +110,9 @@ public abstract class AbstractEthGraphQLHttpServiceTest {
.gasPrice(Wei.ONE)
.build())));
final WorldStateArchive stateArchive = createInMemoryWorldStateArchive();
GENESIS_CONFIG.writeStateTo(stateArchive.getMutable());
final MutableBlockchain blockchain =
InMemoryKeyValueStorageProvider.createInMemoryBlockchain(GENESIS_BLOCK);
context = new ProtocolContext(blockchain, stateArchive, null);
final MutableBlockchain blockchain = blockchainSetupUtil.getBlockchain();
ProtocolContext context =
new ProtocolContext(blockchain, blockchainSetupUtil.getWorldArchive(), null);
final BlockchainQueries blockchainQueries =
new BlockchainQueries(
context.getBlockchain(),
@ -185,7 +141,7 @@ public abstract class AbstractEthGraphQLHttpServiceTest {
GraphQLContextType.BLOCKCHAIN_QUERIES,
blockchainQueries,
GraphQLContextType.PROTOCOL_SCHEDULE,
PROTOCOL_SCHEDULE,
blockchainSetupUtil.getProtocolSchedule(),
GraphQLContextType.TRANSACTION_POOL,
transactionPoolMock,
GraphQLContextType.MINING_COORDINATOR,
@ -206,11 +162,4 @@ public abstract class AbstractEthGraphQLHttpServiceTest {
service.stop().join();
vertx.close();
}
void importBlock(final int n) {
final Block block = BLOCKS.get(n);
final ProtocolSpec protocolSpec = PROTOCOL_SCHEDULE.getByBlockHeader(block.getHeader());
final BlockImporter blockImporter = protocolSpec.getBlockImporter();
blockImporter.importBlock(context, block, HeaderValidationMode.FULL);
}
}

@ -20,6 +20,7 @@ import static org.mockito.Mockito.when;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.ethereum.api.graphql.internal.pojoadapter.EmptyAccountAdapter;
import org.hyperledger.besu.ethereum.api.graphql.internal.pojoadapter.NormalBlockAdapter;
import org.hyperledger.besu.ethereum.api.query.BlockWithMetadata;
@ -36,10 +37,10 @@ import org.mockito.junit.MockitoJUnitRunner;
public class BlockDataFetcherTest extends AbstractDataFetcherTest {
@Test
public void bothNumberAndHashThrows() throws Exception {
public void bothNumberAndHashThrows() {
final Hash fakedHash = Hash.hash(Bytes.of(1));
when(environment.getArgument(ArgumentMatchers.eq("number"))).thenReturn(1L);
when(environment.getArgument(ArgumentMatchers.eq("hash"))).thenReturn(fakedHash);
when(environment.getArgument("number")).thenReturn(1L);
when(environment.getArgument("hash")).thenReturn(fakedHash);
assertThatThrownBy(() -> fetcher.get(environment)).isInstanceOf(GraphQLException.class);
}
@ -47,8 +48,8 @@ public class BlockDataFetcherTest extends AbstractDataFetcherTest {
@Test
public void onlyNumber() throws Exception {
when(environment.getArgument(ArgumentMatchers.eq("number"))).thenReturn(1L);
when(environment.getArgument(ArgumentMatchers.eq("hash"))).thenReturn(null);
when(environment.getArgument("number")).thenReturn(1L);
when(environment.getArgument("hash")).thenReturn(null);
when(environment.getGraphQlContext()).thenReturn(graphQLContext);
when(graphQLContext.get(GraphQLContextType.BLOCKCHAIN_QUERIES)).thenReturn(query);
@ -64,8 +65,8 @@ public class BlockDataFetcherTest extends AbstractDataFetcherTest {
// as null. The compromise is to report zeros and empty on query from a block.
final Address testAddress = Address.fromHexString("0xdeadbeef");
when(environment.getArgument(ArgumentMatchers.eq("number"))).thenReturn(1L);
when(environment.getArgument(ArgumentMatchers.eq("hash"))).thenReturn(null);
when(environment.getArgument("number")).thenReturn(1L);
when(environment.getArgument("hash")).thenReturn(null);
when(environment.getGraphQlContext()).thenReturn(graphQLContext);
when(graphQLContext.get(GraphQLContextType.BLOCKCHAIN_QUERIES)).thenReturn(query);
@ -75,10 +76,10 @@ public class BlockDataFetcherTest extends AbstractDataFetcherTest {
final Optional<NormalBlockAdapter> maybeBlock = fetcher.get(environment);
assertThat(maybeBlock).isPresent();
assertThat(maybeBlock.get().getMiner(environment)).isPresent();
assertThat(((EmptyAccountAdapter) maybeBlock.get().getMiner(environment).get()).getBalance())
.isPresent();
assertThat(((EmptyAccountAdapter) maybeBlock.get().getMiner(environment).get()).getAddress())
.contains(testAddress);
assertThat(maybeBlock.get().getMiner(environment)).isNotNull();
assertThat(((EmptyAccountAdapter) maybeBlock.get().getMiner(environment)).getBalance())
.isGreaterThanOrEqualTo(Wei.ZERO);
assertThat(((EmptyAccountAdapter) maybeBlock.get().getMiner(environment)).getAddress())
.isEqualTo(testAddress);
}
}

@ -118,6 +118,11 @@ public class EthGraphQLHttpBySpecTest extends AbstractEthGraphQLHttpServiceTest
specs.add("graphql_variable_bytes32");
specs.add("graphql_variable_long");
specs.add("block_withdrawals_pre_shanghai");
specs.add("block_withdrawals");
specs.add("eth_getTransaction_type2");
specs.add("eth_getBlock_shanghai");
return specs;
}
@ -142,7 +147,6 @@ public class EthGraphQLHttpBySpecTest extends AbstractEthGraphQLHttpServiceTest
JSON);
final Request request = new Request.Builder().post(requestBody).url(baseUrl).build();
importBlocks(1, BLOCKS.size());
try (final Response resp = client.newCall(request).execute()) {
final JsonObject expectedRespBody = spec.getJsonObject("response");
final String resultStr = resp.body().string();
@ -154,10 +158,4 @@ public class EthGraphQLHttpBySpecTest extends AbstractEthGraphQLHttpServiceTest
Assertions.assertThat(resp.code()).isEqualTo(expectedStatusCode);
}
}
private void importBlocks(final int from, final int to) {
for (int i = from; i < to; ++i) {
importBlock(i);
}
}
}

@ -20,6 +20,11 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.ethereum.api.graphql.internal.Scalars;
import java.util.Locale;
import graphql.GraphQLContext;
import graphql.execution.CoercedVariables;
import graphql.language.FloatValue;
import graphql.language.StringValue;
import graphql.schema.CoercingParseLiteralException;
import graphql.schema.CoercingParseValueException;
@ -40,43 +45,83 @@ public class AddressScalarTest {
@Test
public void parseValueTest() {
final Address result = (Address) scalar.getCoercing().parseValue(addrStr);
final Address result =
(Address)
scalar
.getCoercing()
.parseValue(addrStr, GraphQLContext.newContext().build(), Locale.ENGLISH);
assertThat(result).isEqualTo(addr);
}
@Test
public void parseValueErrorTest() {
assertThatThrownBy(() -> scalar.getCoercing().parseValue(3.4f))
assertThatThrownBy(
() ->
scalar
.getCoercing()
.parseValue(3.4f, GraphQLContext.newContext().build(), Locale.ENGLISH))
.isInstanceOf(CoercingParseValueException.class);
}
@Test
public void serializeTest() {
final String result = (String) scalar.getCoercing().serialize(addr);
final String result =
(String)
scalar
.getCoercing()
.serialize(addr, GraphQLContext.newContext().build(), Locale.ENGLISH);
assertThat(result).isEqualTo(addrStr);
}
@Test
public void serializeErrorTest() {
assertThatThrownBy(() -> scalar.getCoercing().serialize(3.4f))
assertThatThrownBy(
() ->
scalar
.getCoercing()
.serialize(3.4f, GraphQLContext.newContext().build(), Locale.ENGLISH))
.isInstanceOf(CoercingSerializeException.class);
}
@Test
public void parseLiteralTest() {
final Address result = (Address) scalar.getCoercing().parseLiteral(addrValue);
final Address result =
(Address)
scalar
.getCoercing()
.parseLiteral(
addrValue,
CoercedVariables.emptyVariables(),
GraphQLContext.newContext().build(),
Locale.ENGLISH);
assertThat(result).isEqualTo(addr);
}
@Test
public void parseLiteralErrorTest() {
assertThatThrownBy(() -> scalar.getCoercing().parseLiteral(3.4f))
assertThatThrownBy(
() ->
scalar
.getCoercing()
.parseLiteral(
FloatValue.of(3.4f),
CoercedVariables.emptyVariables(),
GraphQLContext.newContext().build(),
Locale.ENGLISH))
.isInstanceOf(CoercingParseLiteralException.class);
}
@Test
public void parseLiteralErrorTest2() {
assertThatThrownBy(() -> scalar.getCoercing().parseLiteral(invalidAddrValue))
assertThatThrownBy(
() ->
scalar
.getCoercing()
.parseLiteral(
invalidAddrValue,
CoercedVariables.emptyVariables(),
GraphQLContext.newContext().build(),
Locale.ENGLISH))
.isInstanceOf(CoercingParseLiteralException.class);
}

@ -19,6 +19,11 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy;
import org.hyperledger.besu.ethereum.api.graphql.internal.Scalars;
import java.util.Locale;
import graphql.GraphQLContext;
import graphql.execution.CoercedVariables;
import graphql.language.FloatValue;
import graphql.language.StringValue;
import graphql.schema.CoercingParseLiteralException;
import graphql.schema.CoercingParseValueException;
@ -38,43 +43,69 @@ public class BigIntScalarTest {
@Test
public void parseValueTest() {
final String result = (String) scalar.getCoercing().parseValue(value);
final String result =
(String)
scalar
.getCoercing()
.parseValue(value, GraphQLContext.newContext().build(), Locale.ENGLISH);
assertThat(result).isEqualTo(str);
}
@Test
public void parseValueErrorTest() {
assertThatThrownBy(() -> scalar.getCoercing().parseValue(3.2))
assertThatThrownBy(
() ->
scalar
.getCoercing()
.parseValue(3.2, GraphQLContext.newContext().build(), Locale.ENGLISH))
.isInstanceOf(CoercingParseValueException.class);
}
@Test
public void serializeTest() {
final String result = (String) scalar.getCoercing().serialize(value);
final String result =
(String)
scalar
.getCoercing()
.serialize(value, GraphQLContext.newContext().build(), Locale.ENGLISH);
assertThat(result).isEqualTo(str);
}
@Test
public void serializeErrorTest() {
assertThatThrownBy(() -> scalar.getCoercing().serialize(3.2))
assertThatThrownBy(
() ->
scalar
.getCoercing()
.serialize(3.2, GraphQLContext.newContext().build(), Locale.ENGLISH))
.isInstanceOf(CoercingSerializeException.class);
}
@Test
public void parseLiteralTest() {
final String result = (String) scalar.getCoercing().parseLiteral(value);
assertThat(result).isEqualTo(str);
}
@Test
public void parseLiteralErrorTest() {
assertThatThrownBy(() -> scalar.getCoercing().parseLiteral(3.2))
assertThatThrownBy(
() ->
scalar
.getCoercing()
.parseLiteral(
FloatValue.of(3.2),
CoercedVariables.emptyVariables(),
GraphQLContext.newContext().build(),
Locale.ENGLISH))
.isInstanceOf(CoercingParseLiteralException.class);
}
@Test
public void parseLiteralErrorTest2() {
assertThatThrownBy(() -> scalar.getCoercing().parseLiteral(invalidStrValue))
assertThatThrownBy(
() ->
scalar
.getCoercing()
.parseLiteral(
invalidStrValue,
CoercedVariables.emptyVariables(),
GraphQLContext.newContext().build(),
Locale.ENGLISH))
.isInstanceOf(CoercingParseLiteralException.class);
}

@ -19,6 +19,11 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy;
import org.hyperledger.besu.ethereum.api.graphql.internal.Scalars;
import java.util.Locale;
import graphql.GraphQLContext;
import graphql.execution.CoercedVariables;
import graphql.language.FloatValue;
import graphql.language.StringValue;
import graphql.schema.CoercingParseLiteralException;
import graphql.schema.CoercingParseValueException;
@ -39,43 +44,80 @@ public class Bytes32ScalarTest {
@Test
public void pareValueTest() {
final var result = scalar.getCoercing().parseValue(str);
final var result =
scalar.getCoercing().parseValue(str, GraphQLContext.newContext().build(), Locale.ENGLISH);
assertThat(result).isEqualTo(value);
}
@Test
public void parseValueErrorTest() {
assertThatThrownBy(() -> scalar.getCoercing().parseValue(3.2f))
assertThatThrownBy(
() ->
scalar
.getCoercing()
.parseValue(3.2f, GraphQLContext.newContext().build(), Locale.ENGLISH))
.isInstanceOf(CoercingParseValueException.class);
}
@Test
public void serializeTest() {
final String result = (String) scalar.getCoercing().serialize(value);
final String result =
(String)
scalar
.getCoercing()
.serialize(value, GraphQLContext.newContext().build(), Locale.ENGLISH);
assertThat(result).isEqualTo(str);
}
@Test
public void serializeErrorTest() {
assertThatThrownBy(() -> scalar.getCoercing().serialize(3.2f))
assertThatThrownBy(
() ->
scalar
.getCoercing()
.serialize(3.2f, GraphQLContext.newContext().build(), Locale.ENGLISH))
.isInstanceOf(CoercingSerializeException.class);
}
@Test
public void parseLiteralTest() {
final Bytes32 result = (Bytes32) scalar.getCoercing().parseLiteral(strValue);
final Bytes32 result =
(Bytes32)
scalar
.getCoercing()
.parseLiteral(
strValue,
CoercedVariables.emptyVariables(),
GraphQLContext.newContext().build(),
Locale.ENGLISH);
assertThat(result).isEqualTo(value);
}
@Test
public void parseLiteralErrorTest() {
assertThatThrownBy(() -> scalar.getCoercing().parseLiteral(3.2f))
assertThatThrownBy(
() ->
scalar
.getCoercing()
.parseLiteral(
FloatValue.of(3.2f),
CoercedVariables.emptyVariables(),
GraphQLContext.newContext().build(),
Locale.ENGLISH))
.isInstanceOf(CoercingParseLiteralException.class);
}
@Test
public void parseLiteralErrorTest2() {
assertThatThrownBy(() -> scalar.getCoercing().parseLiteral(invalidStrValue))
assertThatThrownBy(
() ->
scalar
.getCoercing()
.parseLiteral(
invalidStrValue,
CoercedVariables.emptyVariables(),
GraphQLContext.newContext().build(),
Locale.ENGLISH))
.isInstanceOf(CoercingParseLiteralException.class);
}

@ -19,6 +19,11 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy;
import org.hyperledger.besu.ethereum.api.graphql.internal.Scalars;
import java.util.Locale;
import graphql.GraphQLContext;
import graphql.execution.CoercedVariables;
import graphql.language.FloatValue;
import graphql.language.StringValue;
import graphql.schema.CoercingParseLiteralException;
import graphql.schema.CoercingParseValueException;
@ -39,43 +44,80 @@ public class BytesScalarTest {
@Test
public void parseValueTest() {
final var result = scalar.getCoercing().parseValue(str);
final var result =
scalar.getCoercing().parseValue(str, GraphQLContext.newContext().build(), Locale.ENGLISH);
assertThat(result).isEqualTo(value);
}
@Test
public void parseValueErrorTest() {
assertThatThrownBy(() -> scalar.getCoercing().parseValue(3.2f))
assertThatThrownBy(
() ->
scalar
.getCoercing()
.parseValue(3.2f, GraphQLContext.newContext().build(), Locale.ENGLISH))
.isInstanceOf(CoercingParseValueException.class);
}
@Test
public void serializeTest() {
final String result = (String) scalar.getCoercing().serialize(value);
final String result =
(String)
scalar
.getCoercing()
.serialize(value, GraphQLContext.newContext().build(), Locale.ENGLISH);
assertThat(result).isEqualTo(str);
}
@Test
public void serializeErrorTest() {
assertThatThrownBy(() -> scalar.getCoercing().serialize(3.2f))
assertThatThrownBy(
() ->
scalar
.getCoercing()
.serialize(3.2f, GraphQLContext.newContext().build(), Locale.ENGLISH))
.isInstanceOf(CoercingSerializeException.class);
}
@Test
public void parseLiteralTest() {
final Bytes result = (Bytes) scalar.getCoercing().parseLiteral(strValue);
final Bytes result =
(Bytes)
scalar
.getCoercing()
.parseLiteral(
strValue,
CoercedVariables.emptyVariables(),
GraphQLContext.newContext().build(),
Locale.ENGLISH);
assertThat(result).isEqualTo(value);
}
@Test
public void parseLiteralErrorTest() {
assertThatThrownBy(() -> scalar.getCoercing().parseLiteral(3.2f))
assertThatThrownBy(
() ->
scalar
.getCoercing()
.parseLiteral(
FloatValue.of(3.2f),
CoercedVariables.emptyVariables(),
GraphQLContext.newContext().build(),
Locale.ENGLISH))
.isInstanceOf(CoercingParseLiteralException.class);
}
@Test
public void parseLiteralErrorTest2() {
assertThatThrownBy(() -> scalar.getCoercing().parseLiteral(invalidStrValue))
assertThatThrownBy(
() ->
scalar
.getCoercing()
.parseLiteral(
invalidStrValue,
CoercedVariables.emptyVariables(),
GraphQLContext.newContext().build(),
Locale.ENGLISH))
.isInstanceOf(CoercingParseLiteralException.class);
}

@ -19,6 +19,10 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy;
import org.hyperledger.besu.ethereum.api.graphql.internal.Scalars;
import java.util.Locale;
import graphql.GraphQLContext;
import graphql.execution.CoercedVariables;
import graphql.language.StringValue;
import graphql.schema.CoercingParseLiteralException;
import graphql.schema.CoercingParseValueException;
@ -38,51 +42,101 @@ public class LongScalarTest {
@Test
public void parseLongValueTest() {
assertThat(scalar.getCoercing().parseValue(value)).isEqualTo(value);
assertThat(
scalar
.getCoercing()
.parseValue(value, GraphQLContext.newContext().build(), Locale.ENGLISH))
.isEqualTo(value);
}
@Test
public void parseStringValueTest() {
assertThat(scalar.getCoercing().parseValue(str)).isEqualTo(value);
assertThat(
scalar
.getCoercing()
.parseValue(str, GraphQLContext.newContext().build(), Locale.ENGLISH))
.isEqualTo(value);
}
@Test
public void parseValueErrorTest() {
assertThatThrownBy(() -> scalar.getCoercing().parseValue(invalidStrValue))
assertThatThrownBy(
() ->
scalar
.getCoercing()
.parseValue(
invalidStrValue, GraphQLContext.newContext().build(), Locale.ENGLISH))
.isInstanceOf(CoercingParseValueException.class);
}
@Test
public void serializeLongTest() {
assertThat(scalar.getCoercing().serialize(value)).isEqualTo(value);
assertThat(
scalar
.getCoercing()
.serialize(value, GraphQLContext.newContext().build(), Locale.ENGLISH))
.isEqualTo(value);
}
@Test
public void serializeStringTest() {
assertThat(scalar.getCoercing().serialize(str)).isEqualTo(value);
assertThat(
scalar
.getCoercing()
.serialize(str, GraphQLContext.newContext().build(), Locale.ENGLISH))
.isEqualTo(value);
}
@Test
public void serializeErrorTest() {
assertThatThrownBy(() -> scalar.getCoercing().serialize(invalidStrValue))
assertThatThrownBy(
() ->
scalar
.getCoercing()
.serialize(
invalidStrValue, GraphQLContext.newContext().build(), Locale.ENGLISH))
.isInstanceOf(CoercingSerializeException.class);
}
@Test
public void parseLiteralTest() {
final Long result = (Long) scalar.getCoercing().parseLiteral(strValue);
final Long result =
(Long)
scalar
.getCoercing()
.parseLiteral(
strValue,
CoercedVariables.emptyVariables(),
GraphQLContext.newContext().build(),
Locale.ENGLISH);
assertThat(result).isEqualTo(value);
}
@Test
public void parseLiteralErrorTest() {
assertThatThrownBy(() -> scalar.getCoercing().parseLiteral(str))
.isInstanceOf(CoercingParseLiteralException.class);
public void parseLiteralStringTest() {
final Long result =
(Long)
scalar
.getCoercing()
.parseLiteral(
strValue,
CoercedVariables.emptyVariables(),
GraphQLContext.newContext().build(),
Locale.ENGLISH);
assertThat(result).isEqualTo(value);
}
@Test
public void parseLiteralErrorTest2() {
assertThatThrownBy(() -> scalar.getCoercing().parseLiteral(invalidStrValue))
assertThatThrownBy(
() ->
scalar
.getCoercing()
.parseLiteral(
invalidStrValue,
CoercedVariables.emptyVariables(),
GraphQLContext.newContext().build(),
Locale.ENGLISH))
.isInstanceOf(CoercingParseLiteralException.class);
}

@ -0,0 +1,20 @@
{
"request":
"{ block (number: 33) { number withdrawalsRoot withdrawals { index amount validator address } } }",
"response": {
"data" : {
"block" : {
"number" : 33,
"withdrawalsRoot": "0x37945ab58d2712a26df2a38d217e822694927e29b30d5993d7a53ccea618d1f3",
"withdrawals": [{
"index": 0,
"amount": 10000000000,
"validator": 10,
"address": "0x0000000000000000000000000000000000000dad"
}]
}
}
},
"statusCode": 200
}

@ -0,0 +1,15 @@
{
"request":
"{ block (number: 32) { number withdrawalsRoot withdrawals { index amount } } }",
"response": {
"data" : {
"block" : {
"number" : 32,
"withdrawalsRoot": null,
"withdrawals": null
}
}
},
"statusCode": 200
}

@ -5,7 +5,7 @@
"response": {
"data" : {
"block" : {
"number" : 32
"number" : 33
}
}
},

@ -4,7 +4,7 @@
"response":{
"data" : {
"block" : {
"number" : 32,
"number" : 33,
"call" : {
"data" : "0x0000000000000000000000000000000000000000000000000000000000000001",
"status" : 1

@ -4,7 +4,7 @@
"response":{
"data" : {
"block" : {
"number" : 32,
"number" : 33,
"call" : {
"data" : "0x",
"status" : 1

@ -4,7 +4,7 @@
"response":{
"data" : {
"block" : {
"estimateGas" : 111953
"estimateGas" : 127129
}
}
},

@ -3,7 +3,7 @@
"response":{
"data" : {
"block" : {
"estimateGas" : 21204
"estimateGas" : 21048
}
}
},

@ -3,7 +3,7 @@
"response":{
"data" : {
"block" : {
"estimateGas" : 21000
"estimateGas" : 53000
}
}
},

@ -3,7 +3,9 @@
"response": {
"data": {
"pending": {
"account": null
"account": {
"balance": "0x0"
}
}
}
},

@ -1,9 +1,9 @@
{
"request": "{ block(number:\"0x21\") { account(address: \"0x6295ee1b4f6dd65047762f924ecd367c17eabf8f\") { balance } } }",
"request": "{ block(number:\"0x22\") { account(address: \"0x6295ee1b4f6dd65047762f924ecd367c17eabf8f\") { balance } } }",
"response": {
"errors": [
{
"message": "Exception while fetching data (/block) : Block number 33 was not found",
"message": "Exception while fetching data (/block) : Block number 34 was not found",
"locations": [
{
"line": 1,

@ -0,0 +1,29 @@
{
"request": "{block (number : 33) { baseFeePerGas difficulty extraData miner { address } mixHash nonce stateRoot totalDifficulty withdrawalsRoot withdrawals { address amount index validator } }} ",
"response":{
"data" : {
"block" : {
"baseFeePerGas": "0x3b9aca00",
"difficulty": "0x0",
"extraData": "0x",
"miner": {
"address": "0x0000000000000000000000000000000000000000"
},
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"nonce": "0x0000000000000000",
"stateRoot": "0x0d3c456bb68669bad05da3a1a766daab236c9df1da8f74edf5ebe9383f00084c",
"totalDifficulty": "0x427c00",
"withdrawalsRoot": "0x37945ab58d2712a26df2a38d217e822694927e29b30d5993d7a53ccea618d1f3",
"withdrawals": [
{
"address": "0x0000000000000000000000000000000000000dad",
"amount": 10000000000,
"index": 0,
"validator": 10
}
]
}
}
},
"statusCode": 200
}

@ -5,7 +5,7 @@
"data" : {
"pending": {
"account" :{
"transactionCount" : 32
"transactionCount" : 33
}
}
}

@ -0,0 +1,19 @@
{
"request": "{transaction (hash : \"0x3ecd2ca6cf26c864d0ea5f038a58d4cd4a46a3e242fe92f446f392fdc232dd98\") { accessList { address storageKeys } maxFeePerGas maxPriorityFeePerGas nonce type status } } ",
"response": {
"data": {
"transaction": {
"accessList": [{
"address": "0x6295ee1b4f6dd65047762f924ecd367c17eabf8f",
"storageKeys": ["0x0000000000000000000000000000000000000000000000000000000000000000"]
}],
"maxFeePerGas": "0xb2d05e00",
"maxPriorityFeePerGas": "0x3b9aca00",
"nonce": 32,
"type": 2,
"status": 1
}
}
},
"statusCode": 200
}

@ -15,7 +15,7 @@
"account": {
"balance": "0x140"
},
"estimateGas": 21000,
"estimateGas": 53000,
"call": {
"data": "0x0000000000000000000000000000000000000000000000000000000000000001",
"status": 1

@ -32,8 +32,14 @@ import com.google.common.io.Resources;
/** The Block test util. */
public final class BlockTestUtil {
private BlockTestUtil() {
throw new RuntimeException("Utility Class");
}
private static final Supplier<ChainResources> testChainSupplier =
Suppliers.memoize(BlockTestUtil::supplyTestChainResources);
private static final Supplier<ChainResources> hiveTestChainSupplier =
Suppliers.memoize(BlockTestUtil::supplyHiveTestChainResources);
private static final Supplier<ChainResources> testChainLondonSupplier =
Suppliers.memoize(BlockTestUtil::supplyTestChainLondonResources);
private static final Supplier<ChainResources> mainnetChainSupplier =
@ -92,6 +98,15 @@ public final class BlockTestUtil {
return testChainSupplier.get();
}
/**
* Gets test chain resources for hive tests.
*
* @return the test chain resources
*/
public static ChainResources getHiveTestChainResources() {
return hiveTestChainSupplier.get();
}
/**
* Gets test chain london resources.
*
@ -148,6 +163,15 @@ public final class BlockTestUtil {
return new ChainResources(genesisURL, blocksURL);
}
private static ChainResources supplyHiveTestChainResources() {
final URL genesisURL =
ensureFileUrl(BlockTestUtil.class.getClassLoader().getResource("hive/testGenesis.json"));
final URL blocksURL =
ensureFileUrl(
BlockTestUtil.class.getClassLoader().getResource("hive/testBlockchain.blocks"));
return new ChainResources(genesisURL, blocksURL);
}
private static ChainResources supplyTestChainLondonResources() {
final URL genesisURL =
ensureFileUrl(

@ -0,0 +1,22 @@
{
"config": {
"chainId": 1,
"ethash": {
},
"londonBlock": 33,
"shanghaiTime": 1444660030
},
"parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
"coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1",
"difficulty" : "0x020000",
"gasLimit" : "0x2fefd8",
"timestamp" : "0x54c98c81",
"extraData" : "0x42",
"mixHash" : "0x2c85bcbce56429100b2108254bb56906257582aeafcbd682bc9af67a9f5aee46",
"nonce" : "0x78cc16f7b4f65485",
"alloc" : {
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b": {
"balance" : "0x09184e72a000"
}
}
}
Loading…
Cancel
Save