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