Skip to content

Commit

Permalink
recognize from and to block parameters in eth subscribe (#826)
Browse files Browse the repository at this point in the history
* recognize from and to block parameters in eth subscribe

Signed-off-by: Ratan Rai Sur <ratan.r.sur@gmail.com>
  • Loading branch information
RatanRSur authored May 3, 2020
1 parent fdafee7 commit 88a0b8f
Show file tree
Hide file tree
Showing 18 changed files with 289 additions and 141 deletions.
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);
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

0 comments on commit 88a0b8f

Please sign in to comment.