Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

recognize from and to block parameters in eth subscribe #826

Merged
merged 10 commits into from
May 3, 2020
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.LogsResult;
import org.hyperledger.besu.ethereum.api.query.BlockchainQueries;
import org.hyperledger.besu.ethereum.api.query.LogsQuery;
import org.hyperledger.besu.ethereum.core.LogWithMetadata;

import java.util.List;

public class EthGetLogs implements JsonRpcMethod {

Expand All @@ -41,30 +43,26 @@ public String getName() {
@Override
public JsonRpcResponse response(final JsonRpcRequestContext requestContext) {
final FilterParameter filter = requestContext.getRequiredParameter(0, FilterParameter.class);
final LogsQuery query =
new LogsQuery.Builder().addresses(filter.getAddresses()).topics(filter.getTopics()).build();

if (isValid(filter)) {
if (!filter.isValid()) {
return new JsonRpcErrorResponse(
requestContext.getRequest().getId(), JsonRpcError.INVALID_PARAMS);
}
if (filter.getBlockhash() != null) {
return new JsonRpcSuccessResponse(
requestContext.getRequest().getId(),
new LogsResult(blockchain.matchingLogs(filter.getBlockhash(), query)));
}

final long fromBlockNumber = filter.getFromBlock().getNumber().orElse(0);
final long toBlockNumber = filter.getToBlock().getNumber().orElse(blockchain.headBlockNumber());
final List<LogWithMetadata> matchingLogs =
filter
.getBlockHash()
.map(blockHash -> blockchain.matchingLogs(blockHash, filter.getLogsQuery()))
.orElseGet(
() -> {
final long fromBlockNumber = filter.getFromBlock().getNumber().orElse(0);
Copy link
Member

Choose a reason for hiding this comment

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

I think we should update this to be the headBlockNumber as well. This seems to be the "default" for Geth APIs. And probably update the PrivGetLogs as well.

I'm happy to do this in another PR is you don't wanna mix up with the other changes! :)

https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_getlogs

final long toBlockNumber =
filter.getToBlock().getNumber().orElse(blockchain.headBlockNumber());
return blockchain.matchingLogs(
fromBlockNumber, toBlockNumber, filter.getLogsQuery());
});

return new JsonRpcSuccessResponse(
requestContext.getRequest().getId(),
new LogsResult(blockchain.matchingLogs(fromBlockNumber, toBlockNumber, query)));
}

private boolean isValid(final FilterParameter filter) {
return !filter.getFromBlock().isLatest()
&& !filter.getToBlock().isLatest()
&& filter.getBlockhash() != null;
requestContext.getRequest().getId(), new LogsResult(matchingLogs));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,10 @@
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.filter.FilterManager;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.FilterParameter;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse;
import org.hyperledger.besu.ethereum.api.query.LogsQuery;

public class EthNewFilter implements JsonRpcMethod {

Expand All @@ -38,11 +39,15 @@ public String getName() {
@Override
public JsonRpcResponse response(final JsonRpcRequestContext requestContext) {
final FilterParameter filter = requestContext.getRequiredParameter(0, FilterParameter.class);
final LogsQuery query =
new LogsQuery.Builder().addresses(filter.getAddresses()).topics(filter.getTopics()).build();

if (!filter.isValid()) {
return new JsonRpcErrorResponse(
requestContext.getRequest().getId(), JsonRpcError.INVALID_PARAMS);
}

final String logFilterId =
filterManager.installLogFilter(filter.getFromBlock(), filter.getToBlock(), query);
filterManager.installLogFilter(
filter.getFromBlock(), filter.getToBlock(), filter.getLogsQuery());

return new JsonRpcSuccessResponse(requestContext.getRequest().getId(), logFilterId);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ public class BlockParameter {

private final BlockParameterType type;
private final OptionalLong number;
public static final BlockParameter EARLIEST = new BlockParameter("earliest");
public static final BlockParameter LATEST = new BlockParameter("latest");
public static final BlockParameter PENDING = new BlockParameter("pending");

@JsonCreator
public BlockParameter(final String value) {
Expand All @@ -48,6 +51,11 @@ public BlockParameter(final String value) {
}
}

public BlockParameter(final long value) {
type = BlockParameterType.NUMERIC;
number = OptionalLong.of(value);
}

public OptionalLong getNumber() {
return number;
}
Expand All @@ -68,6 +76,24 @@ public boolean isNumeric() {
return this.type == BlockParameterType.NUMERIC;
}

@Override
public String toString() {
return "BlockParameter{" + "type=" + type + ", number=" + number + '}';
}

@Override
public boolean equals(final Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
BlockParameter that = (BlockParameter) o;
return type == that.type && number.equals(that.number);
}

@Override
public int hashCode() {
return Objects.hash(type, number);
}

private enum BlockParameterType {
EARLIEST,
LATEST,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,14 @@

import static java.util.Collections.emptyList;

import org.hyperledger.besu.ethereum.api.query.LogsQuery;
import org.hyperledger.besu.ethereum.core.Address;
import org.hyperledger.besu.ethereum.core.Hash;
import org.hyperledger.besu.ethereum.core.LogTopic;

import java.util.List;
import java.util.Objects;
import java.util.Optional;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonFormat;
Expand All @@ -34,23 +37,26 @@ public class FilterParameter {
private final BlockParameter toBlock;
private final List<Address> addresses;
private final List<List<LogTopic>> topics;
private final Hash blockhash;
private final Optional<Hash> maybeBlockHash;
private final LogsQuery logsQuery;
private final boolean isValid;

@JsonCreator
public FilterParameter(
@JsonProperty("fromBlock") final String fromBlock,
@JsonProperty("toBlock") final String toBlock,
@JsonProperty("fromBlock") final BlockParameter fromBlock,
@JsonProperty("toBlock") final BlockParameter toBlock,
@JsonFormat(with = JsonFormat.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY) @JsonProperty("address")
final List<Address> address,
@JsonDeserialize(using = TopicsDeserializer.class) @JsonProperty("topics")
final List<List<LogTopic>> topics,
@JsonProperty("blockhash") final String blockhash) {
this.fromBlock =
fromBlock != null ? new BlockParameter(fromBlock) : new BlockParameter("latest");
this.toBlock = toBlock != null ? new BlockParameter(toBlock) : new BlockParameter("latest");
@JsonProperty("blockhash") final Hash blockHash) {
this.isValid = blockHash == null || (fromBlock == null && toBlock == null);
this.fromBlock = fromBlock != null ? fromBlock : BlockParameter.LATEST;
this.toBlock = toBlock != null ? toBlock : BlockParameter.LATEST;
this.addresses = address != null ? address : emptyList();
this.topics = topics != null ? topics : emptyList();
this.blockhash = blockhash != null ? Hash.fromHexString(blockhash) : null;
this.logsQuery = new LogsQuery(addresses, topics);
this.maybeBlockHash = Optional.ofNullable(blockHash);
}

public BlockParameter getFromBlock() {
Expand All @@ -69,16 +75,30 @@ public List<List<LogTopic>> getTopics() {
return topics;
}

public Hash getBlockhash() {
return blockhash;
public Optional<Hash> getBlockHash() {
return maybeBlockHash;
}

public boolean isValid() {
if (!getFromBlock().isLatest() && !getToBlock().isLatest() && getBlockhash() != null) {
return false;
}
public LogsQuery getLogsQuery() {
return logsQuery;
}

return true;
@Override
public boolean equals(final Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
FilterParameter that = (FilterParameter) o;
return fromBlock.equals(that.fromBlock)
&& toBlock.equals(that.toBlock)
&& addresses.equals(that.addresses)
&& topics.equals(that.topics)
&& maybeBlockHash.equals(that.maybeBlockHash)
&& logsQuery.equals(that.logsQuery);
}

@Override
public int hashCode() {
return Objects.hash(fromBlock, toBlock, addresses, topics, maybeBlockHash, logsQuery);
}

@Override
Expand All @@ -88,7 +108,11 @@ public String toString() {
.add("toBlock", toBlock)
.add("addresses", addresses)
.add("topics", topics)
.add("blockhash", blockhash)
.add("blockHash", maybeBlockHash)
.toString();
}

public boolean isValid() {
return isValid;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,12 @@
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.LogsResult;
import org.hyperledger.besu.ethereum.api.query.BlockchainQueries;
import org.hyperledger.besu.ethereum.api.query.LogsQuery;
import org.hyperledger.besu.ethereum.api.query.PrivacyQueries;
import org.hyperledger.besu.ethereum.core.LogWithMetadata;
import org.hyperledger.besu.ethereum.privacy.PrivacyController;

import java.util.List;

public class PrivGetLogs implements JsonRpcMethod {

private final BlockchainQueries blockchainQueries;
Expand All @@ -53,34 +55,34 @@ public String getName() {
}

@Override
public JsonRpcResponse response(final JsonRpcRequestContext request) {
final String privacyGroupId = request.getRequiredParameter(0, String.class);
final FilterParameter filter = request.getRequiredParameter(1, FilterParameter.class);
public JsonRpcResponse response(final JsonRpcRequestContext requestContext) {
final String privacyGroupId = requestContext.getRequiredParameter(0, String.class);
final FilterParameter filter = requestContext.getRequiredParameter(1, FilterParameter.class);

checkIfPrivacyGroupMatchesAuthenticatedEnclaveKey(request, privacyGroupId);
checkIfPrivacyGroupMatchesAuthenticatedEnclaveKey(requestContext, privacyGroupId);

if (!filter.isValid()) {
return new JsonRpcErrorResponse(request.getRequest().getId(), JsonRpcError.INVALID_PARAMS);
}

final LogsQuery query =
new LogsQuery.Builder().addresses(filter.getAddresses()).topics(filter.getTopics()).build();

if (filter.getBlockhash() != null) {
return new JsonRpcSuccessResponse(
request.getRequest().getId(),
new LogsResult(
privacyQueries.matchingLogs(privacyGroupId, filter.getBlockhash(), query)));
return new JsonRpcErrorResponse(
requestContext.getRequest().getId(), JsonRpcError.INVALID_PARAMS);
}

final long fromBlockNumber = filter.getFromBlock().getNumber().orElse(0);
final long toBlockNumber =
filter.getToBlock().getNumber().orElse(blockchainQueries.headBlockNumber());
final List<LogWithMetadata> matchingLogs =
filter
.getBlockHash()
.map(
blockHash ->
privacyQueries.matchingLogs(privacyGroupId, blockHash, filter.getLogsQuery()))
.orElseGet(
() -> {
final long fromBlockNumber = filter.getFromBlock().getNumber().orElse(0);
final long toBlockNumber =
filter.getToBlock().getNumber().orElse(blockchainQueries.headBlockNumber());
return privacyQueries.matchingLogs(
privacyGroupId, fromBlockNumber, toBlockNumber, filter.getLogsQuery());
});

return new JsonRpcSuccessResponse(
request.getRequest().getId(),
new LogsResult(
privacyQueries.matchingLogs(privacyGroupId, fromBlockNumber, toBlockNumber, query)));
requestContext.getRequest().getId(), new LogsResult(matchingLogs));
}

private void checkIfPrivacyGroupMatchesAuthenticatedEnclaveKey(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse;
import org.hyperledger.besu.ethereum.api.query.LogsQuery;
import org.hyperledger.besu.ethereum.privacy.PrivacyController;

public class PrivNewFilter implements JsonRpcMethod {
Expand Down Expand Up @@ -58,12 +57,9 @@ public JsonRpcResponse response(final JsonRpcRequestContext request) {
return new JsonRpcErrorResponse(request.getRequest().getId(), JsonRpcError.INVALID_PARAMS);
}

final LogsQuery query =
new LogsQuery.Builder().addresses(filter.getAddresses()).topics(filter.getTopics()).build();

final String logFilterId =
filterManager.installPrivateLogFilter(
privacyGroupId, filter.getFromBlock(), filter.getToBlock(), query);
privacyGroupId, filter.getFromBlock(), filter.getToBlock(), filter.getLogsQuery());

return new JsonRpcSuccessResponse(request.getRequest().getId(), logFilterId);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
import org.hyperledger.besu.ethereum.api.jsonrpc.websocket.subscription.request.SubscriptionType;
import org.hyperledger.besu.ethereum.api.jsonrpc.websocket.subscription.syncing.SyncingSubscription;

import java.util.Optional;
import java.util.function.Function;

public class SubscriptionBuilder {
Expand All @@ -36,11 +35,7 @@ public Subscription build(
}
case LOGS:
{
return new LogsSubscription(
subscriptionId,
connectionId,
Optional.ofNullable(request.getLogsQuery())
.orElseThrow(IllegalArgumentException::new));
return new LogsSubscription(subscriptionId, connectionId, request.getFilterParameter());
}
case SYNCING:
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,21 +14,21 @@
*/
package org.hyperledger.besu.ethereum.api.jsonrpc.websocket.subscription.logs;

import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.FilterParameter;
import org.hyperledger.besu.ethereum.api.jsonrpc.websocket.subscription.Subscription;
import org.hyperledger.besu.ethereum.api.jsonrpc.websocket.subscription.request.SubscriptionType;
import org.hyperledger.besu.ethereum.api.query.LogsQuery;

public class LogsSubscription extends Subscription {

private final LogsQuery logsQuery;
private final FilterParameter filterParameter;

public LogsSubscription(
final Long subscriptionId, final String connectionId, final LogsQuery logsQuery) {
final Long subscriptionId, final String connectionId, final FilterParameter filterParameter) {
super(subscriptionId, connectionId, SubscriptionType.LOGS, Boolean.FALSE);
this.logsQuery = logsQuery;
this.filterParameter = filterParameter;
}

public LogsQuery getLogsQuery() {
return logsQuery;
public FilterParameter getFilterParameter() {
return filterParameter;
}
}
Loading