Skip to content

Commit 487df39

Browse files
jframefab-10
authored andcommitted
Fix EthStats integration with updating blocks (besu-eth#9220)
* Fix EthStats not updating blocks Signed-off-by: Jason Frame <jason.frame@consensys.net> * Update gradle to include jackson-datatype-jdk8 for ethstats module Signed-off-by: Jason Frame <jason.frame@consensys.net> * changelog Signed-off-by: Jason Frame <jason.frame@consensys.net> * test for sending ethstats block message Signed-off-by: Jason Frame <jason.frame@consensys.net> * rename test Signed-off-by: Jason Frame <jason.frame@consensys.net> * rename test Signed-off-by: Jason Frame <jason.frame@consensys.net> --------- Signed-off-by: Jason Frame <jason.frame@consensys.net> Co-authored-by: Fabio Di Fabio <fabio.difabio@consensys.net> Signed-off-by: jflo <justin+github@florentine.us>
1 parent 092581a commit 487df39

File tree

5 files changed

+78
-2
lines changed

5 files changed

+78
-2
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
- Implement optional sender balance checks in the layered txpool [#9176](https://github.com/hyperledger/besu/pull/9176)
1919

2020
### Bug fixes
21+
- Fix eth_subscribe RPC failing returning a block response [#9212](https://github.com/hyperledger/besu/pull/9212)
22+
- Fix ethstats integration failing to provide block updates to ethstats server [#9220](https://github.com/hyperledger/besu/pull/9220)
2123

2224
## 25.9.0
2325

ethereum/ethstats/build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ dependencies {
3232
api 'org.slf4j:slf4j-api'
3333

3434
implementation 'com.fasterxml.jackson.core:jackson-databind'
35+
implementation 'com.fasterxml.jackson.datatype:jackson-datatype-jdk8'
3536
implementation 'com.google.guava:guava'
3637
implementation 'com.squareup.okhttp3:okhttp'
3738
implementation 'io.vertx:vertx-core'

ethereum/ethstats/src/main/java/org/hyperledger/besu/ethstats/EthStatsService.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@
7171
import java.util.stream.LongStream;
7272

7373
import com.fasterxml.jackson.databind.JsonNode;
74+
import com.google.common.annotations.VisibleForTesting;
7475
import io.vertx.core.Vertx;
7576
import io.vertx.core.http.WebSocket;
7677
import io.vertx.core.http.WebSocketClientOptions;
@@ -366,7 +367,8 @@ private void sendLatencyReport() {
366367
}
367368

368369
/** Sends a block report concerning the last block */
369-
private void sendBlockReport() {
370+
@VisibleForTesting
371+
protected void sendBlockReport() {
370372
blockchainQueries
371373
.latestBlock()
372374
.map(tx -> blockResultFactory.transactionComplete(tx, false))

ethereum/ethstats/src/main/java/org/hyperledger/besu/ethstats/request/EthStatsRequest.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import com.fasterxml.jackson.annotation.JsonProperty;
2323
import com.fasterxml.jackson.core.JsonProcessingException;
2424
import com.fasterxml.jackson.databind.ObjectMapper;
25+
import com.fasterxml.jackson.datatype.jdk8.Jdk8Module;
2526

2627
/**
2728
* This class represents an Ethereum statistics request. It provides methods to get the type of the
@@ -30,7 +31,7 @@
3031
public class EthStatsRequest {
3132

3233
/** The constant MAPPER. */
33-
public static final ObjectMapper MAPPER = new ObjectMapper();
34+
public static final ObjectMapper MAPPER = new ObjectMapper().registerModule(new Jdk8Module());
3435

3536
/** The constant EMIT_FIELD. */
3637
public static final String EMIT_FIELD = "emit";

ethereum/ethstats/src/test/java/org/hyperledger/besu/ethstats/EthStatsServiceTest.java

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,14 @@
2222
import static org.mockito.Mockito.when;
2323

2424
import org.hyperledger.besu.config.GenesisConfigOptions;
25+
import org.hyperledger.besu.datatypes.Hash;
26+
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.BlockResultFactory;
27+
import org.hyperledger.besu.ethereum.api.query.BlockWithMetadata;
2528
import org.hyperledger.besu.ethereum.api.query.BlockchainQueries;
29+
import org.hyperledger.besu.ethereum.api.query.TransactionWithMetadata;
2630
import org.hyperledger.besu.ethereum.blockcreation.MiningCoordinator;
31+
import org.hyperledger.besu.ethereum.core.Block;
32+
import org.hyperledger.besu.ethereum.core.BlockDataGenerator;
2733
import org.hyperledger.besu.ethereum.eth.manager.EthContext;
2834
import org.hyperledger.besu.ethereum.eth.manager.EthProtocolManager;
2935
import org.hyperledger.besu.ethereum.eth.manager.EthScheduler;
@@ -43,6 +49,9 @@
4349
import java.util.NoSuchElementException;
4450
import java.util.Optional;
4551

52+
import com.fasterxml.jackson.databind.JsonNode;
53+
import com.fasterxml.jackson.databind.ObjectMapper;
54+
import com.fasterxml.jackson.datatype.jdk8.Jdk8Module;
4655
import io.vertx.core.AsyncResult;
4756
import io.vertx.core.Handler;
4857
import io.vertx.core.Vertx;
@@ -226,6 +235,67 @@ public void shouldSendFullReportIfHelloMessageSucceeded() {
226235
verify(ethScheduler, times(1)).scheduleFutureTaskWithFixedDelay(any(), any(), any());
227236
}
228237

238+
@Test
239+
public void shouldSendBlockMessage() throws Exception {
240+
ethStatsService =
241+
new EthStatsService(
242+
ethStatsConnectOptions,
243+
blockchainQueries,
244+
ethProtocolManager,
245+
transactionPool,
246+
miningCoordinator,
247+
syncState,
248+
vertx,
249+
"clientVersion",
250+
genesisConfigOptions,
251+
p2PNetwork);
252+
253+
final BlockDataGenerator blockDataGenerator = new BlockDataGenerator();
254+
final Block testBlock = blockDataGenerator.block();
255+
final BlockWithMetadata<TransactionWithMetadata, Hash> blockWithMetadata =
256+
new BlockWithMetadata<>(
257+
testBlock.getHeader(),
258+
List.of(),
259+
List.of(),
260+
testBlock.getHeader().getDifficulty(),
261+
testBlock.getSize(),
262+
Optional.empty());
263+
264+
when(p2PNetwork.getLocalEnode()).thenReturn(Optional.of(node));
265+
when(blockchainQueries.latestBlock()).thenReturn(Optional.of(blockWithMetadata));
266+
267+
final ArgumentCaptor<Handler<AsyncResult<WebSocket>>> webSocketCaptor =
268+
ArgumentCaptor.forClass(Handler.class);
269+
270+
ethStatsService.start();
271+
272+
verify(webSocketClient, times(1))
273+
.connect(any(WebSocketConnectOptions.class), webSocketCaptor.capture());
274+
webSocketCaptor.getValue().handle(succeededWebSocketEvent(Optional.of(webSocket)));
275+
276+
// send block message
277+
ethStatsService.sendBlockReport();
278+
final ArgumentCaptor<String> messagesCaptor = ArgumentCaptor.forClass(String.class);
279+
verify(webSocket, times(2)).writeTextMessage(messagesCaptor.capture(), any(Handler.class));
280+
281+
final List<String> sentMessages = messagesCaptor.getAllValues();
282+
assertThat(sentMessages.get(0)).contains("hello");
283+
284+
final String blockMessage = sentMessages.get(1);
285+
assertThat(blockMessage).contains("\"block\"");
286+
287+
// verify block message
288+
final ObjectMapper objectMapper = new ObjectMapper().registerModule(new Jdk8Module());
289+
final var jsonNode = objectMapper.readTree(blockMessage);
290+
final var blockReportData = jsonNode.get("emit").get(1);
291+
final var blockDataNode = blockReportData.get("block");
292+
293+
final var expectedBlockResult = new BlockResultFactory().transactionComplete(blockWithMetadata);
294+
final JsonNode expectedBlockResultNode = objectMapper.valueToTree(expectedBlockResult);
295+
296+
assertThat(blockDataNode).isEqualTo(expectedBlockResultNode);
297+
}
298+
229299
private <T> AsyncResult<T> succeededWebSocketEvent(final Optional<T> object) {
230300
return new AsyncResult<>() {
231301
@Override

0 commit comments

Comments
 (0)