Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions phoenix_os/arbiter/src/arbiter.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,38 @@ type Payoff struct {
// PayoffMatrix for a 2x2 game
type PayoffMatrix [][]Payoff

// Node represents a participant in the swarm
type Node struct {
ID string
Reputation float64
Authorized bool
}

// Arbiter handles quorum and reputation
type Arbiter struct {
Nodes []Node
QuorumThreshold float64
Comment on lines +23 to +25

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

suggestion (bug_risk): Validate or constrain QuorumThreshold to avoid surprising behavior

If QuorumThreshold is set <= 0 or > 1, quorum checks could effectively always fail or always pass. Please either clamp this to [0,1] or enforce validation (e.g., in a constructor/setter) so invalid thresholds are rejected early.

Suggested implementation:

 // Arbiter handles quorum and reputation
type Arbiter struct {
	Nodes           []Node
	QuorumThreshold float64
}

// NewArbiter constructs an Arbiter with a validated quorum threshold.
// QuorumThreshold must be in the (0,1] range; values outside this range will
// cause NewArbiter to return an error.
func NewArbiter(nodes []Node, quorumThreshold float64) (*Arbiter, error) {
	if quorumThreshold <= 0 || quorumThreshold > 1 {
		return nil, fmt.Errorf("quorumThreshold must be in the range (0,1], got %f", quorumThreshold)
	}

	return &Arbiter{
		Nodes:           nodes,
		QuorumThreshold: quorumThreshold,
	}, nil
}
  1. Ensure fmt is imported at the top of phoenix_os/arbiter/src/arbiter.go, e.g.:
    import "fmt", or added to the existing import block.
  2. Update any existing code that instantiates Arbiter via struct literals to instead call NewArbiter (or, if you must keep struct literals, make sure they always set a valid QuorumThreshold).
  3. If there are other constructors or setters for Arbiter elsewhere in the file, align them with the same validation logic so QuorumThreshold is always constrained to (0,1].

}
Comment on lines +15 to +26

// CalculateQuorum validates quorum based on reputation
func (a *Arbiter) CalculateQuorum(votes map[string]bool) bool {
var totalReputation float64
var positiveReputation float64
for _, node := range a.Nodes {
if !node.Authorized {
continue
}
totalReputation += node.Reputation
if vote, ok := votes[node.ID]; ok && vote {
positiveReputation += node.Reputation
Comment on lines +36 to +38

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Reject negative reputation weights in quorum math

The quorum calculation sums raw Reputation values directly into both numerator and denominator without validating sign, so negative weights can distort the ratio (e.g., make it exceed 1, go negative, or let a single negative-weight vote force or block quorum). Since reputation is a free float64, this creates incorrect consensus outcomes whenever any authorized node’s score drops below zero.

Useful? React with 👍 / 👎.

Comment on lines +32 to +38
}
}
if totalReputation == 0 {
return false
}
return (positiveReputation / totalReputation) >= a.QuorumThreshold

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Enforce a non-zero quorum threshold

CalculateQuorum fails open when QuorumThreshold is left at its Go zero value (0): with any authorized nodes present, positiveReputation/totalReputation can be 0, and 0 >= 0 returns true. That means a caller that forgets to initialize the threshold can approve quorum even when nobody voted yes, which defeats the safety property this arbiter is meant to enforce.

Useful? React with 👍 / 👎.

}
Comment on lines +41 to +45

func SolveMiniMax(m PayoffMatrix) int {
// Simple pure strategy minimax for demonstration
bestDefenderAction := 0
Expand Down
40 changes: 32 additions & 8 deletions phoenix_os/arbiter/src/arbiter_test.go
Original file line number Diff line number Diff line change
@@ -1,14 +1,38 @@
package main

import "testing"
import (
"testing"
)

func TestMiniMax(t *testing.T) {
matrix := PayoffMatrix{
{{10, -10}, {0, 0}},
{{0, 0}, {5, -5}},
func TestCalculateQuorum(t *testing.T) {
arbiter := Arbiter{
Nodes: []Node{
{"node1", 1.0, true},
{"node2", 2.0, true},
{"node3", 1.0, false},
},
QuorumThreshold: 0.6,
}
Comment on lines +7 to 15
action := SolveMiniMax(matrix)
if action != 1 {
t.Errorf("Expected action 1, got %d", action)

votes := map[string]bool{
"node1": true,
"node2": false,
"node3": true,
}

// Reputation: node1=1, node2=2, total=3
// Positive: node1=1, node2=0, total=1
// 1/3 = 0.33 < 0.6 => false
if arbiter.CalculateQuorum(votes) {
t.Errorf("Expected false for 0.33 threshold")
}

votes2 := map[string]bool{
"node1": true,
"node2": true,
}
// (1+2)/3 = 1.0 >= 0.6 => true
if !arbiter.CalculateQuorum(votes2) {
t.Errorf("Expected true for 1.0 threshold")
}
}
Loading