use of tech.pegasys.teku.networking.eth2.rpc.core.ResponseCallback in project teku by ConsenSys.
the class BeaconBlocksByRangeMessageHandler method onIncomingMessage.
@Override
public void onIncomingMessage(final String protocolId, final Eth2Peer peer, final BeaconBlocksByRangeRequestMessage message, final ResponseCallback<SignedBeaconBlock> callback) {
LOG.trace("Peer {} requested {} BeaconBlocks starting at slot {} with step {}", peer.getId(), message.getCount(), message.getStartSlot(), message.getStep());
if (message.getStep().compareTo(ONE) < 0) {
callback.completeWithErrorResponse(new RpcException(INVALID_REQUEST_CODE, "Step must be greater than zero"));
return;
}
if (message.getCount().compareTo(UInt64.valueOf(MAX_REQUEST_BLOCKS)) > 0) {
callback.completeWithErrorResponse(new RpcException(INVALID_REQUEST_CODE, "Only a maximum of " + MAX_REQUEST_BLOCKS + " blocks can be requested per request"));
return;
}
if (!peer.wantToMakeRequest() || !peer.wantToReceiveObjects(callback, maxRequestSize.min(message.getCount()).longValue())) {
return;
}
sendMatchingBlocks(message, callback).finish(callback::completeSuccessfully, error -> {
final Throwable rootCause = Throwables.getRootCause(error);
if (rootCause instanceof RpcException) {
// Keep full context
LOG.trace("Rejecting beacon blocks by range request", error);
callback.completeWithErrorResponse((RpcException) rootCause);
} else {
if (rootCause instanceof StreamClosedException || rootCause instanceof ClosedChannelException) {
LOG.trace("Stream closed while sending requested blocks", error);
} else {
LOG.error("Failed to process blocks by range request", error);
}
callback.completeWithUnexpectedError(error);
}
});
}
use of tech.pegasys.teku.networking.eth2.rpc.core.ResponseCallback in project teku by ConsenSys.
the class BeaconBlocksByRangeMessageHandler method sendMatchingBlocks.
private SafeFuture<?> sendMatchingBlocks(final BeaconBlocksByRangeRequestMessage message, final ResponseCallback<SignedBeaconBlock> callback) {
final UInt64 count = maxRequestSize.min(message.getCount());
final UInt64 endSlot = message.getStartSlot().plus(message.getStep().times(count)).minus(ONE);
return combinedChainDataClient.getEarliestAvailableBlockSlot().thenCompose(earliestSlot -> {
if (earliestSlot.map(s -> s.isGreaterThan(message.getStartSlot())).orElse(true)) {
// We're missing the first block so return an error
return SafeFuture.failedFuture(new RpcException.ResourceUnavailableException("Requested historical blocks are currently unavailable"));
}
final UInt64 headBlockSlot = combinedChainDataClient.getChainHead().map(MinimalBeaconBlockSummary::getSlot).orElse(ZERO);
final NavigableMap<UInt64, Bytes32> hotRoots;
if (combinedChainDataClient.isFinalized(endSlot)) {
// All blocks are finalized so skip scanning the protoarray
hotRoots = new TreeMap<>();
} else {
hotRoots = combinedChainDataClient.getAncestorRoots(message.getStartSlot(), message.getStep(), count);
}
// Don't send anything past the last slot found in protoarray to ensure blocks are
// consistent
// If we didn't find any blocks in protoarray, every block in the range must be
// finalized
// so we don't need to worry about inconsistent blocks
final UInt64 headSlot = hotRoots.isEmpty() ? headBlockSlot : hotRoots.lastKey();
return sendNextBlock(new RequestState(message.getStartSlot(), message.getStep(), count, headSlot, hotRoots, callback)).toVoid();
});
}
use of tech.pegasys.teku.networking.eth2.rpc.core.ResponseCallback in project teku by ConsenSys.
the class BeaconBlocksByRootMessageHandler method onIncomingMessage.
@Override
public void onIncomingMessage(final String protocolId, final Eth2Peer peer, final BeaconBlocksByRootRequestMessage message, final ResponseCallback<SignedBeaconBlock> callback) {
LOG.trace("Peer {} requested BeaconBlocks with roots: {}", peer.getId(), message);
if (storageClient.getStore() != null) {
SafeFuture<Void> future = SafeFuture.COMPLETE;
if (!peer.wantToMakeRequest() || !peer.wantToReceiveObjects(callback, message.size())) {
peer.disconnectCleanly(DisconnectReason.RATE_LIMITING).reportExceptions();
return;
}
for (SszBytes32 blockRoot : message) {
future = future.thenCompose(__ -> storageClient.getStore().retrieveSignedBlock(blockRoot.get()).thenCompose(block -> {
final Optional<RpcException> validationResult = block.flatMap(b -> validateResponse(protocolId, b));
if (validationResult.isPresent()) {
return SafeFuture.failedFuture(validationResult.get());
}
return block.map(callback::respond).orElse(SafeFuture.COMPLETE);
}));
}
future.finish(callback::completeSuccessfully, err -> handleError(callback, err));
} else {
callback.completeSuccessfully();
}
}
use of tech.pegasys.teku.networking.eth2.rpc.core.ResponseCallback in project teku by ConsenSys.
the class StatusMessageHandler method onIncomingMessage.
@Override
public void onIncomingMessage(final String protocolId, final Eth2Peer peer, final StatusMessage message, final ResponseCallback<StatusMessage> callback) {
LOG.trace("Peer {} sent status {}", peer.getId(), message);
if (!peer.wantToMakeRequest()) {
return;
}
final PeerStatus status = PeerStatus.fromStatusMessage(message);
peer.updateStatus(status);
final Optional<StatusMessage> localStatus = statusMessageFactory.createStatusMessage();
if (localStatus.isPresent()) {
callback.respondAndCompleteSuccessfully(localStatus.get());
} else {
LOG.warn("Node is not ready to receive p2p traffic. Responding to incoming status message with an error.");
callback.completeWithErrorResponse(NODE_NOT_READY);
}
}
use of tech.pegasys.teku.networking.eth2.rpc.core.ResponseCallback in project teku by ConsenSys.
the class DefaultEth2Peer method wantToReceiveObjects.
@Override
public boolean wantToReceiveObjects(final ResponseCallback<SignedBeaconBlock> callback, final long objectCount) {
if (blockRequestTracker.wantToRequestObjects(objectCount) == 0L) {
LOG.debug("Peer {} disconnected due to block rate limits", getId());
callback.completeWithErrorResponse(new RpcException(INVALID_REQUEST_CODE, "Peer has been rate limited"));
disconnectCleanly(DisconnectReason.RATE_LIMITING).reportExceptions();
return false;
}
return true;
}
Aggregations