154 lines
5.2 KiB
Go
154 lines
5.2 KiB
Go
package peer
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
"time"
|
|
|
|
"cloud.o-forge.io/core/oc-lib/models/utils"
|
|
"cloud.o-forge.io/core/oc-lib/tools"
|
|
)
|
|
|
|
type PeerRelation int
|
|
|
|
const (
|
|
NONE PeerRelation = iota
|
|
SELF
|
|
PARTNER
|
|
BLACKLIST
|
|
PENDING_PARTNER
|
|
)
|
|
|
|
var path = []string{"unknown", "self", "partner", "blacklist", "partner"}
|
|
|
|
func GetRelationPath(str string) int {
|
|
for i, p := range path {
|
|
if str == p {
|
|
return i
|
|
}
|
|
}
|
|
return -1
|
|
}
|
|
|
|
func (m PeerRelation) Path() string {
|
|
return path[m]
|
|
}
|
|
|
|
func (m PeerRelation) String() string {
|
|
return strings.ToUpper(path[m])
|
|
}
|
|
|
|
func (m PeerRelation) EnumIndex() int {
|
|
return int(m)
|
|
}
|
|
|
|
// BehaviorWarning records a single misbehavior observed by a trusted service.
|
|
type BehaviorWarning struct {
|
|
At time.Time `json:"at" bson:"at"`
|
|
ReporterApp string `json:"reporter_app" bson:"reporter_app"`
|
|
Severity tools.BehaviorSeverity `json:"severity" bson:"severity"`
|
|
Reason string `json:"reason" bson:"reason"`
|
|
Evidence string `json:"evidence,omitempty" bson:"evidence,omitempty"`
|
|
}
|
|
|
|
// Peer is a struct that represents a peer
|
|
type Peer struct {
|
|
utils.AbstractObject
|
|
|
|
Verify bool `json:"verify" bson:"verify"`
|
|
PeerID string `json:"peer_id" bson:"peer_id" validate:"required"`
|
|
|
|
APIUrl string `json:"api_url" bson:"api_url" validate:"required"` // Url is the URL of the peer (base64url)
|
|
StreamAddress string `json:"stream_address" bson:"stream_address" validate:"required"` // Url is the URL of the peer (base64url)
|
|
NATSAddress string `json:"nats_address" bson:"nats_address" validate:"required"`
|
|
WalletAddress string `json:"wallet_address" bson:"wallet_address" validate:"required"` // WalletAddress is the wallet address of the peer
|
|
PublicKey string `json:"public_key" bson:"public_key" validate:"required"` // PublicKey is the public key of the peer
|
|
Relation PeerRelation `json:"relation" bson:"relation" default:"0"`
|
|
ServicesState map[string]int `json:"services_state,omitempty" bson:"services_state,omitempty"`
|
|
FailedExecution []PeerExecution `json:"failed_execution" bson:"failed_execution"` // FailedExecution is the list of failed executions, to be retried
|
|
|
|
// Trust scoring — maintained by oc-discovery from PEER_BEHAVIOR_EVENT reports.
|
|
TrustScore float64 `json:"trust_score" bson:"trust_score" default:"100"`
|
|
BlacklistReason string `json:"blacklist_reason,omitempty" bson:"blacklist_reason,omitempty"`
|
|
BehaviorWarnings []BehaviorWarning `json:"behavior_warnings,omitempty" bson:"behavior_warnings,omitempty"`
|
|
}
|
|
|
|
func (ao *Peer) VerifyAuth(callName string, request *tools.APIRequest) bool {
|
|
return true
|
|
}
|
|
|
|
// BlacklistThreshold is the trust score below which a peer is auto-blacklisted.
|
|
const BlacklistThreshold = 20.0
|
|
|
|
// ApplyBehaviorReport records a misbehavior, deducts the trust penalty, and
|
|
// returns true when the trust score has fallen below BlacklistThreshold so the
|
|
// caller can trigger the relation change.
|
|
func (p *Peer) ApplyBehaviorReport(r tools.PeerBehaviorReport) (shouldBlacklist bool) {
|
|
p.BehaviorWarnings = append(p.BehaviorWarnings, BehaviorWarning{
|
|
At: r.At,
|
|
ReporterApp: r.ReporterApp,
|
|
Severity: r.Severity,
|
|
Reason: r.Reason,
|
|
Evidence: r.Evidence,
|
|
})
|
|
if p.TrustScore == 0 {
|
|
p.TrustScore = 100 // initialise if never set
|
|
}
|
|
p.TrustScore -= r.Severity.Penalty()
|
|
if p.TrustScore < 0 {
|
|
p.TrustScore = 0
|
|
}
|
|
if p.TrustScore <= BlacklistThreshold {
|
|
p.BlacklistReason = r.Reason
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
// ResetTrust clears all behavior history and resets the trust score to 100.
|
|
// Must be called when a peer relation is manually set to NONE or PARTNER.
|
|
func (p *Peer) ResetTrust() {
|
|
p.TrustScore = 100
|
|
p.BlacklistReason = ""
|
|
p.BehaviorWarnings = nil
|
|
}
|
|
|
|
// AddExecution adds an execution to the list of failed executions
|
|
func (ao *Peer) AddExecution(exec PeerExecution) {
|
|
found := false
|
|
for _, v := range ao.FailedExecution { // Check if the execution is already in the list
|
|
if v.Url == exec.Url && v.Method == exec.Method && fmt.Sprint(v.Body) == fmt.Sprint(exec.Body) {
|
|
found = true
|
|
break
|
|
}
|
|
}
|
|
if !found {
|
|
ao.FailedExecution = append(ao.FailedExecution, exec)
|
|
}
|
|
}
|
|
|
|
// RemoveExecution removes an execution from the list of failed executions
|
|
func (ao *Peer) RemoveExecution(exec PeerExecution) {
|
|
new := []PeerExecution{}
|
|
for i, v := range ao.FailedExecution {
|
|
if !(v.Url == exec.Url && v.Method == exec.Method && fmt.Sprint(v.Body) == fmt.Sprint(exec.Body)) {
|
|
new = append(new, ao.FailedExecution[i])
|
|
}
|
|
}
|
|
ao.FailedExecution = new
|
|
}
|
|
|
|
// LaunchPeerExecution launches an execution on a peer
|
|
func (p *Peer) LaunchPeerExecution(peerID string, dataID string, dt tools.DataType, method tools.METHOD, body interface{}, caller *tools.HTTPCaller) (map[string]interface{}, error) {
|
|
p.UUID = peerID
|
|
return cache.LaunchPeerExecution(peerID, dataID, dt, method, body, caller) // Launch the execution on the peer through the cache
|
|
}
|
|
func (d *Peer) GetAccessor(request *tools.APIRequest) utils.Accessor {
|
|
data := NewAccessor(request) // Create a new instance of the accessor
|
|
return data
|
|
}
|
|
|
|
func (r *Peer) CanDelete() bool {
|
|
return false // only draft order can be deleted
|
|
}
|