mirror of https://github.com/hyperledger/besu
[NC-1616] Added iBFT NewChainHeadHeader event and related blockchain observer (#59)
Signed-off-by: Adrian Sutton <adrian.sutton@consensys.net>pull/2/head
parent
d0416e95f8
commit
967a406252
@ -0,0 +1,31 @@ |
||||
package tech.pegasys.pantheon.consensus.ibft; |
||||
|
||||
import tech.pegasys.pantheon.consensus.ibft.ibftevent.NewChainHead; |
||||
import tech.pegasys.pantheon.ethereum.chain.BlockAddedEvent; |
||||
import tech.pegasys.pantheon.ethereum.chain.BlockAddedObserver; |
||||
import tech.pegasys.pantheon.ethereum.chain.Blockchain; |
||||
|
||||
/** |
||||
* Blockchain observer that adds {@link NewChainHead} events to the event queue when a new block is |
||||
* added to the chain head |
||||
*/ |
||||
public class IbftChainObserver implements BlockAddedObserver { |
||||
private final IbftEventQueue queue; |
||||
|
||||
public IbftChainObserver(final IbftEventQueue queue) { |
||||
this.queue = queue; |
||||
} |
||||
|
||||
@Override |
||||
public void onBlockAdded(final BlockAddedEvent event, final Blockchain blockchain) { |
||||
switch (event.getEventType()) { |
||||
case HEAD_ADVANCED: |
||||
queue.add(new NewChainHead(event.getBlock().getHeader())); |
||||
break; |
||||
|
||||
default: |
||||
throw new IllegalStateException( |
||||
String.format("Unexpected BlockAddedEvent received: %s", event.getEventType())); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,56 @@ |
||||
package tech.pegasys.pantheon.consensus.ibft.ibftevent; |
||||
|
||||
import tech.pegasys.pantheon.consensus.ibft.IbftEvent; |
||||
import tech.pegasys.pantheon.consensus.ibft.IbftEvents.Type; |
||||
import tech.pegasys.pantheon.ethereum.core.BlockHeader; |
||||
|
||||
import java.util.Objects; |
||||
|
||||
import com.google.common.base.MoreObjects; |
||||
|
||||
/** Event indicating that new chain head has been received */ |
||||
public final class NewChainHead implements IbftEvent { |
||||
private final BlockHeader newChainHeadHeader; |
||||
|
||||
/** |
||||
* Constructor for a NewChainHead event |
||||
* |
||||
* @param newChainHeadHeader The header of the current blockchain head |
||||
*/ |
||||
public NewChainHead(final BlockHeader newChainHeadHeader) { |
||||
this.newChainHeadHeader = newChainHeadHeader; |
||||
} |
||||
|
||||
@Override |
||||
public Type getType() { |
||||
return Type.NEW_CHAIN_HEAD_HEADER; |
||||
} |
||||
|
||||
@Override |
||||
public String toString() { |
||||
return MoreObjects.toStringHelper(this) |
||||
.add("New Chain Head Header", newChainHeadHeader) |
||||
.toString(); |
||||
} |
||||
|
||||
@Override |
||||
public boolean equals(final Object o) { |
||||
if (this == o) { |
||||
return true; |
||||
} |
||||
if (o == null || getClass() != o.getClass()) { |
||||
return false; |
||||
} |
||||
final NewChainHead that = (NewChainHead) o; |
||||
return Objects.equals(newChainHeadHeader, that.newChainHeadHeader); |
||||
} |
||||
|
||||
@Override |
||||
public int hashCode() { |
||||
return Objects.hash(newChainHeadHeader); |
||||
} |
||||
|
||||
public BlockHeader getNewChainHeadHeader() { |
||||
return newChainHeadHeader; |
||||
} |
||||
} |
@ -0,0 +1,78 @@ |
||||
package tech.pegasys.pantheon.consensus.ibft; |
||||
|
||||
import static java.util.Collections.emptyList; |
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
import static org.mockito.Mockito.mock; |
||||
import static org.mockito.Mockito.verify; |
||||
import static org.mockito.Mockito.when; |
||||
|
||||
import tech.pegasys.pantheon.consensus.ibft.ibftevent.NewChainHead; |
||||
import tech.pegasys.pantheon.ethereum.chain.BlockAddedEvent; |
||||
import tech.pegasys.pantheon.ethereum.chain.Blockchain; |
||||
import tech.pegasys.pantheon.ethereum.core.Address; |
||||
import tech.pegasys.pantheon.ethereum.core.Block; |
||||
import tech.pegasys.pantheon.ethereum.core.BlockBody; |
||||
import tech.pegasys.pantheon.ethereum.core.BlockHeader; |
||||
import tech.pegasys.pantheon.ethereum.core.BlockHeaderTestFixture; |
||||
import tech.pegasys.pantheon.ethereum.core.Hash; |
||||
|
||||
import org.junit.Test; |
||||
import org.mockito.ArgumentCaptor; |
||||
|
||||
public class IbftChainObserverTest { |
||||
@Test |
||||
public void newChainHeadHeaderEventIsAddedToTheQueue() { |
||||
final Blockchain mockBlockchain = mock(Blockchain.class); |
||||
final IbftEventQueue mockQueue = mock(IbftEventQueue.class); |
||||
final BlockAddedEvent mockBlockAddedEvent = mock(BlockAddedEvent.class); |
||||
|
||||
final IbftChainObserver ibftChainObserver = new IbftChainObserver(mockQueue); |
||||
|
||||
final BlockHeader header = |
||||
new BlockHeaderTestFixture() |
||||
.number(1234) |
||||
.coinbase(Address.ECREC) |
||||
.parentHash(Hash.EMPTY_LIST_HASH) |
||||
.buildHeader(); |
||||
|
||||
final Block block = new Block(header, new BlockBody(emptyList(), emptyList())); |
||||
|
||||
when(mockBlockAddedEvent.getEventType()).thenReturn(BlockAddedEvent.EventType.HEAD_ADVANCED); |
||||
when(mockBlockAddedEvent.getBlock()).thenReturn(block); |
||||
|
||||
ibftChainObserver.onBlockAdded(mockBlockAddedEvent, mockBlockchain); |
||||
|
||||
ArgumentCaptor<IbftEvent> ibftEventArgumentCaptor = ArgumentCaptor.forClass(IbftEvent.class); |
||||
verify(mockQueue).add(ibftEventArgumentCaptor.capture()); |
||||
|
||||
assertThat(ibftEventArgumentCaptor.getValue() instanceof NewChainHead).isTrue(); |
||||
assertThat(((NewChainHead) ibftEventArgumentCaptor.getValue()).getNewChainHeadHeader()) |
||||
.isEqualTo(header); |
||||
} |
||||
|
||||
@Test(expected = IllegalStateException.class) |
||||
public void exceptionIsThrownWhenEventTypeIsFork() { |
||||
final Blockchain mockBlockchain = mock(Blockchain.class); |
||||
final IbftEventQueue mockQueue = mock(IbftEventQueue.class); |
||||
final BlockAddedEvent mockBlockAddedEvent = mock(BlockAddedEvent.class); |
||||
|
||||
when(mockBlockAddedEvent.getEventType()).thenReturn(BlockAddedEvent.EventType.FORK); |
||||
|
||||
final IbftChainObserver ibftChainObserver = new IbftChainObserver(mockQueue); |
||||
|
||||
ibftChainObserver.onBlockAdded(mockBlockAddedEvent, mockBlockchain); |
||||
} |
||||
|
||||
@Test(expected = IllegalStateException.class) |
||||
public void exceptionIsThrownWhenEventTypeIsChainReorg() { |
||||
final Blockchain mockBlockchain = mock(Blockchain.class); |
||||
final IbftEventQueue mockQueue = mock(IbftEventQueue.class); |
||||
final BlockAddedEvent mockBlockAddedEvent = mock(BlockAddedEvent.class); |
||||
|
||||
when(mockBlockAddedEvent.getEventType()).thenReturn(BlockAddedEvent.EventType.CHAIN_REORG); |
||||
|
||||
final IbftChainObserver ibftChainObserver = new IbftChainObserver(mockQueue); |
||||
|
||||
ibftChainObserver.onBlockAdded(mockBlockAddedEvent, mockBlockchain); |
||||
} |
||||
} |
Loading…
Reference in new issue