diff --git a/CHANGELOG.md b/CHANGELOG.md index 2821eab33..17bd4f09e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/Scalars.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/Scalars.java index bfaf092b3..251f4815b 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/Scalars.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/Scalars.java @@ -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_COERCING = new Coercing() { 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 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 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 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 LONG_COERCING = - new Coercing() { + 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 { diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/AccountAdapter.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/AccountAdapter.java index f49d709b2..c8acb708a 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/AccountAdapter.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/AccountAdapter.java @@ -41,24 +41,26 @@ public class AccountAdapter extends AdapterBase { this.address = address; } - public Optional
getAddress() { - return Optional.of(address); + public Address getAddress() { + return address; } - public Optional getBalance() { - return account.map(AccountState::getBalance).or(() -> Optional.of(Wei.ZERO)); + public Wei getBalance() { + return account.map(AccountState::getBalance).orElse(Wei.ZERO); } - public Optional getTransactionCount() { - return account.map(AccountState::getNonce).or(() -> Optional.of(0L)); + public Long getTransactionCount() { + return account.map(AccountState::getNonce).orElse(0L); } - public Optional getCode() { - return account.map(AccountState::getCode); + public Bytes getCode() { + return account.map(AccountState::getCode).orElse(Bytes.EMPTY); } - public Optional 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); } } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/BlockAdapterBase.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/BlockAdapterBase.java index 9a22dedd5..2b8251ce8 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/BlockAdapterBase.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/BlockAdapterBase.java @@ -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 getHash() { - return Optional.of(header.getHash()); + public Bytes32 getHash() { + return header.getHash(); } - public Optional 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 getTransactionsRoot() { - return Optional.of(header.getTransactionsRoot()); + public Bytes32 getTransactionsRoot() { + return header.getTransactionsRoot(); } - public Optional getStateRoot() { - return Optional.of(header.getStateRoot()); + public Bytes32 getStateRoot() { + return header.getStateRoot(); } - public Optional getReceiptsRoot() { - return Optional.of(header.getReceiptsRoot()); + public Bytes32 getReceiptsRoot() { + return header.getReceiptsRoot(); } - public Optional 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 getExtraData() { - return Optional.of(header.getExtraData()); + public Bytes getExtraData() { + return header.getExtraData(); } public Optional getBaseFeePerGas() { return header.getBaseFee(); } - public Optional getGasLimit() { - return Optional.of(header.getGasLimit()); + public Long getGasLimit() { + return header.getGasLimit(); } - public Optional getGasUsed() { - return Optional.of(header.getGasUsed()); + public Long getGasUsed() { + return header.getGasUsed(); } - public Optional getTimestamp() { - return Optional.of(header.getTimestamp()); + public Long getTimestamp() { + return header.getTimestamp(); } - public Optional getLogsBloom() { - return Optional.of(header.getLogsBloom()); + public Bytes getLogsBloom() { + return header.getLogsBloom(); } - public Optional getMixHash() { - return Optional.of(header.getMixHash()); + public Bytes32 getMixHash() { + return header.getMixHash(); } - public Optional getDifficulty() { - return Optional.of(header.getDifficulty()); + public Difficulty getDifficulty() { + return header.getDifficulty(); } - public Optional getOmmerHash() { - return Optional.of(header.getOmmersHash()); + public Bytes32 getOmmerHash() { + return header.getOmmersHash(); } - public Optional getNumber() { - final long bn = header.getNumber(); - return Optional.of(bn); + public Long getNumber() { + return header.getNumber(); } - public Optional 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 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 getEstimateGas(final DataFetchingEnvironment environment) { + public Long getEstimateGas(final DataFetchingEnvironment environment) { final Optional result = executeCall(environment); - return result.map(CallResult::getGasUsed); + return result.map(CallResult::getGasUsed).orElse(0L); } public Optional 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 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 getRawHeader() { + Bytes getRawHeader() { final BytesValueRLPOutput rlpOutput = new BytesValueRLPOutput(); header.writeTo(rlpOutput); - return Optional.of(rlpOutput.encoded()); + return rlpOutput.encoded(); } - Optional 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 getWithdrawalsRoot() { + return header.getWithdrawalsRoot().map(Function.identity()); + } + + Optional> 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())); } } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/EmptyAccountAdapter.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/EmptyAccountAdapter.java index ecb16a82a..7fc6d7695 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/EmptyAccountAdapter.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/EmptyAccountAdapter.java @@ -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
getAddress() { - return Optional.of(address); + public Address getAddress() { + return address; } @Override - public Optional getBalance() { - return Optional.of(Wei.ZERO); + public Wei getBalance() { + return Wei.ZERO; } @Override - public Optional getTransactionCount() { - return Optional.of(0L); + public Long getTransactionCount() { + return 0L; } @Override - public Optional getCode() { - return Optional.of(Bytes.EMPTY); + public Bytes getCode() { + return Bytes.EMPTY; } @Override - public Optional getStorage(final DataFetchingEnvironment environment) { - return Optional.of(Bytes32.ZERO); + public Bytes32 getStorage(final DataFetchingEnvironment environment) { + return Bytes32.ZERO; } } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/LogAdapter.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/LogAdapter.java index 20c1e31fe..10357de0c 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/LogAdapter.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/LogAdapter.java @@ -35,8 +35,8 @@ public class LogAdapter extends AdapterBase { this.logWithMetadata = logWithMetadata; } - public Optional getIndex() { - return Optional.of(logWithMetadata.getLogIndex()); + public Integer getIndex() { + return logWithMetadata.getLogIndex(); } public List getTopics() { @@ -44,18 +44,18 @@ public class LogAdapter extends AdapterBase { return new ArrayList<>(topics); } - public Optional getData() { - return Optional.of(logWithMetadata.getData()); + public Bytes getData() { + return logWithMetadata.getData(); } - public Optional getTransaction(final DataFetchingEnvironment environment) { + public TransactionAdapter getTransaction(final DataFetchingEnvironment environment) { final BlockchainQueries query = getBlockchainQueries(environment); final Hash hash = logWithMetadata.getTransactionHash(); final Optional tran = query.transactionByHash(hash); - return tran.map(TransactionAdapter::new); + return tran.map(TransactionAdapter::new).orElseThrow(); } - public Optional 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(); } } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/NormalBlockAdapter.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/NormalBlockAdapter.java index 0245b404c..f54b3f0da 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/NormalBlockAdapter.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/NormalBlockAdapter.java @@ -42,8 +42,8 @@ public class NormalBlockAdapter extends BlockAdapterBase { return Optional.of(blockWithMetaData.getTransactions().size()); } - public Optional getTotalDifficulty() { - return Optional.of(blockWithMetaData.getTotalDifficulty()); + public Difficulty getTotalDifficulty() { + return blockWithMetaData.getTotalDifficulty(); } public Optional getOmmerCount() { @@ -65,7 +65,7 @@ public class NormalBlockAdapter extends BlockAdapterBase { public Optional 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 ommers = blockWithMetaData.getOmmers(); if (ommers.size() > index) { final Hash hash = blockWithMetaData.getHeader().getHash(); @@ -85,7 +85,7 @@ public class NormalBlockAdapter extends BlockAdapterBase { } public Optional getTransactionAt(final DataFetchingEnvironment environment) { - final int index = environment.getArgument("index"); + final int index = ((Number) environment.getArgument("index")).intValue(); final List trans = blockWithMetaData.getTransactions(); if (trans.size() > index) { diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/PendingStateAdapter.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/PendingStateAdapter.java index f3462f420..fbdfb54ae 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/PendingStateAdapter.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/PendingStateAdapter.java @@ -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 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 opt = transactionSimulator.processAtHead(param); + ImmutableTransactionValidationParams.Builder transactionValidationParams = + ImmutableTransactionValidationParams.builder() + .from(TransactionValidationParams.transactionSimulator()); + transactionValidationParams.isAllowExceedingBalance(true); + + final Optional opt = + transactionSimulator.process( + param, + transactionValidationParams.build(), + OperationTracer.NO_TRACING, + query.getBlockchain().getChainHeadHeader()); + if (opt.isPresent()) { final TransactionSimulatorResult result = opt.get(); long status = 0; diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/SyncStateAdapter.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/SyncStateAdapter.java index ddbad14bf..0a8dcbbf9 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/SyncStateAdapter.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/SyncStateAdapter.java @@ -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 getStartingBlock() { - return Optional.of(syncStatus.getStartingBlock()); + public Long getStartingBlock() { + return syncStatus.getStartingBlock(); } - public Optional getCurrentBlock() { - return Optional.of(syncStatus.getCurrentBlock()); + public Long getCurrentBlock() { + return syncStatus.getCurrentBlock(); } - public Optional getHighestBlock() { - return Optional.of(syncStatus.getHighestBlock()); + public Long getHighestBlock() { + return syncStatus.getHighestBlock(); } } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/TransactionAdapter.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/TransactionAdapter.java index f77c5f724..49c1da5da 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/TransactionAdapter.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/TransactionAdapter.java @@ -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 getHash() { - return Optional.of(transactionWithMetadata.getTransaction().getHash()); + public Hash getHash() { + return transactionWithMetadata.getTransaction().getHash(); } public Optional getType() { return Optional.of(transactionWithMetadata.getTransaction().getType().ordinal()); } - public Optional getNonce() { - final long nonce = transactionWithMetadata.getTransaction().getNonce(); - return Optional.of(nonce); + public Long getNonce() { + return transactionWithMetadata.getTransaction().getNonce(); } public Optional getIndex() { return transactionWithMetadata.getTransactionIndex(); } - public Optional 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 getTo(final DataFetchingEnvironment environment) { @@ -105,12 +106,12 @@ public class TransactionAdapter extends AdapterBase { .map(address -> new AccountAdapter(address, ws.get(address)))); } - public Optional getValue() { - return Optional.of(transactionWithMetadata.getTransaction().getValue()); + public Wei getValue() { + return transactionWithMetadata.getTransaction().getValue(); } - public Optional getGasPrice() { - return transactionWithMetadata.getTransaction().getGasPrice(); + public Wei getGasPrice() { + return transactionWithMetadata.getTransaction().getGasPrice().orElse(Wei.ZERO); } public Optional getMaxPriorityFeePerGas() { @@ -126,12 +127,17 @@ public class TransactionAdapter extends AdapterBase { .map(rwm -> rwm.getTransaction().getEffectiveGasPrice(rwm.getBaseFee())); } - public Optional getGas() { - return Optional.of(transactionWithMetadata.getTransaction().getGasLimit()); + public Optional getEffectiveTip(final DataFetchingEnvironment environment) { + return getReceipt(environment) + .map(rwm -> rwm.getTransaction().getEffectivePriorityFeePerGas(rwm.getBaseFee())); } - public Optional getInputData() { - return Optional.of(transactionWithMetadata.getTransaction().getPayload()); + public Long getGas() { + return transactionWithMetadata.getTransaction().getGasLimit(); + } + + public Bytes getInputData() { + return transactionWithMetadata.getTransaction().getPayload(); } public Optional 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()); } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/UncleBlockAdapter.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/UncleBlockAdapter.java index c0e273682..8d9e947ee 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/UncleBlockAdapter.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/UncleBlockAdapter.java @@ -33,8 +33,8 @@ class UncleBlockAdapter extends BlockAdapterBase { return Optional.of(0); } - public Optional getTotalDifficulty() { - return Optional.of(UInt256.ZERO); + public UInt256 getTotalDifficulty() { + return UInt256.ZERO; } public Optional getOmmerCount() { diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/WithdrawalAdapter.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/WithdrawalAdapter.java new file mode 100644 index 000000000..86782b6af --- /dev/null +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/WithdrawalAdapter.java @@ -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(); + } +} diff --git a/ethereum/api/src/main/resources/schema.graphqls b/ethereum/api/src/main/resources/schema.graphqls index 01e20f95d..183bce31e 100644 --- a/ethereum/api/src/main/resources/schema.graphqls +++ b/ethereum/api/src/main/resources/schema.graphqls @@ -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! } \ No newline at end of file diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/AbstractEthGraphQLHttpServiceTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/AbstractEthGraphQLHttpServiceTest.java index cb8c253ad..7f41af9ab 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/AbstractEthGraphQLHttpServiceTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/AbstractEthGraphQLHttpServiceTest.java @@ -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 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); - } } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/BlockDataFetcherTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/BlockDataFetcherTest.java index fbce73301..b41bb1754 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/BlockDataFetcherTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/BlockDataFetcherTest.java @@ -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 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); } } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/EthGraphQLHttpBySpecTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/EthGraphQLHttpBySpecTest.java index a2280923d..7beef9c52 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/EthGraphQLHttpBySpecTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/EthGraphQLHttpBySpecTest.java @@ -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); - } - } } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/scalar/AddressScalarTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/scalar/AddressScalarTest.java index 87153b490..b6f978892 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/scalar/AddressScalarTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/scalar/AddressScalarTest.java @@ -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); } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/scalar/BigIntScalarTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/scalar/BigIntScalarTest.java index 06fcfa42c..d1c4751bd 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/scalar/BigIntScalarTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/scalar/BigIntScalarTest.java @@ -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); } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/scalar/Bytes32ScalarTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/scalar/Bytes32ScalarTest.java index 47e516c3b..4583ecac3 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/scalar/Bytes32ScalarTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/scalar/Bytes32ScalarTest.java @@ -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); } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/scalar/BytesScalarTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/scalar/BytesScalarTest.java index 39ca321c3..ae7204833 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/scalar/BytesScalarTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/scalar/BytesScalarTest.java @@ -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); } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/scalar/LongScalarTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/scalar/LongScalarTest.java index d693d6e2c..119ce81ce 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/scalar/LongScalarTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/scalar/LongScalarTest.java @@ -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); } diff --git a/ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/graphql/block_withdrawals.json b/ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/graphql/block_withdrawals.json new file mode 100644 index 000000000..024f465a3 --- /dev/null +++ b/ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/graphql/block_withdrawals.json @@ -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 +} \ No newline at end of file diff --git a/ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/graphql/block_withdrawals_pre_shanghai.json b/ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/graphql/block_withdrawals_pre_shanghai.json new file mode 100644 index 000000000..dd50acb5f --- /dev/null +++ b/ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/graphql/block_withdrawals_pre_shanghai.json @@ -0,0 +1,15 @@ +{ + "request": + "{ block (number: 32) { number withdrawalsRoot withdrawals { index amount } } }", + + "response": { + "data" : { + "block" : { + "number" : 32, + "withdrawalsRoot": null, + "withdrawals": null + } + } + }, + "statusCode": 200 +} \ No newline at end of file diff --git a/ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/graphql/eth_blockNumber.json b/ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/graphql/eth_blockNumber.json index b3b736185..b061e7e65 100644 --- a/ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/graphql/eth_blockNumber.json +++ b/ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/graphql/eth_blockNumber.json @@ -5,7 +5,7 @@ "response": { "data" : { "block" : { - "number" : 32 + "number" : 33 } } }, diff --git a/ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/graphql/eth_call_BlockLatest.json b/ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/graphql/eth_call_BlockLatest.json index 7478c29a7..7c4a16df7 100644 --- a/ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/graphql/eth_call_BlockLatest.json +++ b/ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/graphql/eth_call_BlockLatest.json @@ -4,7 +4,7 @@ "response":{ "data" : { "block" : { - "number" : 32, + "number" : 33, "call" : { "data" : "0x0000000000000000000000000000000000000000000000000000000000000001", "status" : 1 diff --git a/ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/graphql/eth_call_from_contract.json b/ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/graphql/eth_call_from_contract.json index 1bafc66fd..9904c248c 100644 --- a/ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/graphql/eth_call_from_contract.json +++ b/ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/graphql/eth_call_from_contract.json @@ -4,7 +4,7 @@ "response":{ "data" : { "block" : { - "number" : 32, + "number" : 33, "call" : { "data" : "0x", "status" : 1 diff --git a/ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/graphql/eth_estimateGas_contractDeploy.json b/ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/graphql/eth_estimateGas_contractDeploy.json index 816ab74aa..fda239251 100644 --- a/ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/graphql/eth_estimateGas_contractDeploy.json +++ b/ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/graphql/eth_estimateGas_contractDeploy.json @@ -4,7 +4,7 @@ "response":{ "data" : { "block" : { - "estimateGas" : 111953 + "estimateGas" : 127129 } } }, diff --git a/ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/graphql/eth_estimateGas_from_contract.json b/ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/graphql/eth_estimateGas_from_contract.json index 4c3135d72..776b5e0be 100644 --- a/ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/graphql/eth_estimateGas_from_contract.json +++ b/ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/graphql/eth_estimateGas_from_contract.json @@ -3,7 +3,7 @@ "response":{ "data" : { "block" : { - "estimateGas" : 21204 + "estimateGas" : 21048 } } }, diff --git a/ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/graphql/eth_estimateGas_noParams.json b/ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/graphql/eth_estimateGas_noParams.json index 251bd7ebe..60a6408ae 100644 --- a/ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/graphql/eth_estimateGas_noParams.json +++ b/ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/graphql/eth_estimateGas_noParams.json @@ -3,7 +3,7 @@ "response":{ "data" : { "block" : { - "estimateGas" : 21000 + "estimateGas" : 53000 } } }, diff --git a/ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/graphql/eth_getBalance_invalidAccountLatest.json b/ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/graphql/eth_getBalance_invalidAccountLatest.json index b5e1f90cc..90c599967 100644 --- a/ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/graphql/eth_getBalance_invalidAccountLatest.json +++ b/ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/graphql/eth_getBalance_invalidAccountLatest.json @@ -3,7 +3,9 @@ "response": { "data": { "pending": { - "account": null + "account": { + "balance": "0x0" + } } } }, diff --git a/ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/graphql/eth_getBalance_toobig_bn.json b/ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/graphql/eth_getBalance_toobig_bn.json index bd1260f84..cbc24c848 100644 --- a/ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/graphql/eth_getBalance_toobig_bn.json +++ b/ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/graphql/eth_getBalance_toobig_bn.json @@ -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, diff --git a/ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/graphql/eth_getBlock_shanghai.json b/ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/graphql/eth_getBlock_shanghai.json new file mode 100644 index 000000000..099460a8e --- /dev/null +++ b/ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/graphql/eth_getBlock_shanghai.json @@ -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 +} diff --git a/ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/graphql/eth_getTransactionCount.json b/ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/graphql/eth_getTransactionCount.json index ab563cf8a..990fbf747 100644 --- a/ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/graphql/eth_getTransactionCount.json +++ b/ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/graphql/eth_getTransactionCount.json @@ -5,7 +5,7 @@ "data" : { "pending": { "account" :{ - "transactionCount" : 32 + "transactionCount" : 33 } } } diff --git a/ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/graphql/eth_getTransaction_type2.json b/ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/graphql/eth_getTransaction_type2.json new file mode 100644 index 000000000..b910e159c --- /dev/null +++ b/ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/graphql/eth_getTransaction_type2.json @@ -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 +} \ No newline at end of file diff --git a/ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/graphql/graphql_blocks_byFrom.json b/ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/graphql/graphql_blocks_byFrom.json index 4e6c33d3f..7ba8b74a4 100644 --- a/ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/graphql/graphql_blocks_byFrom.json +++ b/ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/graphql/graphql_blocks_byFrom.json @@ -11,6 +11,9 @@ }, { "number": 32 + }, + { + "number": 33 } ] } diff --git a/ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/graphql/graphql_pending.json b/ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/graphql/graphql_pending.json index 46cad8c1c..c12410e10 100644 --- a/ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/graphql/graphql_pending.json +++ b/ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/graphql/graphql_pending.json @@ -15,7 +15,7 @@ "account": { "balance": "0x140" }, - "estimateGas": 21000, + "estimateGas": 53000, "call": { "data": "0x0000000000000000000000000000000000000000000000000000000000000001", "status": 1 diff --git a/testutil/src/main/java/org/hyperledger/besu/testutil/BlockTestUtil.java b/testutil/src/main/java/org/hyperledger/besu/testutil/BlockTestUtil.java index 4975cbee0..d2909a84f 100644 --- a/testutil/src/main/java/org/hyperledger/besu/testutil/BlockTestUtil.java +++ b/testutil/src/main/java/org/hyperledger/besu/testutil/BlockTestUtil.java @@ -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 testChainSupplier = Suppliers.memoize(BlockTestUtil::supplyTestChainResources); + private static final Supplier hiveTestChainSupplier = + Suppliers.memoize(BlockTestUtil::supplyHiveTestChainResources); private static final Supplier testChainLondonSupplier = Suppliers.memoize(BlockTestUtil::supplyTestChainLondonResources); private static final Supplier 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( diff --git a/testutil/src/main/resources/hive/testBlockchain.blocks b/testutil/src/main/resources/hive/testBlockchain.blocks new file mode 100644 index 000000000..480efc87d Binary files /dev/null and b/testutil/src/main/resources/hive/testBlockchain.blocks differ diff --git a/testutil/src/main/resources/hive/testGenesis.json b/testutil/src/main/resources/hive/testGenesis.json new file mode 100644 index 000000000..248f0933d --- /dev/null +++ b/testutil/src/main/resources/hive/testGenesis.json @@ -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" + } + } +} \ No newline at end of file