Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dump p2p on files instead of hex logs #8177

Merged
merged 82 commits into from
Apr 17, 2024
Merged
Show file tree
Hide file tree
Changes from 75 commits
Commits
Show all changes
82 commits
Select commit Hold shift + click to select a range
4d3be14
Create P2PDumpManager with save invalid block functionality
courtneyeh Apr 7, 2024
13f1a8f
Create logic for other two file saves
courtneyeh Apr 8, 2024
8c3ef5d
Use unprefixed hex string in file name
courtneyeh Apr 8, 2024
164882e
Add testing
courtneyeh Apr 8, 2024
1fcfbd2
Add identifiers to file names
courtneyeh Apr 8, 2024
4184191
Rename variables
courtneyeh Apr 8, 2024
6659bad
Use arrival timestamp on message
courtneyeh Apr 8, 2024
e6e4b79
Use time provider for timestamp in test
courtneyeh Apr 8, 2024
087ecc9
Merge branch 'master' into p2p-dump
courtneyeh Apr 8, 2024
8b1bba7
Remove TODO
courtneyeh Apr 8, 2024
6521f6d
Merge branch 'master' into p2p-dump
courtneyeh Apr 9, 2024
3b6b567
Move P2PDumpManager
courtneyeh Apr 9, 2024
0abea63
Move P2PDumpManager to statetransition util
courtneyeh Apr 9, 2024
530c4bc
Initialise P2PDumpManager
courtneyeh Apr 9, 2024
3fbe240
Remove optional result
courtneyeh Apr 10, 2024
1f62c96
Merge branch 'master' into p2p-dump
courtneyeh Apr 10, 2024
68161a4
Spotless
courtneyeh Apr 10, 2024
7eb7cb5
Change return result
courtneyeh Apr 10, 2024
0ee2b96
Update P2PDumpManager
courtneyeh Apr 10, 2024
6099b66
Dump p2p on files instead of hex logs
courtneyeh Apr 10, 2024
a3eb42d
Fix tests and util
courtneyeh Apr 10, 2024
74669be
Merge branch 'master' into p2p-dump
courtneyeh Apr 10, 2024
91fccca
Highlighting issues
courtneyeh Apr 10, 2024
f6652af
Remove todos
courtneyeh Apr 10, 2024
882f3ae
Do not save to file if p2p warnings are disabled
courtneyeh Apr 10, 2024
c33baf2
Test not save to file when warnings disabled
courtneyeh Apr 10, 2024
f1ddf82
Update to new design
courtneyeh Apr 11, 2024
5abd7e0
Merge branch 'master' into p2p-dump
courtneyeh Apr 11, 2024
c6a9ea9
Update directory structure
courtneyeh Apr 11, 2024
d920c82
Fix referenceTestsPrep
courtneyeh Apr 11, 2024
239ee7e
Test new P2P Option
courtneyeh Apr 11, 2024
3079834
Add changelog entry
courtneyeh Apr 11, 2024
f6eafd9
Merge branch 'master' into p2p-dump
courtneyeh Apr 11, 2024
6062046
Update directory structure
courtneyeh Apr 11, 2024
c29ec81
Change manager name to DebugDataDumper
courtneyeh Apr 11, 2024
a82ea04
Few renames
courtneyeh Apr 11, 2024
08d78aa
Create NoOpDebugDataDumper
courtneyeh Apr 11, 2024
86b7e9e
Fix log inconsistency
courtneyeh Apr 11, 2024
4e7e077
Test not throw exception when unable to save to file
courtneyeh Apr 11, 2024
d871069
Use debug log
courtneyeh Apr 11, 2024
e214ad1
Remove identifiers
courtneyeh Apr 11, 2024
513c93e
Remove unused parameter
courtneyeh Apr 11, 2024
9ae5406
Fix description of p2p dump flag
courtneyeh Apr 11, 2024
0adaf95
Only create topic directories once
courtneyeh Apr 11, 2024
916d9ef
Add test for IO exception
courtneyeh Apr 11, 2024
0518042
Add disable breakers when failure and unable to return
courtneyeh Apr 11, 2024
e583fa0
Merge branch 'master' into p2p-dump
courtneyeh Apr 11, 2024
b732c5f
Test disabling service
courtneyeh Apr 11, 2024
26f295c
Test DebugDataDumper was used in ForkChoice
courtneyeh Apr 12, 2024
af98ec6
Test Eth2TopicHandler uses DebugDataDumper
courtneyeh Apr 12, 2024
d9b19f3
Update filenames
courtneyeh Apr 12, 2024
64770ff
Disable windows test
courtneyeh Apr 12, 2024
fa2bb78
Use mock debug data dumper in test
courtneyeh Apr 12, 2024
37cf086
Fix windows build
courtneyeh Apr 12, 2024
326f496
Format date in filename
courtneyeh Apr 12, 2024
1aff63f
Use timeprovider in test
courtneyeh Apr 12, 2024
70fb1f3
Small changes
courtneyeh Apr 12, 2024
25ee9d6
Rename for clarity
courtneyeh Apr 12, 2024
b2a3696
Remove static of timestamp formatter
courtneyeh Apr 12, 2024
c499511
Update simpler log info on file creation
courtneyeh Apr 12, 2024
7e2db7b
Handle unknown arrival time
courtneyeh Apr 12, 2024
33f63e2
Fix tests
courtneyeh Apr 12, 2024
9945286
Update test
courtneyeh Apr 12, 2024
69c7488
Fix windows build can't use : in filename
courtneyeh Apr 12, 2024
e82a751
Spotless
courtneyeh Apr 12, 2024
ae09a43
Fix unit test
courtneyeh Apr 12, 2024
689c9b7
Handle typical topic formatting
courtneyeh Apr 12, 2024
721e66d
Update success logging to be consistent with P2PLogger
courtneyeh Apr 13, 2024
fa338e6
Merge branch 'master' into p2p-dump
courtneyeh Apr 13, 2024
7c06149
Merge branch 'master' into p2p-dump
courtneyeh Apr 14, 2024
3a36a97
Merge branch 'master' into p2p-dump
courtneyeh Apr 15, 2024
3c17786
Move directory creation
courtneyeh Apr 15, 2024
6e402d6
Clean up timestamp file name
courtneyeh Apr 15, 2024
b4b7859
Rename tests
courtneyeh Apr 15, 2024
18a5fc6
Fix NoOpDebugDataDumper
courtneyeh Apr 15, 2024
92db86a
Fix test dirs
courtneyeh Apr 15, 2024
e7d6be9
Use NoOpDebugDataDumper when disabled in config
courtneyeh Apr 15, 2024
17e437e
Merge branch 'master' into p2p-dump
lucassaldanha Apr 16, 2024
1d3037d
Merge branch 'master' into p2p-dump
courtneyeh Apr 16, 2024
4247274
Pass block to data dumper
courtneyeh Apr 17, 2024
1f0bce0
Use supplier so message isn't calculated when disabled dumper
courtneyeh Apr 17, 2024
b5716d5
Merge branch 'master' into p2p-dump
lucassaldanha Apr 17, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,6 @@ the [releases page](https://github.com/Consensys/teku/releases).
- Deposit tree snapshots will be loaded from database as a default unless custom snapshot has been provided.
- Added hidden option `--Xdeposit-contract-logs-syncing-enabled` to allow disabling the syncing of the deposit contract logs from the EL. This is useful when running a non-validating node. It is advisable to be used alongside with `--Xeth1-missing-deposits-event-logging-enabled=false` to avoid unnecessary logging of missing deposits.
- Updated the bootnodes for Chiado and Gnosis networks
- Added hidden option `--Xp2p-dumps-to-file-enabled` to enable saving p2p dumps to file.

### Bug Fixes
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.mockito.Mockito.mock;
import static tech.pegasys.teku.infrastructure.async.SafeFutureAssert.safeJoin;
import static tech.pegasys.teku.infrastructure.time.TimeUtilities.secondsToMillis;

Expand Down Expand Up @@ -69,6 +70,7 @@
import tech.pegasys.teku.statetransition.forkchoice.MergeTransitionBlockValidator;
import tech.pegasys.teku.statetransition.forkchoice.NoopForkChoiceNotifier;
import tech.pegasys.teku.statetransition.forkchoice.TickProcessor;
import tech.pegasys.teku.statetransition.util.DebugDataDumper;
import tech.pegasys.teku.statetransition.validation.BlockBroadcastValidator;
import tech.pegasys.teku.statetransition.validation.InternalValidationResult;
import tech.pegasys.teku.storage.client.RecentChainData;
Expand Down Expand Up @@ -139,6 +141,7 @@ spec, new SignedBlockAndState(anchorBlock, anchorState)),
new TickProcessor(spec, recentChainData),
transitionBlockValidator,
true,
mock(DebugDataDumper.class),
storageSystem.getMetricsSystem());
final ExecutionLayerChannelStub executionLayer =
new ExecutionLayerChannelStub(spec, false, Optional.empty());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@
import tech.pegasys.teku.statetransition.attestation.DeferredAttestations;
import tech.pegasys.teku.statetransition.blobs.BlobSidecarManager;
import tech.pegasys.teku.statetransition.block.BlockImportPerformance;
import tech.pegasys.teku.statetransition.util.DebugDataDumper;
import tech.pegasys.teku.statetransition.util.noop.NoOpDebugDataDumper;
import tech.pegasys.teku.statetransition.validation.AttestationStateSelector;
import tech.pegasys.teku.statetransition.validation.BlockBroadcastValidator;
import tech.pegasys.teku.statetransition.validation.InternalValidationResult;
Expand Down Expand Up @@ -108,6 +110,8 @@ public class ForkChoice implements ForkChoiceUpdatedResultSubscriber {

private final LabelledMetric<Counter> getProposerHeadSelectedCounter;

private final DebugDataDumper debugDataDumper;

public ForkChoice(
final Spec spec,
final EventThread forkChoiceExecutor,
Expand All @@ -118,6 +122,7 @@ public ForkChoice(
final TickProcessor tickProcessor,
final MergeTransitionBlockValidator transitionBlockValidator,
final boolean forkChoiceLateBlockReorgEnabled,
final DebugDataDumper debugDataDumper,
final MetricsSystem metricsSystem) {
this.spec = spec;
this.forkChoiceExecutor = forkChoiceExecutor;
Expand All @@ -132,6 +137,7 @@ public ForkChoice(
this.forkChoiceLateBlockReorgEnabled = forkChoiceLateBlockReorgEnabled;
this.lastProcessHeadSlot.set(UInt64.ZERO);
LOG.debug("forkChoiceLateBlockReorgEnabled is set to {}", forkChoiceLateBlockReorgEnabled);
this.debugDataDumper = debugDataDumper;
getProposerHeadSelectedCounter =
metricsSystem.createLabelledCounter(
TekuMetricCategory.BEACON,
Expand Down Expand Up @@ -161,6 +167,7 @@ public ForkChoice(
new TickProcessor(spec, recentChainData),
transitionBlockValidator,
false,
new NoOpDebugDataDumper(),
metricsSystem);
}

Expand Down Expand Up @@ -753,6 +760,12 @@ private void reportInvalidBlock(final SignedBeaconBlock block, final BlockImport
if (result.getFailureReason() == FailureReason.BLOCK_IS_FROM_FUTURE) {
return;
}
debugDataDumper.saveInvalidBlockToFile(
block.getSlot(),
block.getRoot(),
block.sszSerialize(),
result.getFailureReason().name(),
result.getFailureCause());
P2P_LOG.onInvalidBlock(
block.getSlot(),
block.getRoot(),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,204 @@
/*
* Copyright Consensys Software Inc., 2024
*
* 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.teku.statetransition.util;

import com.google.common.annotations.VisibleForTesting;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.NoSuchFileException;
import java.nio.file.Path;
import java.sql.Date;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Optional;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.bytes.Bytes32;
import tech.pegasys.teku.infrastructure.time.SystemTimeProvider;
import tech.pegasys.teku.infrastructure.time.TimeProvider;
import tech.pegasys.teku.infrastructure.unsigned.UInt64;

public class DebugDataDumper {
private static final Logger LOG = LogManager.getLogger();

private static final String GOSSIP_MESSAGES_DIR = "gossip_messages";
private static final String DECODING_ERROR_SUB_DIR = "decoding_error";
private static final String REJECTED_SUB_DIR = "rejected";
private static final String INVALID_BLOCK_DIR = "invalid_blocks";

private boolean enabled;
private final Path directory;

public DebugDataDumper(final Path directory, final boolean enabled) {
this.enabled = enabled;
this.directory = directory;
if (!enabled) {
return;
}

final Path gossipMessagesPath = this.directory.resolve(GOSSIP_MESSAGES_DIR);
createDirectory(gossipMessagesPath, GOSSIP_MESSAGES_DIR, "gossip messages");
createDirectory(
gossipMessagesPath.resolve(DECODING_ERROR_SUB_DIR),
DECODING_ERROR_SUB_DIR,
"gossip messages with decoding errors");
createDirectory(
gossipMessagesPath.resolve(REJECTED_SUB_DIR), REJECTED_SUB_DIR, "rejected gossip messages");
createDirectory(this.directory.resolve(INVALID_BLOCK_DIR), INVALID_BLOCK_DIR, "invalid blocks");
}

public void saveGossipMessageDecodingError(
final String topic,
final Optional<UInt64> arrivalTimestamp,
final Bytes originalMessage,
final Throwable error) {
if (!enabled) {
return;
}
final String formattedTimestamp = formatOptionalTimestamp(arrivalTimestamp);
final String fileName = String.format("%s.ssz", formattedTimestamp);
final Path topicPath =
Path.of(GOSSIP_MESSAGES_DIR)
.resolve(DECODING_ERROR_SUB_DIR)
.resolve(topic.replaceAll("/", "_"));
final boolean success =
saveBytesToFile(
"gossip message with decoding error", topicPath.resolve(fileName), originalMessage);
if (success) {
LOG.warn("Failed to decode gossip message on topic {}", topic, error);
}
}

public void saveGossipRejectedMessageToFile(
final String topic,
final Optional<UInt64> arrivalTimestamp,
final Bytes decodedMessage,
final Optional<String> reason) {
if (!enabled) {
return;
}
final String formattedTimestamp = formatOptionalTimestamp(arrivalTimestamp);
final String fileName = String.format("%s.ssz", formattedTimestamp);
final Path topicPath =
Path.of(GOSSIP_MESSAGES_DIR).resolve(REJECTED_SUB_DIR).resolve(topic.replaceAll("/", "_"));
final boolean success =
saveBytesToFile("rejected gossip message", topicPath.resolve(fileName), decodedMessage);
if (success) {
LOG.warn(
"Rejecting gossip message on topic {}, reason: {}",
topic,
reason.orElse("failed validation"));
}
}

public void saveInvalidBlockToFile(
final UInt64 slot,
final Bytes32 blockRoot,
final Bytes blockSsz,
final String failureReason,
final Optional<Throwable> failureCause) {
if (!enabled) {
return;
}
final String fileName = String.format("%s_%s.ssz", slot, blockRoot.toUnprefixedHexString());
final boolean success =
saveBytesToFile("invalid block", Path.of(INVALID_BLOCK_DIR).resolve(fileName), blockSsz);
if (success) {
LOG.warn(
"Rejecting invalid block at slot {} with root {} because {}",
slot,
blockRoot,
failureReason,
failureCause.orElse(null));
}
}

@VisibleForTesting
protected boolean saveBytesToFile(
final String description, final Path relativeFilePath, final Bytes bytes) {
final Path path = directory.resolve(relativeFilePath);
try {
Files.write(path, bytes.toArray());
} catch (NoSuchFileException e) {
return saveAfterCreatingTopicDirectory(description, path, relativeFilePath, bytes);
} catch (IOException e) {
LOG.error("Failed to save {} bytes to file.", description, e);
return false;
}
return true;
}

private boolean saveAfterCreatingTopicDirectory(
final String description, final Path path, final Path relativeFilePath, final Bytes bytes) {
if (!path.getParent().toFile().mkdirs()) {
LOG.error(
"Failed to save {} bytes to file. No such directory {} to save file.",
description,
relativeFilePath.getParent());
return false;
}
try {
Files.write(path, bytes.toArray());
} catch (IOException e) {
LOG.error("Failed to save {} bytes to file.", description, e);
if (!path.getParent().toFile().exists()) {
this.enabled = false;
LOG.error(
"{} directory does not exist. Disabling saving debug data to file.",
relativeFilePath.getParent());
}
return false;
}
return true;
}

private void createDirectory(
final Path path, final String directoryName, final String description) {
if (!enabled) {
return;
}
if (path.toFile().mkdirs()) {
LOG.debug("{} directory has been created to save {}.", directoryName, description);
} else {
if (!path.toFile().exists()) {
this.enabled = false;
LOG.error(
"Unable to create {} directory to save {}. Disabling saving debug data to file.",
directoryName,
description);
}
}
}

private String formatOptionalTimestamp(final Optional<UInt64> maybeTimestamp) {
return formatOptionalTimestamp(maybeTimestamp, new SystemTimeProvider());
}

@VisibleForTesting
String formatOptionalTimestamp(
final Optional<UInt64> maybeTimestamp, final TimeProvider timeProvider) {
final DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH_mm_ss.SS");
final Date date =
maybeTimestamp
.map(timestamp -> new Date(timestamp.longValue()))
.orElse(new Date(timeProvider.getTimeInMillis().longValue()));
return df.format(date);
}

@VisibleForTesting
boolean isEnabled() {
return enabled;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
* Copyright Consensys Software Inc., 2024
*
* 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.teku.statetransition.util.noop;

import java.nio.file.Path;
import java.util.Optional;
import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.bytes.Bytes32;
import tech.pegasys.teku.infrastructure.unsigned.UInt64;
import tech.pegasys.teku.statetransition.util.DebugDataDumper;

public class NoOpDebugDataDumper extends DebugDataDumper {

public NoOpDebugDataDumper() {
super(Path.of("."), true);
}

@Override
public void saveGossipMessageDecodingError(
final String topic,
final Optional<UInt64> arrivalTimestamp,
final Bytes originalMessage,
final Throwable error) {}

@Override
public void saveGossipRejectedMessageToFile(
final String topic,
final Optional<UInt64> arrivalTimestamp,
final Bytes decodedMessage,
final Optional<String> reason) {}

@Override
public void saveInvalidBlockToFile(
final UInt64 slot,
final Bytes32 blockRoot,
final Bytes blockSsz,
final String failureReason,
final Optional<Throwable> failureCause) {}
}
Loading