Skip to content

Custom rpc endpoints plugin#414

Merged
pablocampogo merged 7 commits into
mainfrom
custom-rpc-endpoints-plugin
Jun 18, 2026
Merged

Custom rpc endpoints plugin#414
pablocampogo merged 7 commits into
mainfrom
custom-rpc-endpoints-plugin

Conversation

@pablocampogo

Copy link
Copy Markdown
Contributor

Summary

Adds a detached, read-only query path from plugins to Canopy so plugin builders can serve their own custom RPC endpoints for chain-specific data, without coupling Canopy core to plugin-specific routes.

What's added

Core

  • New PluginQueryRequest/PluginQueryResponse proto messages + wire fields (lib/.proto/plugin.proto).
  • PluginQueryProvider + handleQueryRequest in lib/plugin.go, backed by a controller-owned TimeMachine snapshot adapter (controller/controller.go). Detached queries are read-only (no StateWrite).
  • Prefix-collision guard (two layers): plugins declare custom_state_prefixes; core panics at handshake if any collides with a core-reserved prefix (1–15), and FSM.StateWrite rejects writes to reserved prefixes (fsm/state.go, fsm/plugin_guard_test.go).

Plugin SDKs (go, python, typescript, kotlin, csharp)

  • Detached QueryState(height, read) client method + transport.
  • rpcAddress config field and a skeleton HTTP server (rpc.*) that starts with no routes, ready for builders to add their own endpoints.
  • custom_state_prefixes config plumbing.

Docs & tutorial

  • TUTORIAL.md / AGENTS.md for every plugin document how to add custom RPC endpoints, including a full worked faucet/reward example that lives only in each plugin's tutorial/ folder (with integration tests).

Comment thread lib/plugin.go
Comment thread controller/controller.go
@pablocampogo pablocampogo force-pushed the custom-rpc-endpoints-plugin branch from 63e3e37 to 5f5a515 Compare June 18, 2026 06:11
@pablocampogo pablocampogo merged commit e9eec0a into main Jun 18, 2026
2 checks passed
RichardJamesLopez added a commit to RichardJamesLopez/canopy that referenced this pull request Jun 18, 2026
Re-ran proto _generate.sh against the merged proto set (upstream PR canopy-network#414 added
RPC-endpoint fields to PluginConfig) and rebuilt dcb/web/dcb.wasm. Plugin,
dcb/app and dcb/faucet build on the new core; the DcbStateEvent schema fix still
resolves (9 tx + 1 event type URLs).
Makaveli912 added a commit to Makaveli912/praxis-market that referenced this pull request Jul 9, 2026
sendToPluginAsync() (block lifecycle) and sendDetachedAsync()
(QueryState/custom RPC, e.g. /v1/query/markets) both released the
p.l bookkeeping mutex before calling sendProtoMsg(), which performs
an unlocked conn.Write(). Concurrent calls to either path could
interleave writes on the same socket, corrupting the length-prefixed
message stream.

Symptom: hitting a custom RPC endpoint while the node is actively
producing blocks intermittently crashes the node with:
  FSM log: 'unrecognized plugin_to_fsm message: <nil>'
  Plugin log: 'plugin socket read failed: EOF'

This is present in the stock PR canopy-network#414 reference implementation, not
introduced by Praxis-specific code.

Fix: add a dedicated writeMu sync.Mutex held for the full duration
of sendProtoMsg(), serializing all socket writes regardless of which
call path triggered them. Bookkeeping (p.l) is left untouched so
unrelated request-tracking isn't serialized behind blocking I/O.

Verified: 50 concurrent /v1/query/markets requests against an
actively block-producing node, zero crashes, all responses valid.

Also fixes duplicate 'go' directive and stale checksum in
plugin/go/go.mod/go.sum from an earlier bad merge.
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.

2 participants