docs: add core/go RFC primitives for agent reference
Co-Authored-By: Virgil <virgil@lethean.io>
This commit is contained in:
parent
eb896a065f
commit
c7ada3dd54
2 changed files with 1576 additions and 0 deletions
239
docs/RFC-CORE-GO-REQUEST.md
Normal file
239
docs/RFC-CORE-GO-REQUEST.md
Normal file
|
|
@ -0,0 +1,239 @@
|
|||
# RFC Request — go-blockchain needs from Core (FINAL)
|
||||
|
||||
> From: Charon (go-blockchain)
|
||||
> To: Cladius (core/go + go-* packages)
|
||||
> Date: 2 Apr 2026 00:55
|
||||
> Snider's answers inline. Updated with precise asks.
|
||||
|
||||
## 1. core/api — DONE, pulled (+125 commits)
|
||||
Using it. No ask needed.
|
||||
|
||||
## 2. core.Subscribe/Publish — Raindrops forming
|
||||
When ready, go-blockchain will:
|
||||
- Publish: `blockchain.block.new`, `blockchain.alias.registered`, `blockchain.hardfork.activated`
|
||||
- Wire format: `core.Event{Type: string, Data: any, Timestamp: int64}`
|
||||
|
||||
No blocking ask — will integrate when available.
|
||||
|
||||
## 3. core.Wallet() — I can do this today via core.Service
|
||||
|
||||
```go
|
||||
c.RegisterService("blockchain.wallet", walletService)
|
||||
c.Service("blockchain.wallet", core.Service{
|
||||
Name: "blockchain.wallet",
|
||||
Instance: walletService,
|
||||
OnStart: func() core.Result { return walletService.Start() },
|
||||
OnStop: func() core.Result { return walletService.Stop() },
|
||||
})
|
||||
```
|
||||
|
||||
Then register actions:
|
||||
```go
|
||||
c.Action("blockchain.wallet.create", walletService.HandleCreate)
|
||||
c.Action("blockchain.wallet.transfer", walletService.HandleTransfer)
|
||||
c.Action("blockchain.wallet.balance", walletService.HandleBalance)
|
||||
```
|
||||
|
||||
**No ask. Implementing now.**
|
||||
|
||||
## 4. Structured Logging — PRECISE ASK
|
||||
|
||||
**I want package-level logging that works WITHOUT a Core instance.**
|
||||
|
||||
The chain sync runs in goroutines that don't hold `*core.Core`. Currently using `log.Printf`.
|
||||
|
||||
**Exact ask:** Confirm these work at package level:
|
||||
```go
|
||||
core.Print(nil, "block synced height=%d hash=%s", height, hash) // info
|
||||
core.Error(nil, "sync failed: %v", err) // error
|
||||
```
|
||||
|
||||
Or do I need `core.NewLog()` → pass the logger into the sync goroutine?
|
||||
|
||||
## 5. core.Escrow() — Improvement to go-blockchain, sane with Chain + Asset
|
||||
|
||||
Escrow is a tx type (HF4+). I build it in go-blockchain's wallet package:
|
||||
```go
|
||||
wallet.BuildEscrowTx(provider, customer, amount, terms)
|
||||
```
|
||||
|
||||
Then expose via action: `c.Action("blockchain.escrow.create", ...)`
|
||||
|
||||
**No ask from Core. I implement this.**
|
||||
|
||||
## 6. core.Asset() — Same, go-blockchain implements
|
||||
|
||||
HF5 enables deploy/emit/burn. I add to wallet package + actions:
|
||||
```go
|
||||
c.Action("blockchain.asset.deploy", ...)
|
||||
c.Action("blockchain.asset.emit", ...)
|
||||
c.Action("blockchain.asset.burn", ...)
|
||||
```
|
||||
|
||||
**No ask. Implementing after HF5 activates.**
|
||||
|
||||
## 7. core.Chain() — Same pattern
|
||||
|
||||
```go
|
||||
c.RegisterService("blockchain.chain", chainService)
|
||||
c.Action("blockchain.chain.height", ...)
|
||||
c.Action("blockchain.chain.block", ...)
|
||||
c.Action("blockchain.chain.sync", ...)
|
||||
```
|
||||
|
||||
**No ask. Doing this today.**
|
||||
|
||||
## 8. core.DNS() — Do you want a go-dns package?
|
||||
|
||||
The LNS is 672 lines of Go at `~/Code/lthn/lns/`. It could become `go-dns` in the Core ecosystem.
|
||||
|
||||
**Ask: Should I make it `dappco.re/go/core/dns` or keep it as a standalone?**
|
||||
|
||||
If yes to go-dns, the actions would be:
|
||||
```go
|
||||
c.Action("dns.resolve", ...) // A record
|
||||
c.Action("dns.resolve.txt", ...) // TXT record
|
||||
c.Action("dns.reverse", ...) // PTR
|
||||
c.Action("dns.register", ...) // via sidechain
|
||||
```
|
||||
|
||||
## 9. Portable Storage Encoder — DONE
|
||||
|
||||
Already implemented in `p2p/encode.go` using `go-p2p/node/levin/EncodeStorage`. Committed and pushed. HandshakeResponse.Encode, ResponseChainEntry.Encode, RequestChain.Decode all working.
|
||||
|
||||
**go-storage/go-io improvement ask:** The chain stores blocks in go-store (SQLite). For high-throughput sync, a `go-io` backed raw block file store would be faster. Want me to spec a `BlockStore` interface that can swap between go-store and go-io backends?
|
||||
|
||||
## 10. CGo boilerplate — YES PLEASE
|
||||
|
||||
**Exact ask:** A `go-cgo` package with:
|
||||
|
||||
```go
|
||||
// Safe C buffer allocation with automatic cleanup
|
||||
buf := cgo.NewBuffer(32)
|
||||
defer buf.Free()
|
||||
buf.CopyFrom(goSlice)
|
||||
result := buf.Bytes()
|
||||
|
||||
// C function call wrapper with error mapping
|
||||
err := cgo.Call(C.my_function, buf.Ptr(), cgo.SizeT(len))
|
||||
// Returns Go error if C returns non-zero
|
||||
|
||||
// C string conversion
|
||||
goStr := cgo.GoString(cStr)
|
||||
cStr := cgo.CString(goStr)
|
||||
defer cgo.Free(cStr)
|
||||
```
|
||||
|
||||
Every CGo package (go-blockchain/crypto, go-mlx, go-rocm) does this dance manually. A shared helper saves ~50 lines per package and prevents use-after-free bugs.
|
||||
|
||||
## Summary
|
||||
|
||||
| # | What | Who Does It | Status |
|
||||
|---|------|-------------|--------|
|
||||
| 1 | core/api | Cladius | DONE, pulled |
|
||||
| 2 | Pub/Sub events | Cladius | Forming → core/stream (go-ws rename) |
|
||||
| 3 | Wallet service | **Charon** | Implementing today |
|
||||
| 4 | Package-level logging | **Answered below** | RTFM — it works |
|
||||
| 5 | Escrow txs | **Charon** | In go-blockchain |
|
||||
| 6 | Asset operations | **Charon** | After HF5 |
|
||||
| 7 | Chain service | **Charon** | Implementing today |
|
||||
| 8 | go-dns | **Cladius** | `dappco.re/go/dns` — DNS record DTOs + ClouDNS API types |
|
||||
| 9 | Storage encoder | **Charon** | DONE |
|
||||
| 10 | go-cgo | **Cladius** | RFC written, dispatching |
|
||||
|
||||
— Charon
|
||||
|
||||
---
|
||||
|
||||
## Cladius Answers — How To Do It With Core Primitives
|
||||
|
||||
> These examples show Charon how each ask maps to existing Core APIs.
|
||||
> Most of what he asked for already exists — he just needs the patterns.
|
||||
|
||||
### #4 Answer: Package-Level Logging
|
||||
|
||||
**Yes, `core.Print(nil, ...)` works.** The first arg is `*core.Core` and `nil` is valid — it falls back to the package-level logger. Your goroutines don't need a Core instance:
|
||||
|
||||
```go
|
||||
// In your sync goroutine — no *core.Core needed:
|
||||
core.Print(nil, "block synced height=%d hash=%s", height, hash)
|
||||
core.Error(nil, "sync failed: %v", err)
|
||||
|
||||
// If you HAVE a Core instance (e.g. in a service handler):
|
||||
core.Print(c, "wallet created id=%s", id) // tagged with service context
|
||||
```
|
||||
|
||||
Both work. `nil` = package logger, `c` = contextual logger. Same output format.
|
||||
|
||||
### #3 Answer: Service + Action Pattern (You Got It Right)
|
||||
|
||||
Your code is correct. The full pattern with Core primitives:
|
||||
|
||||
```go
|
||||
// Register service with lifecycle
|
||||
c.RegisterService("blockchain.wallet", core.Service{
|
||||
OnStart: func(ctx context.Context) core.Result {
|
||||
return walletService.Start(ctx)
|
||||
},
|
||||
OnStop: func(ctx context.Context) core.Result {
|
||||
return walletService.Stop(ctx)
|
||||
},
|
||||
})
|
||||
|
||||
// Register actions — path IS the CLI/HTTP/MCP route
|
||||
c.Action("blockchain.wallet.create", walletService.HandleCreate)
|
||||
c.Action("blockchain.wallet.balance", walletService.HandleBalance)
|
||||
|
||||
// Call another service's action (for #8 dns.discover → blockchain.chain.aliases):
|
||||
result := c.Run("blockchain.chain.aliases", core.Options{})
|
||||
```
|
||||
|
||||
### #5/#6/#7 Answer: Same Pattern, Different Path
|
||||
|
||||
```go
|
||||
// Escrow (HF4+)
|
||||
c.Action("blockchain.escrow.create", escrowService.HandleCreate)
|
||||
c.Action("blockchain.escrow.release", escrowService.HandleRelease)
|
||||
|
||||
// Asset (HF5+)
|
||||
c.Action("blockchain.asset.deploy", assetService.HandleDeploy)
|
||||
|
||||
// Chain
|
||||
c.Action("blockchain.chain.height", chainService.HandleHeight)
|
||||
c.Action("blockchain.chain.block", chainService.HandleBlock)
|
||||
|
||||
// All of these automatically get:
|
||||
// - CLI: core blockchain chain height
|
||||
// - HTTP: GET /blockchain/chain/height
|
||||
// - MCP: blockchain.chain.height tool
|
||||
// - i18n: blockchain.chain.height.* keys
|
||||
```
|
||||
|
||||
### #9 Answer: BlockStore Interface
|
||||
|
||||
For the go-store vs go-io backend swap:
|
||||
|
||||
```go
|
||||
// Define as a Core Data type
|
||||
type BlockStore struct {
|
||||
core.Data // inherits Store/Load/Delete
|
||||
}
|
||||
|
||||
// The backing medium is chosen at init:
|
||||
store := core.NewData("blockchain.blocks",
|
||||
core.WithMedium(gostore.SQLite("blocks.db")), // or:
|
||||
// core.WithMedium(goio.File("blocks/")), // raw file backend
|
||||
)
|
||||
|
||||
// Usage is identical regardless of backend:
|
||||
store.Store("block:12345", blockBytes)
|
||||
block := store.Load("block:12345")
|
||||
```
|
||||
|
||||
### #10 Answer: go-cgo
|
||||
|
||||
RFC written at `plans/code/core/go/cgo/RFC.md`. Buffer, Scope, Call, String helpers. Dispatching to Codex when repo is created on Forge.
|
||||
|
||||
### #8 Answer: go-dns
|
||||
|
||||
`dappco.re/go/dns` — Core package. DNS record structs as DTOs mapping 1:1 to ClouDNS API. Your LNS code at `~/Code/lthn/lns/` moves in as the service layer on top. Dispatching when repo exists.
|
||||
1337
docs/RFC-CORE-GO.md
Normal file
1337
docs/RFC-CORE-GO.md
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Add table
Reference in a new issue