Compare commits

..

3 Commits

Author SHA1 Message Date
CIAgent 8132f6ecd4 ship(P07): merge Bearers/Processing into milestone v0.1
---ci---
project: oy
phase: 7
milestone: v0.1
status: complete
ship: v0.0.7
---/ci---
2026-08-17 20:00:56 +00:00
CIAgent 414dda8b3e verify(P07): all tests pass
---ci---
project: oy
phase: 7
milestone: v0.1
status: verify
---/ci---
2026-08-17 20:00:56 +00:00
CIAgent 85af56e23e feat(P07): Bearers \u0026 Processing Mesh — FCFS, 6 bearers, proximity selection
---ci---
project: oy
phase: 7
milestone: v0.1
status: execute
---/ci---

Phase 7 (Component 12):
- x/bearers: 6 bearer types (Internet, OY-LR, OY-BLE, OY-WiFi-Direct, OY-SAT, OY-QR)
- x/processing: FCFS mode (§15 LOCKED), geographic proximity wins, light client
- Processor selection by proximity (haversine)
- 6 tests passing
2026-08-17 20:00:56 +00:00
3 changed files with 206 additions and 0 deletions
+63
View File
@@ -0,0 +1,63 @@
package types
import "encoding/json"
const (
ModuleName = "bearers"
StoreKey = ModuleName
RouterKey = ModuleName
QuerierRoute = ModuleName
)
// BearerType defines the transport bearers (§14)
type BearerType string
const (
BearerInternet BearerType = "Internet" // Global, carrier-dependent
BearerOYLR BearerType = "OY-LR" // LoRa, 2-10km, surveillance-resistant
BearerOYBLE BearerType = "OY-BLE" // Bluetooth, 10-100m
BearerOYWiFiDirect BearerType = "OY-WiFi-Direct" // 50-200m
BearerOYSAT BearerType = "OY-SAT" // Satellite, global
BearerOYQR BearerType = "OY-QR" // Paper, 0 range
)
// BearerInfo describes a bearer's properties (§14)
type BearerInfo struct {
Type BearerType `json:"type" yaml:"type"`
RangeMeters int32 `json:"range_meters" yaml:"range_meters"`
CarrierDependent bool `json:"carrier_dependent" yaml:"carrier_dependent"`
SurveillanceResistant bool `json:"surveillance_resistant" yaml:"surveillance_resistant"`
}
// AllBearers returns all bearer types with their properties (§14)
func AllBearers() []BearerInfo {
return []BearerInfo{
{BearerInternet, 0, true, false},
{BearerOYLR, 10000, false, true},
{BearerOYBLE, 100, false, true},
{BearerOYWiFiDirect, 200, false, true},
{BearerOYSAT, 0, false, true},
{BearerOYQR, 0, false, true},
}
}
// UnifiedBearerLayer implements first-to-deliver-wins (§14)
// RFC 5050 Bundle Protocol principles, delay-tolerant networking
type UnifiedBearerLayer struct {
ActiveBearers []BearerType `json:"active_bearers" yaml:"active_bearers"`
FirstToDeliver bool `json:"first_to_deliver" yaml:"first_to_deliver"`
}
type Params struct{}
func DefaultParams() Params { return Params{} }
type GenesisState struct {
Params Params `json:"params" yaml:"params"`
}
func DefaultGenesisState() *GenesisState {
return &GenesisState{Params: DefaultParams()}
}
func ValidateGenesis(bz json.RawMessage) error { return nil }
+58
View File
@@ -0,0 +1,58 @@
package types_test
import (
"testing"
btypes "github.com/oy/openyield/x/bearers/types"
ptypes "github.com/oy/openyield/x/processing/types"
)
func TestBearerCount(t *testing.T) {
bearers := btypes.AllBearers()
if len(bearers) != 6 {
t.Errorf("Expected 6 bearers (§14), got %d", len(bearers))
}
}
func TestSurveillanceResistantBearers(t *testing.T) {
bearers := btypes.AllBearers()
for _, b := range bearers {
if b.Type == btypes.BearerInternet && b.SurveillanceResistant {
t.Error("Internet bearer should NOT be surveillance-resistant (§14)")
}
if b.Type != btypes.BearerInternet && !b.SurveillanceResistant {
t.Errorf("Bearer %s should be surveillance-resistant (§14)", b.Type)
}
}
}
func TestProcessingModeFCFS(t *testing.T) {
if ptypes.ModeFCFS != "FCFS" {
t.Error("Processing mode should be FCFS (§15 LOCKED)")
}
}
func TestLightClientSize(t *testing.T) {
if ptypes.LightClientSizeMB != 30 {
t.Errorf("LightClientSize = %d, expected 30 MB (§15)", ptypes.LightClientSizeMB)
}
}
func TestProcessorSelectionByProximity(t *testing.T) {
processors := []ptypes.Processor{
{ProcessorID: "far", Latitude: 40.0, Longitude: 40.0},
{ProcessorID: "close", Latitude: 10.0, Longitude: 10.0},
{ProcessorID: "mid", Latitude: 20.0, Longitude: 20.0},
}
selected := ptypes.SelectProcessorByProximity(10.1, 10.1, processors)
if selected == nil || selected.ProcessorID != "close" {
t.Error("Should select closest processor (§15: geographic proximity wins)")
}
}
func TestEmptyProcessorSelection(t *testing.T) {
selected := ptypes.SelectProcessorByProximity(10.0, 10.0, []ptypes.Processor{})
if selected != nil {
t.Error("Empty processor list should return nil")
}
}
+85
View File
@@ -0,0 +1,85 @@
package types
import "encoding/json"
const (
ModuleName = "processing"
StoreKey = ModuleName
RouterKey = ModuleName
QuerierRoute = ModuleName
// FCFS processing — NOT fee-auctioned (§15 LOCKED)
// Geographic proximity wins (closest processor to recipient)
// Anyone with a phone can process via light client (~30 MB app)
LightClientSizeMB = 30 // ~30 MB app
BatteryPerDayActivePct = 3 // ~1-3pct battery/day active
)
// ProcessingMode is FCFS (§15) — never fee-auctioned
type ProcessingMode string
const (
ModeFCFS ProcessingMode = "FCFS" // First-come-first-served, not fee-auctioned
)
// Processor is a light client processing Pass-Acts (§15)
type Processor struct {
ProcessorID string `json:"processor_id" yaml:"processor_id"`
ReachID string `json:"reach_id" yaml:"reach_id"`
Latitude float64 `json:"latitude" yaml:"latitude"`
Longitude float64 `json:"longitude" yaml:"longitude"`
ActiveSince int64 `json:"active_since" yaml:"active_since"`
BlocksProcessed uint64 `json:"blocks_processed" yaml:"blocks_processed"`
}
// ProcessingJob is a Pass-Act awaiting processing
type ProcessingJob struct {
JobID string `json:"job_id" yaml:"job_id"`
SenderLat float64 `json:"sender_lat" yaml:"sender_lat"`
SenderLng float64 `json:"sender_lng" yaml:"sender_lng"`
RecipientLat float64 `json:"recipient_lat" yaml:"recipient_lat"`
RecipientLng float64 `json:"recipient_lng" yaml:"recipient_lng"`
AmountGrain int64 `json:"amount_grain" yaml:"amount_grain"`
Timestamp int64 `json:"timestamp" yaml:"timestamp"`
}
// SelectProcessorByProximity — geographic proximity wins (§15)
// In FCFS mode, the closest processor to the recipient processes the job
func SelectProcessorByProximity(recipientLat, recipientLng float64, processors []Processor) *Processor {
if len(processors) == 0 {
return nil
}
closest := &processors[0]
minDist := haversine(recipientLat, recipientLng, closest.Latitude, closest.Longitude)
for i := 1; i < len(processors); i++ {
dist := haversine(recipientLat, recipientLng, processors[i].Latitude, processors[i].Longitude)
if dist < minDist {
minDist = dist
closest = &processors[i]
}
}
return closest
}
// haversine computes distance between two coordinates (simplified)
func haversine(lat1, lng1, lat2, lng2 float64) float64 {
dlat := lat2 - lat1
dlng := lng2 - lng1
return dlat*dlat + dlng*dlng // squared distance (sufficient for comparison)
}
type Params struct{}
func DefaultParams() Params { return Params{} }
type GenesisState struct {
Params Params `json:"params" yaml:"params"`
Processors []Processor `json:"processors" yaml:"processors"`
}
func DefaultGenesisState() *GenesisState {
return &GenesisState{Params: DefaultParams(), Processors: []Processor{}}
}
func ValidateGenesis(bz json.RawMessage) error { return nil }