Support pruned chain history in peer validators (#6698)

* dao fork block presence is optional in peer validator to support peers with pruned chain history

Signed-off-by: garyschulte <garyschulte@gmail.com>

* Update ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/peervalidation/AbstractPeerBlockValidator.java

Co-authored-by: Sally MacFarlane <macfarla.github@gmail.com>
Signed-off-by: garyschulte <garyschulte@gmail.com>

---------

Signed-off-by: garyschulte <garyschulte@gmail.com>
Co-authored-by: Sally MacFarlane <macfarla.github@gmail.com>
pull/6720/head
garyschulte 8 months ago committed by GitHub
parent 934e43558b
commit c39ca6d44f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 24
      ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/peervalidation/AbstractPeerBlockValidator.java
  2. 9
      ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/peervalidation/DaoForkPeerValidator.java
  3. 24
      ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/peervalidation/DaoForkPeerValidatorTest.java
  4. 22
      ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/peervalidation/RequiredBlocksPeerValidatorTest.java

@ -86,12 +86,20 @@ abstract class AbstractPeerBlockValidator implements PeerValidator {
}
final List<BlockHeader> headers = res.getResult();
if (headers.size() == 0) {
// If no headers are returned, fail
LOG.debug(
"Peer {} is invalid because required block ({}) is unavailable.",
ethPeer,
blockNumber);
return false;
if (blockIsRequired()) {
// If no headers are returned, fail
LOG.debug(
"Peer {} is invalid because required block ({}) is unavailable.",
ethPeer,
blockNumber);
return false;
} else {
LOG.debug(
"Peer {} deemed valid because unavailable block ({}) is not required.",
ethPeer,
blockNumber);
return true;
}
}
final BlockHeader header = headers.get(0);
return validateBlockHeader(ethPeer, header);
@ -105,6 +113,10 @@ abstract class AbstractPeerBlockValidator implements PeerValidator {
return ethPeer.chainState().getEstimatedHeight() >= (blockNumber + chainHeightEstimationBuffer);
}
protected boolean blockIsRequired() {
return true;
}
@Override
public Duration nextValidationCheckTimeout(final EthPeer ethPeer) {
if (!ethPeer.chainState().hasEstimatedHeight()) {

@ -49,4 +49,13 @@ public class DaoForkPeerValidator extends AbstractPeerBlockValidator {
}
return validDaoBlock;
}
/**
* In order to support chain history pruning, clients do not need to have the dao fork block to be
* deemed valid.
*/
@Override
protected boolean blockIsRequired() {
return false;
}
}

@ -98,4 +98,28 @@ public class DaoForkPeerValidatorTest extends AbstractPeerBlockValidatorTest {
assertThat(result).isDone();
assertThat(result).isCompletedWithValue(false);
}
@Test
public void validatePeer_responsivePeerDoesNotHaveBlockWhenPastForkHeight() {
final EthProtocolManager ethProtocolManager = EthProtocolManagerTestUtil.create();
final long daoBlockNumber = 500;
final PeerValidator validator =
new DaoForkPeerValidator(
ProtocolScheduleFixture.MAINNET, new NoOpMetricsSystem(), daoBlockNumber, 0);
final RespondingEthPeer peer =
EthProtocolManagerTestUtil.createPeer(ethProtocolManager, daoBlockNumber);
final CompletableFuture<Boolean> result =
validator.validatePeer(ethProtocolManager.ethContext(), peer.getEthPeer());
assertThat(result).isNotDone();
// Respond to block header request with empty
peer.respond(RespondingEthPeer.emptyResponder());
assertThat(result).isDone();
assertThat(result).isCompletedWithValue(true);
}
}

@ -104,4 +104,26 @@ public class RequiredBlocksPeerValidatorTest extends AbstractPeerBlockValidatorT
assertThat(result).isDone();
assertThat(result).isCompletedWithValue(false);
}
@Test
public void validatePeer_responsivePeerDoesNotHaveBlockWhenPastForkHeight() {
final EthProtocolManager ethProtocolManager = EthProtocolManagerTestUtil.create();
final PeerValidator validator =
new RequiredBlocksPeerValidator(
ProtocolScheduleFixture.MAINNET, new NoOpMetricsSystem(), 1, Hash.ZERO);
final RespondingEthPeer peer = EthProtocolManagerTestUtil.createPeer(ethProtocolManager, 1);
final CompletableFuture<Boolean> result =
validator.validatePeer(ethProtocolManager.ethContext(), peer.getEthPeer());
assertThat(result).isNotDone();
// Respond to block header request with empty
peer.respond(RespondingEthPeer.emptyResponder());
assertThat(result).isDone();
assertThat(result).isCompletedWithValue(false);
}
}

Loading…
Cancel
Save