Skip to content

[ic-1047] feat: data pipeline for events#91

Open
dbrajovic wants to merge 8 commits into
v0.50.x-injfrom
ic-1047/data-pipeline
Open

[ic-1047] feat: data pipeline for events#91
dbrajovic wants to merge 8 commits into
v0.50.x-injfrom
ic-1047/data-pipeline

Conversation

@dbrajovic

@dbrajovic dbrajovic commented Jun 9, 2026

Copy link
Copy Markdown

Adds a custom event manager for publishing events to Message Queue consumer (Kafka). Published events are not part of the abci block space and are flushed to the consumer at the end of every block.

Summary by CodeRabbit

Release Notes

  • New Features

    • Added publish event infrastructure for emitting custom protocol buffer messages separately from standard ABCI events, with event ordering preservation.
    • Added message queue publishing configuration support (MQPub) for event streaming.
  • Tests

    • Added comprehensive tests validating publish event behavior during block finalization and transaction execution.

@linear

linear Bot commented Jun 9, 2026

Copy link
Copy Markdown

IC-1047

@github-actions

github-actions Bot commented Jun 9, 2026

Copy link
Copy Markdown

@dbrajovic your pull request is missing a changelog!

@coderabbitai

coderabbitai Bot commented Jun 9, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

This PR introduces a publish-event pipeline to Cosmos SDK's BaseApp, enabling collection and streaming of proto.Message events separately from ABCI events while preserving cross-pipeline ordering. New types, context integration, and finalize/commit logic accumulate per-tx and block-level events into flush data structures, which are conditionally published via a channel when enabled. Comprehensive tests and configuration infrastructure support the feature.

Changes

Publish Event Pipeline

Layer / File(s) Summary
Publish Event Type System and Data Contracts
types/events.go, baseapp/publish_event.go, baseapp/baseapp.go
New PublishEventManagerI and PublishEventManager collect proto.Message events; EventPlaceholderManager routes published events to both managers while emitting placeholder ABCI events to preserve ordering. BaseApp gains EnablePublish flag, PublishEvents channel, and flushData field.
Context Publish Event Manager Plumbing
types/context.go
Context carries publishEventManager field initialized and accessible via PublishEventManager() and WithPublishEventManager() methods; CacheContext forwards publish events from child scopes to parent via writeCache.
FinalizeBlock Event Collection and Per-Tx Capture
baseapp/abci.go
internalFinalizeBlock collects publish events from begin/end block phases, resets the publish manager before each tx, and calls executeTxs which now returns per-tx EventSet structs. New filterOutPublishEvents helper partitions ABCI events and placeholder events into ordered TrueOrder metadata.
Commit Integration and Event Publishing
baseapp/abci.go
Commit captures the hash returned by cms.Commit() and invokes publishEvents(commitHash), which populates flushData.NewAppHash and conditionally publishes the accumulated flush data on PublishEvents channel.
Test Infrastructure for Publish Event Emission
baseapp/utils_test.go
New TestPublishEvent protobuf-compatible type; CounterServerImpl, Counter2ServerImpl, and ante handler gain emitCustomEvent boolean to optionally emit publish events during handler execution for testing purposes.
Publish Event Validation Tests
baseapp/publish_event_test.go
Two comprehensive tests validate begin/end block event emission, per-tx capture, event ordering preservation across ABCI and publish pipelines, and post-commit flush output including height/app-hash chaining.
Config Infrastructure and Existing Test Updates
server/config/config.go, server/config/toml.go, server/config/config_test.go, baseapp/abci_test.go, baseapp/baseapp_test.go, baseapp/streaming_test.go
New MQPubConfig struct and TOML template for message queue publish configuration. Existing ABCI and BaseApp tests updated to pass emitCustomEvent boolean when registering counter server implementations.

Sequence Diagram(s)

sequenceDiagram
  participant internalFinalizeBlock
  participant PublishEventManager
  participant executeTxs
  participant filterOutPublishEvents
  participant flushData
  internalFinalizeBlock->>PublishEventManager: read beginBlock publish events
  internalFinalizeBlock->>publishEvents: accumulate beginBlock events
  internalFinalizeBlock->>executeTxs: execute txs, collect per-tx EventSet
  executeTxs->>PublishEventManager: reset before each tx
  executeTxs->>filterOutPublishEvents: partition tx events
  filterOutPublishEvents-->>executeTxs: ABCI events + TrueOrder + PublishEvents
  internalFinalizeBlock->>PublishEventManager: read endBlock publish events
  internalFinalizeBlock->>filterOutPublishEvents: filter block-level placeholders
  internalFinalizeBlock->>flushData: populate BlockEvents, TxEvents, TrueOrder
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • InjectiveLabs/cosmos-sdk#68: Related publish-event pipeline updates sharing overlapping changes to BaseApp finalize/commit logic and publish-event type infrastructure.

Suggested reviewers

  • maxim-inj

Poem

A rabbit hops through event streams so bright,
Publish and ABCI dancing in sight,
Per-tx events captured with care,
Order preserved, flush data to share,
Blocks now flow with a well-ordered light! 🐰✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 18.18% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title '[ic-1047] feat: data pipeline for events' clearly and concisely summarizes the main change: implementing an event data pipeline for publishing events to external systems.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch ic-1047/data-pipeline

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

♻️ Duplicate comments (1)
baseapp/baseapp.go (1)

248-248: ⚠️ Potential issue | 🔴 Critical

Channel initialization contributes to potential deadlock.

This line initializes PublishEvents as an unbuffered channel. As flagged in the publishEvents() method review, sending on this unbuffered channel (line 33 in publish_event.go) can block Commit indefinitely if no receiver is present.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@baseapp/baseapp.go` at line 248, The PublishEvents channel is currently
unbuffered causing sends in publishEvents() to potentially block Commit; change
the initialization of PublishEvents (the struct field set where PublishEvents is
created) from an unbuffered channel to a buffered one (e.g., make(chan
PublishEventFlush, N)) with a reasonable capacity (e.g., 100) so producers in
Commit won't block if no receiver is immediately ready; update any related
comments to note the chosen buffer size and rationale.
🧹 Nitpick comments (1)
types/events.go (1)

393-402: 💤 Low value

Consider simplifying the loop syntax.

The loop at line 397 uses blank identifiers for _, _ = range events which is unconventional. Since the loop index and value are not used, prefer the cleaner for range events syntax.

♻️ Proposed simplification
 func (e *EventPlaceholderManager) EmitEvents(events []proto.Message) {
 	e.publishEventManager.EmitEvents(events)
 
 	placeholders := make(Events, 0, len(events))
-	for _, _ = range events {
+	for range events {
 		placeholders = append(placeholders, NewEvent(PlaceholderEventType))
 	}
 
 	e.eventManager.EmitEvents(placeholders)
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@types/events.go` around lines 393 - 402, In
EventPlaceholderManager.EmitEvents, simplify the loop that builds placeholders:
replace the unconventional "for _, _ = range events" with the cleaner "for range
events" in the block that appends NewEvent(PlaceholderEventType) to the
placeholders slice before calling e.eventManager.EmitEvents; keep the existing
placeholders allocation and calls to e.publishEventManager.EmitEvents and
e.eventManager.EmitEvents unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@baseapp/publish_event_test.go`:
- Around line 26-28: The Reset method on StringPublishEvent currently uses a
value receiver so assigning to e resets only the local copy; change the receiver
to a pointer (func (e *StringPublishEvent) Reset()) and reset the underlying
value (e.g. assign an empty StringPublishEvent to *e or zero its fields) so the
original struct instance is actually cleared.
- Around line 36-50: The helper getStreamEventFlushChan spawns an unbounded
goroutine forwarding from app.PublishEvents to publishEventChan with no
cancellation, causing leaks; modify getStreamEventFlushChan to accept (or create
and return) a cancel signal (e.g., a done channel or context.Context and a
cleanup function) and use it in the goroutine select alongside app.PublishEvents
and when closed/ctx.Done() triggers, return/exit the goroutine and close
publishEventChan; update callers/tests to call the returned cleanup (or defer
cancel) after getting the chan so the forwarder is stopped when the test
finishes.
- Line 199: Remove the leftover debug print by deleting the
fmt.Println(pevts.TxEvents) call in the test (publish_event_test.go) — locate
the statement that prints pevts.TxEvents (in the test function where pevts is
used) and remove it so the test contains no debug output before merging.

In `@baseapp/publish_event.go`:
- Around line 29-35: publishEvents is blocking on an unbuffered send to
app.PublishEvents (called from Commit()), which can deadlock consensus if no
receiver is present; change the send to a non-blocking send using select with a
default case (or alternatively ensure app.PublishEvents is created buffered),
e.g. in BaseApp.publishEvents replace the direct send of app.flushData with a
select that attempts to send to app.PublishEvents and otherwise drops (and
optionally logs) the event so Commit() cannot block; reference functions/fields:
BaseApp.publishEvents, app.PublishEvents, app.flushData, EnablePublish and the
Commit() caller.

In `@types/context.go`:
- Around line 414-426: The type assertion on pem in writeCache is unsafe and can
panic; change it to the two-value form (e.g., epm, ok :=
pem.(*EventPlaceholderManager)) and only reassign pem to epm.publishEventManager
when ok is true and epm is non-nil, otherwise leave pem as-is (then call
pem.EmitEvents as before). Update the logic around PublishEventManager and
EventPlaceholderManager in writeCache to use this safe check so EmitEvents is
invoked on the correct publishEventManager only when the assertion succeeded.

---

Duplicate comments:
In `@baseapp/baseapp.go`:
- Line 248: The PublishEvents channel is currently unbuffered causing sends in
publishEvents() to potentially block Commit; change the initialization of
PublishEvents (the struct field set where PublishEvents is created) from an
unbuffered channel to a buffered one (e.g., make(chan PublishEventFlush, N))
with a reasonable capacity (e.g., 100) so producers in Commit won't block if no
receiver is immediately ready; update any related comments to note the chosen
buffer size and rationale.

---

Nitpick comments:
In `@types/events.go`:
- Around line 393-402: In EventPlaceholderManager.EmitEvents, simplify the loop
that builds placeholders: replace the unconventional "for _, _ = range events"
with the cleaner "for range events" in the block that appends
NewEvent(PlaceholderEventType) to the placeholders slice before calling
e.eventManager.EmitEvents; keep the existing placeholders allocation and calls
to e.publishEventManager.EmitEvents and e.eventManager.EmitEvents unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 7cfa7d7b-a44b-42c0-99a0-27e546f86216

📥 Commits

Reviewing files that changed from the base of the PR and between 3361bee and 3f170a8.

📒 Files selected for processing (13)
  • baseapp/abci.go
  • baseapp/abci_test.go
  • baseapp/baseapp.go
  • baseapp/baseapp_test.go
  • baseapp/publish_event.go
  • baseapp/publish_event_test.go
  • baseapp/streaming_test.go
  • baseapp/utils_test.go
  • server/config/config.go
  • server/config/config_test.go
  • server/config/toml.go
  • types/context.go
  • types/events.go

Comment on lines +26 to +28
func (e StringPublishEvent) Reset() {
e = StringPublishEvent{}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Reset() method won't actually reset the receiver.

The Reset() method uses a value receiver and assigns to the local copy e, which has no effect on the original struct. This should use a pointer receiver to properly reset the value.

🔧 Proposed fix
-func (e StringPublishEvent) Reset() {
-	e = StringPublishEvent{}
+func (e *StringPublishEvent) Reset() {
+	*e = StringPublishEvent{}
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
func (e StringPublishEvent) Reset() {
e = StringPublishEvent{}
}
func (e *StringPublishEvent) Reset() {
*e = StringPublishEvent{}
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@baseapp/publish_event_test.go` around lines 26 - 28, The Reset method on
StringPublishEvent currently uses a value receiver so assigning to e resets only
the local copy; change the receiver to a pointer (func (e *StringPublishEvent)
Reset()) and reset the underlying value (e.g. assign an empty StringPublishEvent
to *e or zero its fields) so the original struct instance is actually cleared.

Comment on lines +36 to +50
func getStreamEventFlushChan(app *baseapp.BaseApp) chan baseapp.PublishEventFlush {
app.EnablePublish = true
publishEventChan := make(chan baseapp.PublishEventFlush)

go func() {
for {
select {
case e := <-app.PublishEvents:
publishEventChan <- e
}
}
}()

return publishEventChan
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Goroutine leak: no cleanup mechanism for the event forwarder.

The goroutine spawned in getStreamEventFlushChan runs indefinitely with no cancellation mechanism. When tests complete, this goroutine will continue running, causing a leak.

🧹 Recommended fix to add cleanup

Consider using a context or done channel to allow cleanup:

-func getStreamEventFlushChan(app *baseapp.BaseApp) chan baseapp.PublishEventFlush {
+func getStreamEventFlushChan(app *baseapp.BaseApp) (chan baseapp.PublishEventFlush, func()) {
 	app.EnablePublish = true
 	publishEventChan := make(chan baseapp.PublishEventFlush)
+	done := make(chan struct{})
 
 	go func() {
 		for {
 			select {
+			case <-done:
+				return
 			case e := <-app.PublishEvents:
 				publishEventChan <- e
 			}
 		}
 	}()
 
-	return publishEventChan
+	cleanup := func() { close(done) }
+	return publishEventChan, cleanup
 }

Then call defer cleanup() in each test that uses this helper.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
func getStreamEventFlushChan(app *baseapp.BaseApp) chan baseapp.PublishEventFlush {
app.EnablePublish = true
publishEventChan := make(chan baseapp.PublishEventFlush)
go func() {
for {
select {
case e := <-app.PublishEvents:
publishEventChan <- e
}
}
}()
return publishEventChan
}
func getStreamEventFlushChan(app *baseapp.BaseApp) (chan baseapp.PublishEventFlush, func()) {
app.EnablePublish = true
publishEventChan := make(chan baseapp.PublishEventFlush)
done := make(chan struct{})
go func() {
for {
select {
case <-done:
return
case e := <-app.PublishEvents:
publishEventChan <- e
}
}
}()
cleanup := func() { close(done) }
return publishEventChan, cleanup
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@baseapp/publish_event_test.go` around lines 36 - 50, The helper
getStreamEventFlushChan spawns an unbounded goroutine forwarding from
app.PublishEvents to publishEventChan with no cancellation, causing leaks;
modify getStreamEventFlushChan to accept (or create and return) a cancel signal
(e.g., a done channel or context.Context and a cleanup function) and use it in
the goroutine select alongside app.PublishEvents and when closed/ctx.Done()
triggers, return/exit the goroutine and close publishEventChan; update
callers/tests to call the returned cleanup (or defer cancel) after getting the
chan so the forwarder is stopped when the test finishes.

}
require.Equal(t, pevts.NewAppHash, res.AppHash)
require.Len(t, pevts.TxEvents, txPerHeight)
fmt.Println(pevts.TxEvents)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Remove debug output before merging.

The fmt.Println statement on line 199 appears to be debug output left in the code and should be removed.

🗑️ Proposed fix
 		require.Len(t, pevts.TxEvents, txPerHeight)
-		fmt.Println(pevts.TxEvents)
 		for i := 0; i < txPerHeight; i++ {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
fmt.Println(pevts.TxEvents)
require.Len(t, pevts.TxEvents, txPerHeight)
for i := 0; i < txPerHeight; i++ {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@baseapp/publish_event_test.go` at line 199, Remove the leftover debug print
by deleting the fmt.Println(pevts.TxEvents) call in the test
(publish_event_test.go) — locate the statement that prints pevts.TxEvents (in
the test function where pevts is used) and remove it so the test contains no
debug output before merging.

Comment thread baseapp/publish_event.go
Comment on lines +29 to +35
func (app *BaseApp) publishEvents(commitHash []byte) {
app.flushData.NewAppHash = commitHash

if app.EnablePublish {
app.PublishEvents <- app.flushData
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical | 🏗️ Heavy lift

Channel send can block Commit indefinitely.

At line 33, the code sends on an unbuffered channel (app.PublishEvents <- app.flushData). If EnablePublish is true but no receiver is consuming from PublishEvents, this will deadlock and block the consensus commit flow indefinitely. Since publishEvents is called from Commit() (see baseapp/abci.go line 1033), this could halt the chain.

Consider one of these solutions:

  1. Use a buffered channel with sufficient capacity
  2. Use a non-blocking send with select and default
  3. Document that consumers MUST read from the channel when EnablePublish is true
🔧 Proposed fix with non-blocking send
 func (app *BaseApp) publishEvents(commitHash []byte) {
 	app.flushData.NewAppHash = commitHash
 
 	if app.EnablePublish {
-		app.PublishEvents <- app.flushData
+		select {
+		case app.PublishEvents <- app.flushData:
+			// Event published successfully
+		default:
+			app.logger.Warn("PublishEvents channel full, dropping flush data", "height", app.flushData.Height)
+		}
 	}
 }

Alternatively, use a buffered channel in baseapp.go:

-	PublishEvents: make(chan PublishEventFlush),
+	PublishEvents: make(chan PublishEventFlush, 100),
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
func (app *BaseApp) publishEvents(commitHash []byte) {
app.flushData.NewAppHash = commitHash
if app.EnablePublish {
app.PublishEvents <- app.flushData
}
}
func (app *BaseApp) publishEvents(commitHash []byte) {
app.flushData.NewAppHash = commitHash
if app.EnablePublish {
select {
case app.PublishEvents <- app.flushData:
// Event published successfully
default:
app.logger.Warn("PublishEvents channel full, dropping flush data", "height", app.flushData.Height)
}
}
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@baseapp/publish_event.go` around lines 29 - 35, publishEvents is blocking on
an unbuffered send to app.PublishEvents (called from Commit()), which can
deadlock consensus if no receiver is present; change the send to a non-blocking
send using select with a default case (or alternatively ensure app.PublishEvents
is created buffered), e.g. in BaseApp.publishEvents replace the direct send of
app.flushData with a select that attempts to send to app.PublishEvents and
otherwise drops (and optionally logs) the event so Commit() cannot block;
reference functions/fields: BaseApp.publishEvents, app.PublishEvents,
app.flushData, EnablePublish and the Commit() caller.

Comment thread types/context.go
Comment on lines 414 to +426
writeCache = func() {
c.EventManager().EmitEvents(cc.EventManager().Events())

pem := c.PublishEventManager()
// pem contains EventPlaceholderManager within the interface and by the time this callback is called
// it already put placeholder events in the regular EventManager whenever a published event was emitted.
// We just need to forward the published events to the original context (see PublishEventManager method of sdk Context)
if pem.(*EventPlaceholderManager) != nil {
pem = pem.(*EventPlaceholderManager).publishEventManager
}

pem.EmitEvents(cc.PublishEventManager().Events())

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Type assertion pattern is incorrect and could panic.

At line 421, the code performs a type assertion pem.(*EventPlaceholderManager) without the two-value form and then checks != nil. This pattern is incorrect in Go:

  1. If pem is not an *EventPlaceholderManager, the assertion will panic rather than returning nil
  2. The != nil check is meaningless after a successful assertion—it would have panicked already if the type didn't match

Use the two-value form of type assertion to avoid panics:

🛡️ Proposed fix using safe type assertion
 	writeCache = func() {
 		c.EventManager().EmitEvents(cc.EventManager().Events())
 
 		pem := c.PublishEventManager()
 		// pem contains EventPlaceholderManager within the interface and by the time this callback is called
 		// it already put placeholder events in the regular EventManager whenever a published event was emitted.
 		// We just need to forward the published events to the original context (see PublishEventManager method of sdk Context)
-		if pem.(*EventPlaceholderManager) != nil {
+		if pm, ok := pem.(*EventPlaceholderManager); ok {
-			pem = pem.(*EventPlaceholderManager).publishEventManager
+			pem = pm.publishEventManager
 		}
 
 		pem.EmitEvents(cc.PublishEventManager().Events())
 
 		cms.Write()
 	}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
writeCache = func() {
c.EventManager().EmitEvents(cc.EventManager().Events())
pem := c.PublishEventManager()
// pem contains EventPlaceholderManager within the interface and by the time this callback is called
// it already put placeholder events in the regular EventManager whenever a published event was emitted.
// We just need to forward the published events to the original context (see PublishEventManager method of sdk Context)
if pem.(*EventPlaceholderManager) != nil {
pem = pem.(*EventPlaceholderManager).publishEventManager
}
pem.EmitEvents(cc.PublishEventManager().Events())
writeCache = func() {
c.EventManager().EmitEvents(cc.EventManager().Events())
pem := c.PublishEventManager()
// pem contains EventPlaceholderManager within the interface and by the time this callback is called
// it already put placeholder events in the regular EventManager whenever a published event was emitted.
// We just need to forward the published events to the original context (see PublishEventManager method of sdk Context)
if pm, ok := pem.(*EventPlaceholderManager); ok {
pem = pm.publishEventManager
}
pem.EmitEvents(cc.PublishEventManager().Events())
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@types/context.go` around lines 414 - 426, The type assertion on pem in
writeCache is unsafe and can panic; change it to the two-value form (e.g., epm,
ok := pem.(*EventPlaceholderManager)) and only reassign pem to
epm.publishEventManager when ok is true and epm is non-nil, otherwise leave pem
as-is (then call pem.EmitEvents as before). Update the logic around
PublishEventManager and EventPlaceholderManager in writeCache to use this safe
check so EmitEvents is invoked on the correct publishEventManager only when the
assertion succeeded.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants