Skip to content

Commit

Permalink
[NC-1508] Added iBFT 2.0 BlockTimerExpiry Event and realated timer ma…
Browse files Browse the repository at this point in the history
…nagement class (#58)



Signed-off-by: Adrian Sutton <adrian.sutton@consensys.net>
  • Loading branch information
saltiniroberto authored Oct 17, 2018
1 parent 89e860f commit 6507f03
Show file tree
Hide file tree
Showing 4 changed files with 401 additions and 1 deletion.
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
/*
* Copyright 2018 ConsenSys AG.
*
* 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.
*/
package tech.pegasys.pantheon.consensus.ibft;

import tech.pegasys.pantheon.consensus.ibft.ibftevent.BlockTimerExpiry;
import tech.pegasys.pantheon.ethereum.core.BlockHeader;
import tech.pegasys.pantheon.util.time.Clock;

import java.util.Optional;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;

/** Class for starting and keeping organised block timers */
public class BlockTimer {
private final ScheduledExecutorService timerExecutor;
private Optional<ScheduledFuture<?>> currentTimerTask;
private final IbftEventQueue queue;
private final long minimumTimeBetweenBlocksMillis;
private final Clock clock;

/**
* Construct a BlockTimer with primed executor service ready to start timers
*
* @param queue The queue in which to put block expiry events
* @param minimumTimeBetweenBlocksMillis Minimum timestamp difference between blocks
* @param timerExecutor Executor service that timers can be scheduled with
* @param clock System clock
*/
public BlockTimer(
final IbftEventQueue queue,
final long minimumTimeBetweenBlocksMillis,
final ScheduledExecutorService timerExecutor,
final Clock clock) {
this.queue = queue;
this.timerExecutor = timerExecutor;
this.currentTimerTask = Optional.empty();
this.minimumTimeBetweenBlocksMillis = minimumTimeBetweenBlocksMillis;
this.clock = clock;
}

/** Cancels the current running round timer if there is one */
public synchronized void cancelTimer() {
currentTimerTask.ifPresent(t -> t.cancel(false));
currentTimerTask = Optional.empty();
}

/**
* Whether there is a timer currently running or not
*
* @return boolean of whether a timer is ticking or not
*/
public synchronized boolean isRunning() {
return currentTimerTask.map(t -> !t.isDone()).orElse(false);
}

/**
* Starts a timer for the supplied round cancelling any previously active block timer
*
* @param round The round identifier which this timer is tracking
* @param chainHeadHeader The header of the chain head
*/
public synchronized void startTimer(
final ConsensusRoundIdentifier round, final BlockHeader chainHeadHeader) {
cancelTimer();

final long now = clock.millisecondsSinceEpoch();

// absolute time when the timer is supposed to expire
final long expiryTime = chainHeadHeader.getTimestamp() * 1_000 + minimumTimeBetweenBlocksMillis;

if (expiryTime > now) {
final long delay = expiryTime - now;

final Runnable newTimerRunnable = () -> queue.add(new BlockTimerExpiry(round));

final ScheduledFuture<?> newTimerTask =
timerExecutor.schedule(newTimerRunnable, delay, TimeUnit.MILLISECONDS);
currentTimerTask = Optional.of(newTimerTask);
} else {
queue.add(new BlockTimerExpiry(round));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ public static IbftEvent fromMessage(final Message message) {

public enum Type {
ROUND_EXPIRY,
NEW_CHAIN_HEAD_HEADER
NEW_CHAIN_HEAD_HEADER,
BLOCK_TIMER_EXPIRY
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/*
* Copyright 2018 ConsenSys AG.
*
* 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.
*/
package tech.pegasys.pantheon.consensus.ibft.ibftevent;

import tech.pegasys.pantheon.consensus.ibft.ConsensusRoundIdentifier;
import tech.pegasys.pantheon.consensus.ibft.IbftEvent;
import tech.pegasys.pantheon.consensus.ibft.IbftEvents.Type;

import java.util.Objects;

import com.google.common.base.MoreObjects;

/** Event indicating a block timer has expired */
public final class BlockTimerExpiry implements IbftEvent {
private final ConsensusRoundIdentifier roundIdentifier;

/**
* Constructor for a BlockTimerExpiry event
*
* @param roundIdentifier The roundIdentifier that the expired timer belonged to
*/
public BlockTimerExpiry(final ConsensusRoundIdentifier roundIdentifier) {
this.roundIdentifier = roundIdentifier;
}

@Override
public Type getType() {
return Type.BLOCK_TIMER_EXPIRY;
}

public ConsensusRoundIdentifier getRoundIndentifier() {
return roundIdentifier;
}

@Override
public String toString() {
return MoreObjects.toStringHelper(this).add("Round Identifier", roundIdentifier).toString();
}

@Override
public boolean equals(final Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
final BlockTimerExpiry that = (BlockTimerExpiry) o;
return Objects.equals(roundIdentifier, that.roundIdentifier);
}

@Override
public int hashCode() {
return Objects.hash(roundIdentifier);
}
}
Loading

0 comments on commit 6507f03

Please sign in to comment.