From d375ba8e82efbec0c8c21523ad3a2c9bf542ced0 Mon Sep 17 00:00:00 2001 From: Sam Calder-Mason Date: Wed, 30 Sep 2026 14:33:28 +1000 Subject: [PATCH 1/3] Bump xatu-sidecar to v0.0.7 and forward Gloas gossip events Execution payload envelopes, execution payload bids, payload attestation messages, proposer preferences and Gloas data column sidecars accepted on gossip are now sent to xatu-sidecar with the v0.0.7 event types. --- patches/consensys/teku/master.patch | 6 +- plugins/xatu/build.gradle | 1 + .../teku/plugin/xatu/XatuSidecarCore.java | 100 ++++++++++++++++++ scripts/apply-temu-patch.sh | 2 +- 4 files changed, 105 insertions(+), 4 deletions(-) diff --git a/patches/consensys/teku/master.patch b/patches/consensys/teku/master.patch index b7f1992..6bc1e99 100644 --- a/patches/consensys/teku/master.patch +++ b/patches/consensys/teku/master.patch @@ -1,5 +1,5 @@ diff --git a/build.gradle b/build.gradle -index ba3f2a7..d2265ee 100644 +index ba3f2a7..b0d14e1 100644 --- a/build.gradle +++ b/build.gradle @@ -928,6 +928,28 @@ tasks.register('localDocker') { @@ -7,7 +7,7 @@ index ba3f2a7..d2265ee 100644 into(dockerBuildDir) } + // Download and copy xatu native library -+ def xatuVersion = "v0.0.6" ++ def xatuVersion = "v0.0.7" + def libxatuFile = file("${projectDir}/libxatu.so") + if (!libxatuFile.exists()) { + def platform = "linux" @@ -36,7 +36,7 @@ index ba3f2a7..d2265ee 100644 def includeCommitHashInDockerTag = project.hasProperty('includeCommitHashInDockerTag') && project.property('includeCommitHashInDockerTag').toBoolean() def commitHashTag = includeCommitHashInDockerTag ? '-' + gitCommitHashShort() : '' + // Download and copy xatu native library -+ def xatuVersion = "v0.0.6" ++ def xatuVersion = "v0.0.7" + def libxatuFile = file("${projectDir}/libxatu.so") + if (!libxatuFile.exists()) { + def platform = "linux" diff --git a/plugins/xatu/build.gradle b/plugins/xatu/build.gradle index 0dbf6c3..574106e 100644 --- a/plugins/xatu/build.gradle +++ b/plugins/xatu/build.gradle @@ -7,6 +7,7 @@ dependencies { implementation project(':infrastructure:time') implementation project(':infrastructure:unsigned') implementation project(':ethereum:spec') + implementation project(':ethereum:execution-types') implementation 'net.java.dev.jna:jna' implementation 'org.apache.logging.log4j:log4j-api' diff --git a/plugins/xatu/src/main/java/tech/pegasys/teku/plugin/xatu/XatuSidecarCore.java b/plugins/xatu/src/main/java/tech/pegasys/teku/plugin/xatu/XatuSidecarCore.java index b61f96b..26ab68d 100644 --- a/plugins/xatu/src/main/java/tech/pegasys/teku/plugin/xatu/XatuSidecarCore.java +++ b/plugins/xatu/src/main/java/tech/pegasys/teku/plugin/xatu/XatuSidecarCore.java @@ -37,7 +37,16 @@ import tech.pegasys.teku.infrastructure.version.VersionProvider; import tech.pegasys.teku.spec.datastructures.blobs.DataColumnSidecar; import tech.pegasys.teku.spec.datastructures.blobs.versions.deneb.BlobSidecar; +import tech.pegasys.teku.spec.datastructures.blobs.versions.gloas.DataColumnSidecarGloas; import tech.pegasys.teku.spec.datastructures.blocks.SignedBeaconBlock; +import tech.pegasys.teku.spec.datastructures.epbs.versions.gloas.ExecutionPayloadBid; +import tech.pegasys.teku.spec.datastructures.epbs.versions.gloas.ExecutionPayloadEnvelope; +import tech.pegasys.teku.spec.datastructures.epbs.versions.gloas.PayloadAttestationData; +import tech.pegasys.teku.spec.datastructures.epbs.versions.gloas.PayloadAttestationMessage; +import tech.pegasys.teku.spec.datastructures.epbs.versions.gloas.ProposerPreferences; +import tech.pegasys.teku.spec.datastructures.epbs.versions.gloas.SignedExecutionPayloadBid; +import tech.pegasys.teku.spec.datastructures.epbs.versions.gloas.SignedExecutionPayloadEnvelope; +import tech.pegasys.teku.spec.datastructures.epbs.versions.gloas.SignedProposerPreferences; import tech.pegasys.teku.spec.datastructures.operations.Attestation; import tech.pegasys.teku.spec.datastructures.operations.SignedAggregateAndProof; @@ -319,6 +328,21 @@ private Optional convertToXatuEvent(final GossipMessageAcceptedEvent blobSidecar.getSignedBeaconBlockHeader().getMessage().getStateRoot().toHexString()); return Optional.of(eventNode); + } else if (message instanceof DataColumnSidecarGloas dataColumnSidecar) { + ObjectNode eventNode = MAPPER.createObjectNode(); + eventNode.put("event_type", "DATA_COLUMN_SIDECAR_GLOAS"); + long slot = dataColumnSidecar.getSlot().longValue(); + eventNode.put("timestamp_ms", timestampMs); + eventNode.put("slot", slot); + eventNode.put("epoch", slot / SLOTS_PER_EPOCH); + eventNode.put("column_index", dataColumnSidecar.getIndex().longValue()); + eventNode.put("message_size", messageSize); + eventNode.put("peer_id", peerId); + eventNode.put("message_id", messageId); + eventNode.put("topic", topic); + eventNode.put("block_root", dataColumnSidecar.getBeaconBlockRoot().toHexString()); + return Optional.of(eventNode); + } else if (message instanceof DataColumnSidecar dataColumnSidecar) { ObjectNode eventNode = MAPPER.createObjectNode(); eventNode.put("event_type", "DATA_COLUMN_SIDECAR"); @@ -345,6 +369,82 @@ private Optional convertToXatuEvent(final GossipMessageAcceptedEvent eventNode.put("state_root", header.getMessage().getStateRoot().toHexString()); }); return Optional.of(eventNode); + + } else if (message instanceof SignedExecutionPayloadEnvelope signedEnvelope) { + ObjectNode eventNode = MAPPER.createObjectNode(); + eventNode.put("event_type", "EXECUTION_PAYLOAD_ENVELOPE"); + ExecutionPayloadEnvelope envelope = signedEnvelope.getMessage(); + long slot = envelope.getSlot().longValue(); + eventNode.put("timestamp_ms", timestampMs); + eventNode.put("slot", slot); + eventNode.put("epoch", slot / SLOTS_PER_EPOCH); + eventNode.put("builder_index", envelope.getBuilderIndex().longValue()); + eventNode.put("message_size", messageSize); + eventNode.put("peer_id", peerId); + eventNode.put("message_id", messageId); + eventNode.put("topic", topic); + eventNode.put("beacon_block_root", envelope.getBeaconBlockRoot().toHexString()); + eventNode.put("block_hash", envelope.getPayload().getBlockHash().toHexString()); + eventNode.put("state_root", envelope.getPayload().getStateRoot().toHexString()); + return Optional.of(eventNode); + + } else if (message instanceof SignedExecutionPayloadBid signedBid) { + ObjectNode eventNode = MAPPER.createObjectNode(); + eventNode.put("event_type", "EXECUTION_PAYLOAD_BID"); + ExecutionPayloadBid bid = signedBid.getMessage(); + long slot = bid.getSlot().longValue(); + eventNode.put("timestamp_ms", timestampMs); + eventNode.put("slot", slot); + eventNode.put("epoch", slot / SLOTS_PER_EPOCH); + eventNode.put("builder_index", bid.getBuilderIndex().longValue()); + eventNode.put("value", bid.getValue().longValue()); + eventNode.put("execution_payment", bid.getExecutionPayment().longValue()); + eventNode.put("gas_limit", bid.getGasLimit().longValue()); + eventNode.put("blob_kzg_commitment_count", bid.getBlobKzgCommitments().size()); + eventNode.put("message_size", messageSize); + eventNode.put("peer_id", peerId); + eventNode.put("message_id", messageId); + eventNode.put("topic", topic); + eventNode.put("block_hash", bid.getBlockHash().toHexString()); + eventNode.put("parent_block_hash", bid.getParentBlockHash().toHexString()); + eventNode.put("fee_recipient", bid.getFeeRecipient().getWrappedBytes().toHexString()); + return Optional.of(eventNode); + + } else if (message instanceof PayloadAttestationMessage payloadAttestation) { + ObjectNode eventNode = MAPPER.createObjectNode(); + eventNode.put("event_type", "PAYLOAD_ATTESTATION_MESSAGE"); + PayloadAttestationData data = payloadAttestation.getData(); + long slot = data.getSlot().longValue(); + eventNode.put("timestamp_ms", timestampMs); + eventNode.put("slot", slot); + eventNode.put("epoch", slot / SLOTS_PER_EPOCH); + eventNode.put("validator_index", payloadAttestation.getValidatorIndex().longValue()); + eventNode.put("payload_present", data.isPayloadPresent()); + eventNode.put("blob_data_available", data.isBlobDataAvailable()); + eventNode.put("message_size", messageSize); + eventNode.put("peer_id", peerId); + eventNode.put("message_id", messageId); + eventNode.put("topic", topic); + eventNode.put("beacon_block_root", data.getBeaconBlockRoot().toHexString()); + return Optional.of(eventNode); + + } else if (message instanceof SignedProposerPreferences signedPreferences) { + ObjectNode eventNode = MAPPER.createObjectNode(); + eventNode.put("event_type", "PROPOSER_PREFERENCES"); + ProposerPreferences preferences = signedPreferences.getMessage(); + long slot = preferences.getProposalSlot().longValue(); + eventNode.put("timestamp_ms", timestampMs); + eventNode.put("slot", slot); + eventNode.put("epoch", slot / SLOTS_PER_EPOCH); + eventNode.put("validator_index", preferences.getValidatorIndex().longValue()); + eventNode.put("target_gas_limit", preferences.getTargetGasLimit().longValue()); + eventNode.put("message_size", messageSize); + eventNode.put("peer_id", peerId); + eventNode.put("message_id", messageId); + eventNode.put("topic", topic); + eventNode.put( + "fee_recipient", preferences.getFeeRecipient().getWrappedBytes().toHexString()); + return Optional.of(eventNode); } // Unknown type - skip (e.g. SyncCommitteeMessage, SignedContributionAndProof) diff --git a/scripts/apply-temu-patch.sh b/scripts/apply-temu-patch.sh index 11fd5ed..7daf0a3 100755 --- a/scripts/apply-temu-patch.sh +++ b/scripts/apply-temu-patch.sh @@ -142,7 +142,7 @@ echo -e "${GREEN} Copied plugins/xatu/${NC}" echo "" echo -e "${BLUE}=== Downloading libxatu ===${NC}" -XATU_SIDECAR_VERSION="v0.0.6" +XATU_SIDECAR_VERSION="v0.0.7" if [ ! -f "libxatu.so" ]; then echo -e "${BLUE} Downloading libxatu.so (${XATU_SIDECAR_VERSION})...${NC}" From 0021431414050656786dd0df93c6bf2e2bab3da9 Mon Sep 17 00:00:00 2001 From: Sam Calder-Mason Date: Wed, 30 Sep 2026 14:41:08 +1000 Subject: [PATCH 2/3] Format the proposer preferences fee recipient line for spotless --- .../java/tech/pegasys/teku/plugin/xatu/XatuSidecarCore.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/plugins/xatu/src/main/java/tech/pegasys/teku/plugin/xatu/XatuSidecarCore.java b/plugins/xatu/src/main/java/tech/pegasys/teku/plugin/xatu/XatuSidecarCore.java index 26ab68d..6dda7f1 100644 --- a/plugins/xatu/src/main/java/tech/pegasys/teku/plugin/xatu/XatuSidecarCore.java +++ b/plugins/xatu/src/main/java/tech/pegasys/teku/plugin/xatu/XatuSidecarCore.java @@ -442,8 +442,7 @@ private Optional convertToXatuEvent(final GossipMessageAcceptedEvent eventNode.put("peer_id", peerId); eventNode.put("message_id", messageId); eventNode.put("topic", topic); - eventNode.put( - "fee_recipient", preferences.getFeeRecipient().getWrappedBytes().toHexString()); + eventNode.put("fee_recipient", preferences.getFeeRecipient().getWrappedBytes().toHexString()); return Optional.of(eventNode); } From 6e95400e505004b2b9e7879e51f48a74dd3d2f0e Mon Sep 17 00:00:00 2001 From: Sam Calder-Mason Date: Wed, 30 Sep 2026 14:51:24 +1000 Subject: [PATCH 3/3] Send Gloas uint64 fields as unsigned numbers Self-built execution payload envelopes carry builder_index UINT64_MAX, which longValue() turned into -1 and xatu-sidecar rejected. --- .../teku/plugin/xatu/XatuSidecarCore.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/plugins/xatu/src/main/java/tech/pegasys/teku/plugin/xatu/XatuSidecarCore.java b/plugins/xatu/src/main/java/tech/pegasys/teku/plugin/xatu/XatuSidecarCore.java index 6dda7f1..4fa0863 100644 --- a/plugins/xatu/src/main/java/tech/pegasys/teku/plugin/xatu/XatuSidecarCore.java +++ b/plugins/xatu/src/main/java/tech/pegasys/teku/plugin/xatu/XatuSidecarCore.java @@ -378,7 +378,7 @@ private Optional convertToXatuEvent(final GossipMessageAcceptedEvent eventNode.put("timestamp_ms", timestampMs); eventNode.put("slot", slot); eventNode.put("epoch", slot / SLOTS_PER_EPOCH); - eventNode.put("builder_index", envelope.getBuilderIndex().longValue()); + eventNode.put("builder_index", envelope.getBuilderIndex().bigIntegerValue()); eventNode.put("message_size", messageSize); eventNode.put("peer_id", peerId); eventNode.put("message_id", messageId); @@ -396,10 +396,10 @@ private Optional convertToXatuEvent(final GossipMessageAcceptedEvent eventNode.put("timestamp_ms", timestampMs); eventNode.put("slot", slot); eventNode.put("epoch", slot / SLOTS_PER_EPOCH); - eventNode.put("builder_index", bid.getBuilderIndex().longValue()); - eventNode.put("value", bid.getValue().longValue()); - eventNode.put("execution_payment", bid.getExecutionPayment().longValue()); - eventNode.put("gas_limit", bid.getGasLimit().longValue()); + eventNode.put("builder_index", bid.getBuilderIndex().bigIntegerValue()); + eventNode.put("value", bid.getValue().bigIntegerValue()); + eventNode.put("execution_payment", bid.getExecutionPayment().bigIntegerValue()); + eventNode.put("gas_limit", bid.getGasLimit().bigIntegerValue()); eventNode.put("blob_kzg_commitment_count", bid.getBlobKzgCommitments().size()); eventNode.put("message_size", messageSize); eventNode.put("peer_id", peerId); @@ -418,7 +418,7 @@ private Optional convertToXatuEvent(final GossipMessageAcceptedEvent eventNode.put("timestamp_ms", timestampMs); eventNode.put("slot", slot); eventNode.put("epoch", slot / SLOTS_PER_EPOCH); - eventNode.put("validator_index", payloadAttestation.getValidatorIndex().longValue()); + eventNode.put("validator_index", payloadAttestation.getValidatorIndex().bigIntegerValue()); eventNode.put("payload_present", data.isPayloadPresent()); eventNode.put("blob_data_available", data.isBlobDataAvailable()); eventNode.put("message_size", messageSize); @@ -436,8 +436,8 @@ private Optional convertToXatuEvent(final GossipMessageAcceptedEvent eventNode.put("timestamp_ms", timestampMs); eventNode.put("slot", slot); eventNode.put("epoch", slot / SLOTS_PER_EPOCH); - eventNode.put("validator_index", preferences.getValidatorIndex().longValue()); - eventNode.put("target_gas_limit", preferences.getTargetGasLimit().longValue()); + eventNode.put("validator_index", preferences.getValidatorIndex().bigIntegerValue()); + eventNode.put("target_gas_limit", preferences.getTargetGasLimit().bigIntegerValue()); eventNode.put("message_size", messageSize); eventNode.put("peer_id", peerId); eventNode.put("message_id", messageId);