From c678d2060851c6b7756943e3419dbbabbd730677 Mon Sep 17 00:00:00 2001 From: Virgil Date: Mon, 30 Mar 2026 19:44:05 +0000 Subject: [PATCH] refactor(repo): prefer AX error names Co-Authored-By: Virgil --- docs/architecture.md | 6 +-- docs/history.md | 4 +- docs/routing.md | 20 +++---- node/controller.go | 10 ++-- node/dispatcher.go | 33 +++++++----- node/errors.go | 16 ++++-- node/identity.go | 2 +- node/levin/connection.go | 2 +- node/levin/header.go | 31 ++++++++--- node/levin/storage.go | 112 +++++++++++++++++++++++---------------- node/levin/varint.go | 24 +++++---- node/message.go | 42 ++++++++++----- node/protocol.go | 4 +- node/transport.go | 2 +- node/worker.go | 10 ++-- specs/node-levin.md | 32 +++++------ 16 files changed, 211 insertions(+), 139 deletions(-) diff --git a/docs/architecture.md b/docs/architecture.md index 105c0ec..49f8af1 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -183,9 +183,9 @@ Auto-connect: if the target peer is not yet connected, `sendRequest` calls `tran | `IntentCustom` | `0xFF` | Application-level sub-protocols | **Sentinel errors**: -- `ErrThreatScoreExceeded` — threat circuit breaker fired -- `ErrUnknownIntent` — no handler registered for the `IntentID` -- `ErrNilPacket` — nil packet passed to `Dispatch` +- `ErrorThreatScoreExceeded` — threat circuit breaker fired +- `ErrorUnknownIntent` — no handler registered for the `IntentID` +- `ErrorNilPacket` — nil packet passed to `Dispatch` ### bundle.go — TIM Deployment Bundles diff --git a/docs/history.md b/docs/history.md index 52ea3f2..369614a 100644 --- a/docs/history.md +++ b/docs/history.md @@ -57,8 +57,8 @@ Replaced the dispatcher stub with a complete implementation. 10 test functions, Design decisions recorded at the time: 1. `IntentHandler` as a `func` type rather than an interface, matching the `MessageHandler` pattern already used in `transport.go`. Lighter weight for a single-method contract. -2. Sentinel errors (`ErrThreatScoreExceeded`, `ErrUnknownIntent`, `ErrNilPacket`) rather than silent drops. Callers can inspect outcomes; the dispatcher still logs at WARN level regardless. -3. Threat check occurs before intent routing. A high-threat packet with an unknown intent returns `ErrThreatScoreExceeded`, not `ErrUnknownIntent`. The circuit breaker is the first line of defence. +2. Sentinel errors (`ErrorThreatScoreExceeded`, `ErrorUnknownIntent`, `ErrorNilPacket`) rather than silent drops. Callers can inspect outcomes; the dispatcher still logs at WARN level regardless. +3. Threat check occurs before intent routing. A high-threat packet with an unknown intent returns `ErrorThreatScoreExceeded`, not `ErrorUnknownIntent`. The circuit breaker is the first line of defence. 4. Threshold fixed at 50,000 (a constant, not configurable) to match the original stub specification. The value sits at approximately 76% of `uint16` max. 5. `sync.RWMutex` for the handler map. Registration is infrequent (write lock); dispatch is read-heavy (read lock). diff --git a/docs/routing.md b/docs/routing.md index 2bb3405..9fc6e82 100644 --- a/docs/routing.md +++ b/docs/routing.md @@ -57,9 +57,9 @@ err := dispatcher.Dispatch(packet) ### Dispatch Flow -1. **Nil check** -- returns `ErrNilPacket` immediately. -2. **Threat circuit breaker** -- if `ThreatScore > 50,000`, the packet is dropped and `ErrThreatScoreExceeded` is returned. A warning is logged. -3. **Intent lookup** -- finds the handler registered for `pkt.Header.IntentID`. If none exists, the packet is dropped and `ErrUnknownIntent` is returned. +1. **Nil check** -- returns `ErrorNilPacket` immediately. +2. **Threat circuit breaker** -- if `ThreatScore > 50,000`, the packet is dropped and `ErrorThreatScoreExceeded` is returned. A warning is logged. +3. **Intent lookup** -- finds the handler registered for `pkt.Header.IntentID`. If none exists, the packet is dropped and `ErrorUnknownIntent` is returned. 4. **Handler invocation** -- calls the handler and returns its result. ### Threat Circuit Breaker @@ -74,8 +74,8 @@ Dropped packets are logged at WARN level with the threat score, threshold, inten ### Design Rationale -- **High-threat packets are not dispatched**. The dispatcher logs them and returns `ErrThreatScoreExceeded` to the caller; the sender still receives no protocol-level response. -- **Unknown intents are not forwarded**. The dispatcher logs them and returns `ErrUnknownIntent`, avoiding back-pressure on the transport layer. +- **High-threat packets are not dispatched**. The dispatcher logs them and returns `ErrorThreatScoreExceeded` to the caller; the sender still receives no protocol-level response. +- **Unknown intents are not forwarded**. The dispatcher logs them and returns `ErrorUnknownIntent`, avoiding back-pressure on the transport layer. - **Handler errors propagate** to the caller, allowing upstream code to record failures. ## Intent Constants @@ -100,13 +100,13 @@ const ( ```go var ( - ErrThreatScoreExceeded = core.E( + ErrorThreatScoreExceeded = core.E( "Dispatcher.Dispatch", core.Sprintf("packet rejected: threat score exceeds safety threshold (%d)", ThreatScoreThreshold), nil, ) - ErrUnknownIntent = core.E("Dispatcher.Dispatch", "packet dropped: unknown intent", nil) - ErrNilPacket = core.E("Dispatcher.Dispatch", "nil packet", nil) + ErrorUnknownIntent = core.E("Dispatcher.Dispatch", "packet dropped: unknown intent", nil) + ErrorNilPacket = core.E("Dispatcher.Dispatch", "nil packet", nil) ) ``` @@ -124,11 +124,11 @@ if err != nil { // Route through the dispatcher if err := dispatcher.Dispatch(packet); err != nil { - if errors.Is(err, node.ErrThreatScoreExceeded) { + if errors.Is(err, node.ErrorThreatScoreExceeded) { // Packet was too threatening -- already logged return nil } - if errors.Is(err, node.ErrUnknownIntent) { + if errors.Is(err, node.ErrorUnknownIntent) { // No handler for this intent -- already logged return nil } diff --git a/node/controller.go b/node/controller.go index 5724b9a..90e9085 100644 --- a/node/controller.go +++ b/node/controller.go @@ -118,7 +118,7 @@ func (c *Controller) sendRequest(peerID string, msg *Message, timeout time.Durat func (c *Controller) GetRemoteStats(peerID string) (*StatsPayload, error) { identity := c.node.GetIdentity() if identity == nil { - return nil, ErrIdentityNotInitialized + return nil, ErrorIdentityNotInitialized } msg, err := NewMessage(MsgGetStats, identity.ID, peerID, nil) @@ -143,7 +143,7 @@ func (c *Controller) GetRemoteStats(peerID string) (*StatsPayload, error) { func (c *Controller) StartRemoteMiner(peerID, minerType, profileID string, configOverride RawMessage) error { identity := c.node.GetIdentity() if identity == nil { - return ErrIdentityNotInitialized + return ErrorIdentityNotInitialized } if minerType == "" { @@ -182,7 +182,7 @@ func (c *Controller) StartRemoteMiner(peerID, minerType, profileID string, confi func (c *Controller) StopRemoteMiner(peerID, minerName string) error { identity := c.node.GetIdentity() if identity == nil { - return ErrIdentityNotInitialized + return ErrorIdentityNotInitialized } payload := StopMinerPayload{ @@ -215,7 +215,7 @@ func (c *Controller) StopRemoteMiner(peerID, minerName string) error { func (c *Controller) GetRemoteLogs(peerID, minerName string, lines int) ([]string, error) { identity := c.node.GetIdentity() if identity == nil { - return nil, ErrIdentityNotInitialized + return nil, ErrorIdentityNotInitialized } payload := GetLogsPayload{ @@ -274,7 +274,7 @@ func (c *Controller) GetAllStats() map[string]*StatsPayload { func (c *Controller) PingPeer(peerID string) (float64, error) { identity := c.node.GetIdentity() if identity == nil { - return 0, ErrIdentityNotInitialized + return 0, ErrorIdentityNotInitialized } sentAt := time.Now() diff --git a/node/dispatcher.go b/node/dispatcher.go index 276be96..769217e 100644 --- a/node/dispatcher.go +++ b/node/dispatcher.go @@ -100,16 +100,16 @@ func (d *Dispatcher) Handlers() iter.Seq2[byte, IntentHandler] { // and then to the appropriate intent handler. // // Behaviour: -// - Returns ErrThreatScoreExceeded if the packet's ThreatScore exceeds the +// - Returns ErrorThreatScoreExceeded if the packet's ThreatScore exceeds the // threshold (packet is dropped and logged). -// - Returns ErrUnknownIntent if no handler is registered for the IntentID +// - Returns ErrorUnknownIntent if no handler is registered for the IntentID // (packet is dropped and logged). // - Returns nil on successful delivery to a handler, or any error the // handler itself returns. -// - A nil packet returns ErrNilPacket immediately. +// - A nil packet returns ErrorNilPacket immediately. func (d *Dispatcher) Dispatch(pkt *ueps.ParsedPacket) error { if pkt == nil { - return ErrNilPacket + return ErrorNilPacket } // 1. Threat circuit breaker (L5 guard) @@ -120,7 +120,7 @@ func (d *Dispatcher) Dispatch(pkt *ueps.ParsedPacket) error { "intent_id": core.Sprintf("0x%02X", pkt.Header.IntentID), "version": pkt.Header.Version, }) - return ErrThreatScoreExceeded + return ErrorThreatScoreExceeded } // 2. Intent routing (L9 semantic) @@ -133,7 +133,7 @@ func (d *Dispatcher) Dispatch(pkt *ueps.ParsedPacket) error { "intent_id": core.Sprintf("0x%02X", pkt.Header.IntentID), "version": pkt.Header.Version, }) - return ErrUnknownIntent + return ErrorUnknownIntent } return handler(pkt) @@ -141,14 +141,23 @@ func (d *Dispatcher) Dispatch(pkt *ueps.ParsedPacket) error { // Sentinel errors returned by Dispatch. var ( - // ErrThreatScoreExceeded is returned when a packet's ThreatScore exceeds + // ErrorThreatScoreExceeded is returned when a packet's ThreatScore exceeds // the safety threshold. - ErrThreatScoreExceeded = core.E("Dispatcher.Dispatch", core.Sprintf("packet rejected: threat score exceeds safety threshold (%d)", ThreatScoreThreshold), nil) + ErrorThreatScoreExceeded = core.E("Dispatcher.Dispatch", core.Sprintf("packet rejected: threat score exceeds safety threshold (%d)", ThreatScoreThreshold), nil) - // ErrUnknownIntent is returned when no handler is registered for the + // Deprecated: use ErrorThreatScoreExceeded. + ErrThreatScoreExceeded = ErrorThreatScoreExceeded + + // ErrorUnknownIntent is returned when no handler is registered for the // packet's IntentID. - ErrUnknownIntent = core.E("Dispatcher.Dispatch", "packet dropped: unknown intent", nil) + ErrorUnknownIntent = core.E("Dispatcher.Dispatch", "packet dropped: unknown intent", nil) - // ErrNilPacket is returned when a nil packet is passed to Dispatch. - ErrNilPacket = core.E("Dispatcher.Dispatch", "nil packet", nil) + // Deprecated: use ErrorUnknownIntent. + ErrUnknownIntent = ErrorUnknownIntent + + // ErrorNilPacket is returned when a nil packet is passed to Dispatch. + ErrorNilPacket = core.E("Dispatcher.Dispatch", "nil packet", nil) + + // Deprecated: use ErrorNilPacket. + ErrNilPacket = ErrorNilPacket ) diff --git a/node/errors.go b/node/errors.go index 96cf152..1ee3f82 100644 --- a/node/errors.go +++ b/node/errors.go @@ -2,13 +2,19 @@ package node import core "dappco.re/go/core" -// Sentinel errors shared across the node package. +// Shared error sentinels for the node package. var ( - // ErrIdentityNotInitialized is returned when a node operation requires + // ErrorIdentityNotInitialized is returned when a node operation requires // a node identity but none has been generated or loaded. - ErrIdentityNotInitialized = core.E("node", "node identity not initialized", nil) + ErrorIdentityNotInitialized = core.E("node", "node identity not initialized", nil) - // ErrMinerManagerNotConfigured is returned when a miner operation is + // Deprecated: use ErrorIdentityNotInitialized. + ErrIdentityNotInitialized = ErrorIdentityNotInitialized + + // ErrorMinerManagerNotConfigured is returned when a miner operation is // attempted but no MinerManager has been set on the Worker. - ErrMinerManagerNotConfigured = core.E("node", "miner manager not configured", nil) + ErrorMinerManagerNotConfigured = core.E("node", "miner manager not configured", nil) + + // Deprecated: use ErrorMinerManagerNotConfigured. + ErrMinerManagerNotConfigured = ErrorMinerManagerNotConfigured ) diff --git a/node/identity.go b/node/identity.go index a6cb702..636dc82 100644 --- a/node/identity.go +++ b/node/identity.go @@ -191,7 +191,7 @@ func (n *NodeManager) DeriveSharedSecret(peerPubKeyBase64 string) ([]byte, error defer n.mu.RUnlock() if n.privateKey == nil { - return nil, ErrIdentityNotInitialized + return nil, ErrorIdentityNotInitialized } // Load peer's public key diff --git a/node/levin/connection.go b/node/levin/connection.go index 20d7c7d..63a748e 100644 --- a/node/levin/connection.go +++ b/node/levin/connection.go @@ -131,7 +131,7 @@ func (c *Connection) ReadPacket() (Header, []byte, error) { // Check against the connection-specific payload limit. if h.PayloadSize > c.MaxPayloadSize { - return Header{}, nil, ErrPayloadTooBig + return Header{}, nil, ErrorPayloadTooBig } // Empty payload is valid — return nil data without allocation. diff --git a/node/levin/header.go b/node/levin/header.go index bd7602f..b8b465a 100644 --- a/node/levin/header.go +++ b/node/levin/header.go @@ -22,10 +22,19 @@ const MaxPayloadSize uint64 = 100 * 1024 * 1024 // Return-code constants carried in every Levin response. const ( - ReturnOK int32 = 0 - ReturnErrConnection int32 = -1 - ReturnErrFormat int32 = -7 - ReturnErrSignature int32 = -13 + ReturnOK int32 = 0 + ReturnErrorConnection int32 = -1 + ReturnErrorFormat int32 = -7 + ReturnErrorSignature int32 = -13 + + // Deprecated: use ReturnErrorConnection. + ReturnErrConnection = ReturnErrorConnection + + // Deprecated: use ReturnErrorFormat. + ReturnErrFormat = ReturnErrorFormat + + // Deprecated: use ReturnErrorSignature. + ReturnErrSignature = ReturnErrorSignature ) // Command IDs for the CryptoNote P2P layer. @@ -43,8 +52,14 @@ const ( // Sentinel errors returned by DecodeHeader. var ( - ErrBadSignature = core.E("levin", "bad signature", nil) - ErrPayloadTooBig = core.E("levin", "payload exceeds maximum size", nil) + ErrorBadSignature = core.E("levin", "bad signature", nil) + ErrorPayloadTooBig = core.E("levin", "payload exceeds maximum size", nil) + + // Deprecated: use ErrorBadSignature. + ErrBadSignature = ErrorBadSignature + + // Deprecated: use ErrorPayloadTooBig. + ErrPayloadTooBig = ErrorPayloadTooBig ) // Header is the 33-byte packed header that prefixes every Levin message. @@ -87,11 +102,11 @@ func DecodeHeader(buf [HeaderSize]byte) (Header, error) { var h Header h.Signature = binary.LittleEndian.Uint64(buf[0:8]) if h.Signature != Signature { - return Header{}, ErrBadSignature + return Header{}, ErrorBadSignature } h.PayloadSize = binary.LittleEndian.Uint64(buf[8:16]) if h.PayloadSize > MaxPayloadSize { - return Header{}, ErrPayloadTooBig + return Header{}, ErrorPayloadTooBig } h.ExpectResponse = buf[16] == 0x01 h.Command = binary.LittleEndian.Uint32(buf[17:21]) diff --git a/node/levin/storage.go b/node/levin/storage.go index 85b1428..a03d303 100644 --- a/node/levin/storage.go +++ b/node/levin/storage.go @@ -40,12 +40,30 @@ const ( // Sentinel errors for storage encoding and decoding. var ( - ErrStorageBadSignature = core.E("levin.storage", "bad storage signature", nil) - ErrStorageTruncated = core.E("levin.storage", "truncated storage data", nil) - ErrStorageBadVersion = core.E("levin.storage", "unsupported storage version", nil) - ErrStorageNameTooLong = core.E("levin.storage", "entry name exceeds 255 bytes", nil) - ErrStorageTypeMismatch = core.E("levin.storage", "value type mismatch", nil) - ErrStorageUnknownType = core.E("levin.storage", "unknown type tag", nil) + ErrorStorageBadSignature = core.E("levin.storage", "bad storage signature", nil) + ErrorStorageTruncated = core.E("levin.storage", "truncated storage data", nil) + ErrorStorageBadVersion = core.E("levin.storage", "unsupported storage version", nil) + ErrorStorageNameTooLong = core.E("levin.storage", "entry name exceeds 255 bytes", nil) + ErrorStorageTypeMismatch = core.E("levin.storage", "value type mismatch", nil) + ErrorStorageUnknownType = core.E("levin.storage", "unknown type tag", nil) + + // Deprecated: use ErrorStorageBadSignature. + ErrStorageBadSignature = ErrorStorageBadSignature + + // Deprecated: use ErrorStorageTruncated. + ErrStorageTruncated = ErrorStorageTruncated + + // Deprecated: use ErrorStorageBadVersion. + ErrStorageBadVersion = ErrorStorageBadVersion + + // Deprecated: use ErrorStorageNameTooLong. + ErrStorageNameTooLong = ErrorStorageNameTooLong + + // Deprecated: use ErrorStorageTypeMismatch. + ErrStorageTypeMismatch = ErrorStorageTypeMismatch + + // Deprecated: use ErrorStorageUnknownType. + ErrStorageUnknownType = ErrorStorageUnknownType ) // Section is an ordered map of named values forming a portable storage section. @@ -179,7 +197,7 @@ func ObjectArrayVal(vs []Section) Value { // AsUint64 returns the uint64 value or an error on type mismatch. func (v Value) AsUint64() (uint64, error) { if v.Type != TypeUint64 { - return 0, ErrStorageTypeMismatch + return 0, ErrorStorageTypeMismatch } return v.uintVal, nil } @@ -187,7 +205,7 @@ func (v Value) AsUint64() (uint64, error) { // AsUint32 returns the uint32 value or an error on type mismatch. func (v Value) AsUint32() (uint32, error) { if v.Type != TypeUint32 { - return 0, ErrStorageTypeMismatch + return 0, ErrorStorageTypeMismatch } return uint32(v.uintVal), nil } @@ -195,7 +213,7 @@ func (v Value) AsUint32() (uint32, error) { // AsUint16 returns the uint16 value or an error on type mismatch. func (v Value) AsUint16() (uint16, error) { if v.Type != TypeUint16 { - return 0, ErrStorageTypeMismatch + return 0, ErrorStorageTypeMismatch } return uint16(v.uintVal), nil } @@ -203,7 +221,7 @@ func (v Value) AsUint16() (uint16, error) { // AsUint8 returns the uint8 value or an error on type mismatch. func (v Value) AsUint8() (uint8, error) { if v.Type != TypeUint8 { - return 0, ErrStorageTypeMismatch + return 0, ErrorStorageTypeMismatch } return uint8(v.uintVal), nil } @@ -211,7 +229,7 @@ func (v Value) AsUint8() (uint8, error) { // AsInt64 returns the int64 value or an error on type mismatch. func (v Value) AsInt64() (int64, error) { if v.Type != TypeInt64 { - return 0, ErrStorageTypeMismatch + return 0, ErrorStorageTypeMismatch } return v.intVal, nil } @@ -219,7 +237,7 @@ func (v Value) AsInt64() (int64, error) { // AsInt32 returns the int32 value or an error on type mismatch. func (v Value) AsInt32() (int32, error) { if v.Type != TypeInt32 { - return 0, ErrStorageTypeMismatch + return 0, ErrorStorageTypeMismatch } return int32(v.intVal), nil } @@ -227,7 +245,7 @@ func (v Value) AsInt32() (int32, error) { // AsInt16 returns the int16 value or an error on type mismatch. func (v Value) AsInt16() (int16, error) { if v.Type != TypeInt16 { - return 0, ErrStorageTypeMismatch + return 0, ErrorStorageTypeMismatch } return int16(v.intVal), nil } @@ -235,7 +253,7 @@ func (v Value) AsInt16() (int16, error) { // AsInt8 returns the int8 value or an error on type mismatch. func (v Value) AsInt8() (int8, error) { if v.Type != TypeInt8 { - return 0, ErrStorageTypeMismatch + return 0, ErrorStorageTypeMismatch } return int8(v.intVal), nil } @@ -243,7 +261,7 @@ func (v Value) AsInt8() (int8, error) { // AsBool returns the bool value or an error on type mismatch. func (v Value) AsBool() (bool, error) { if v.Type != TypeBool { - return false, ErrStorageTypeMismatch + return false, ErrorStorageTypeMismatch } return v.boolVal, nil } @@ -251,7 +269,7 @@ func (v Value) AsBool() (bool, error) { // AsDouble returns the float64 value or an error on type mismatch. func (v Value) AsDouble() (float64, error) { if v.Type != TypeDouble { - return 0, ErrStorageTypeMismatch + return 0, ErrorStorageTypeMismatch } return v.floatVal, nil } @@ -259,7 +277,7 @@ func (v Value) AsDouble() (float64, error) { // AsString returns the byte-string value or an error on type mismatch. func (v Value) AsString() ([]byte, error) { if v.Type != TypeString { - return nil, ErrStorageTypeMismatch + return nil, ErrorStorageTypeMismatch } return v.bytesVal, nil } @@ -267,7 +285,7 @@ func (v Value) AsString() ([]byte, error) { // AsSection returns the nested Section or an error on type mismatch. func (v Value) AsSection() (Section, error) { if v.Type != TypeObject { - return nil, ErrStorageTypeMismatch + return nil, ErrorStorageTypeMismatch } return v.objectVal, nil } @@ -279,7 +297,7 @@ func (v Value) AsSection() (Section, error) { // AsUint64Array returns the []uint64 array or an error on type mismatch. func (v Value) AsUint64Array() ([]uint64, error) { if v.Type != (ArrayFlag | TypeUint64) { - return nil, ErrStorageTypeMismatch + return nil, ErrorStorageTypeMismatch } return v.uint64Array, nil } @@ -287,7 +305,7 @@ func (v Value) AsUint64Array() ([]uint64, error) { // AsUint32Array returns the []uint32 array or an error on type mismatch. func (v Value) AsUint32Array() ([]uint32, error) { if v.Type != (ArrayFlag | TypeUint32) { - return nil, ErrStorageTypeMismatch + return nil, ErrorStorageTypeMismatch } return v.uint32Array, nil } @@ -295,7 +313,7 @@ func (v Value) AsUint32Array() ([]uint32, error) { // AsStringArray returns the [][]byte array or an error on type mismatch. func (v Value) AsStringArray() ([][]byte, error) { if v.Type != (ArrayFlag | TypeString) { - return nil, ErrStorageTypeMismatch + return nil, ErrorStorageTypeMismatch } return v.stringArray, nil } @@ -303,7 +321,7 @@ func (v Value) AsStringArray() ([][]byte, error) { // AsSectionArray returns the []Section array or an error on type mismatch. func (v Value) AsSectionArray() ([]Section, error) { if v.Type != (ArrayFlag | TypeObject) { - return nil, ErrStorageTypeMismatch + return nil, ErrorStorageTypeMismatch } return v.objectArray, nil } @@ -348,7 +366,7 @@ func encodeSection(buf []byte, s Section) ([]byte, error) { // Name: uint8 length + raw bytes. if len(name) > 255 { - return nil, ErrStorageNameTooLong + return nil, ErrorStorageNameTooLong } buf = append(buf, byte(len(name))) buf = append(buf, name...) @@ -431,7 +449,7 @@ func encodeValue(buf []byte, v Value) ([]byte, error) { return encodeSection(buf, v.objectVal) default: - return nil, core.E("levin.encodeValue", core.Sprintf("unknown type tag: 0x%02x", v.Type), ErrStorageUnknownType) + return nil, core.E("levin.encodeValue", core.Sprintf("unknown type tag: 0x%02x", v.Type), ErrorStorageUnknownType) } } @@ -478,7 +496,7 @@ func encodeArray(buf []byte, v Value) ([]byte, error) { return buf, nil default: - return nil, core.E("levin.encodeArray", core.Sprintf("unknown type tag: array of 0x%02x", elemType), ErrStorageUnknownType) + return nil, core.E("levin.encodeArray", core.Sprintf("unknown type tag: array of 0x%02x", elemType), ErrorStorageUnknownType) } } @@ -492,7 +510,7 @@ func encodeArray(buf []byte, v Value) ([]byte, error) { // section, err := DecodeStorage(data) func DecodeStorage(data []byte) (Section, error) { if len(data) < StorageHeaderSize { - return nil, ErrStorageTruncated + return nil, ErrorStorageTruncated } sigA := binary.LittleEndian.Uint32(data[0:4]) @@ -500,10 +518,10 @@ func DecodeStorage(data []byte) (Section, error) { ver := data[8] if sigA != StorageSignatureA || sigB != StorageSignatureB { - return nil, ErrStorageBadSignature + return nil, ErrorStorageBadSignature } if ver != StorageVersion { - return nil, ErrStorageBadVersion + return nil, ErrorStorageBadVersion } s, _, err := decodeSection(data[StorageHeaderSize:]) @@ -524,21 +542,21 @@ func decodeSection(buf []byte) (Section, int, error) { for range count { // Name length (1 byte). if off >= len(buf) { - return nil, 0, ErrStorageTruncated + return nil, 0, ErrorStorageTruncated } nameLen := int(buf[off]) off++ // Name bytes. if off+nameLen > len(buf) { - return nil, 0, ErrStorageTruncated + return nil, 0, ErrorStorageTruncated } name := string(buf[off : off+nameLen]) off += nameLen // Type tag (1 byte). if off >= len(buf) { - return nil, 0, ErrStorageTruncated + return nil, 0, ErrorStorageTruncated } tag := buf[off] off++ @@ -567,68 +585,68 @@ func decodeValue(buf []byte, tag uint8) (Value, int, error) { switch tag { case TypeUint64: if len(buf) < 8 { - return Value{}, 0, ErrStorageTruncated + return Value{}, 0, ErrorStorageTruncated } v := binary.LittleEndian.Uint64(buf[:8]) return Value{Type: TypeUint64, uintVal: v}, 8, nil case TypeInt64: if len(buf) < 8 { - return Value{}, 0, ErrStorageTruncated + return Value{}, 0, ErrorStorageTruncated } v := int64(binary.LittleEndian.Uint64(buf[:8])) return Value{Type: TypeInt64, intVal: v}, 8, nil case TypeDouble: if len(buf) < 8 { - return Value{}, 0, ErrStorageTruncated + return Value{}, 0, ErrorStorageTruncated } bits := binary.LittleEndian.Uint64(buf[:8]) return Value{Type: TypeDouble, floatVal: math.Float64frombits(bits)}, 8, nil case TypeUint32: if len(buf) < 4 { - return Value{}, 0, ErrStorageTruncated + return Value{}, 0, ErrorStorageTruncated } v := binary.LittleEndian.Uint32(buf[:4]) return Value{Type: TypeUint32, uintVal: uint64(v)}, 4, nil case TypeInt32: if len(buf) < 4 { - return Value{}, 0, ErrStorageTruncated + return Value{}, 0, ErrorStorageTruncated } v := int32(binary.LittleEndian.Uint32(buf[:4])) return Value{Type: TypeInt32, intVal: int64(v)}, 4, nil case TypeUint16: if len(buf) < 2 { - return Value{}, 0, ErrStorageTruncated + return Value{}, 0, ErrorStorageTruncated } v := binary.LittleEndian.Uint16(buf[:2]) return Value{Type: TypeUint16, uintVal: uint64(v)}, 2, nil case TypeInt16: if len(buf) < 2 { - return Value{}, 0, ErrStorageTruncated + return Value{}, 0, ErrorStorageTruncated } v := int16(binary.LittleEndian.Uint16(buf[:2])) return Value{Type: TypeInt16, intVal: int64(v)}, 2, nil case TypeUint8: if len(buf) < 1 { - return Value{}, 0, ErrStorageTruncated + return Value{}, 0, ErrorStorageTruncated } return Value{Type: TypeUint8, uintVal: uint64(buf[0])}, 1, nil case TypeInt8: if len(buf) < 1 { - return Value{}, 0, ErrStorageTruncated + return Value{}, 0, ErrorStorageTruncated } return Value{Type: TypeInt8, intVal: int64(int8(buf[0]))}, 1, nil case TypeBool: if len(buf) < 1 { - return Value{}, 0, ErrStorageTruncated + return Value{}, 0, ErrorStorageTruncated } return Value{Type: TypeBool, boolVal: buf[0] != 0}, 1, nil @@ -638,7 +656,7 @@ func decodeValue(buf []byte, tag uint8) (Value, int, error) { return Value{}, 0, err } if uint64(len(buf)-n) < strLen { - return Value{}, 0, ErrStorageTruncated + return Value{}, 0, ErrorStorageTruncated } data := make([]byte, strLen) copy(data, buf[n:n+int(strLen)]) @@ -652,7 +670,7 @@ func decodeValue(buf []byte, tag uint8) (Value, int, error) { return Value{Type: TypeObject, objectVal: sec}, consumed, nil default: - return Value{}, 0, core.E("levin.decodeValue", core.Sprintf("unknown type tag: 0x%02x", tag), ErrStorageUnknownType) + return Value{}, 0, core.E("levin.decodeValue", core.Sprintf("unknown type tag: 0x%02x", tag), ErrorStorageUnknownType) } } @@ -671,7 +689,7 @@ func decodeArray(buf []byte, tag uint8) (Value, int, error) { arr := make([]uint64, count) for i := range count { if off+8 > len(buf) { - return Value{}, 0, ErrStorageTruncated + return Value{}, 0, ErrorStorageTruncated } arr[i] = binary.LittleEndian.Uint64(buf[off : off+8]) off += 8 @@ -682,7 +700,7 @@ func decodeArray(buf []byte, tag uint8) (Value, int, error) { arr := make([]uint32, count) for i := range count { if off+4 > len(buf) { - return Value{}, 0, ErrStorageTruncated + return Value{}, 0, ErrorStorageTruncated } arr[i] = binary.LittleEndian.Uint32(buf[off : off+4]) off += 4 @@ -698,7 +716,7 @@ func decodeArray(buf []byte, tag uint8) (Value, int, error) { } off += sn if uint64(len(buf)-off) < strLen { - return Value{}, 0, ErrStorageTruncated + return Value{}, 0, ErrorStorageTruncated } data := make([]byte, strLen) copy(data, buf[off:off+int(strLen)]) @@ -720,6 +738,6 @@ func decodeArray(buf []byte, tag uint8) (Value, int, error) { return Value{Type: tag, objectArray: arr}, off, nil default: - return Value{}, 0, core.E("levin.decodeArray", core.Sprintf("unknown type tag: array of 0x%02x", elemType), ErrStorageUnknownType) + return Value{}, 0, core.E("levin.decodeArray", core.Sprintf("unknown type tag: array of 0x%02x", elemType), ErrorStorageUnknownType) } } diff --git a/node/levin/varint.go b/node/levin/varint.go index 97d3e93..740a0df 100644 --- a/node/levin/varint.go +++ b/node/levin/varint.go @@ -22,11 +22,17 @@ const ( varintMax8 = 4_611_686_018_427_387_903 ) -// ErrVarintTruncated is returned when the buffer is too short. -var ErrVarintTruncated = core.E("levin", "truncated varint", nil) +// ErrorVarintTruncated is returned when the buffer is too short. +var ErrorVarintTruncated = core.E("levin", "truncated varint", nil) -// ErrVarintOverflow is returned when the value is too large to encode. -var ErrVarintOverflow = core.E("levin", "varint overflow", nil) +// Deprecated: use ErrorVarintTruncated. +var ErrVarintTruncated = ErrorVarintTruncated + +// ErrorVarintOverflow is returned when the value is too large to encode. +var ErrorVarintOverflow = core.E("levin", "varint overflow", nil) + +// Deprecated: use ErrorVarintOverflow. +var ErrVarintOverflow = ErrorVarintOverflow // PackVarint encodes v using the epee portable-storage varint scheme. // The low two bits of the first byte indicate the total encoded width; @@ -61,7 +67,7 @@ func PackVarint(v uint64) []byte { // value, err := UnpackVarint(data) func UnpackVarint(buf []byte) (value uint64, bytesConsumed int, err error) { if len(buf) == 0 { - return 0, 0, ErrVarintTruncated + return 0, 0, ErrorVarintTruncated } mark := buf[0] & varintMask @@ -72,27 +78,27 @@ func UnpackVarint(buf []byte) (value uint64, bytesConsumed int, err error) { return value, 1, nil case varintMark2: if len(buf) < 2 { - return 0, 0, ErrVarintTruncated + return 0, 0, ErrorVarintTruncated } raw := binary.LittleEndian.Uint16(buf[:2]) value = uint64(raw) >> 2 return value, 2, nil case varintMark4: if len(buf) < 4 { - return 0, 0, ErrVarintTruncated + return 0, 0, ErrorVarintTruncated } raw := binary.LittleEndian.Uint32(buf[:4]) value = uint64(raw) >> 2 return value, 4, nil case varintMark8: if len(buf) < 8 { - return 0, 0, ErrVarintTruncated + return 0, 0, ErrorVarintTruncated } raw := binary.LittleEndian.Uint64(buf[:8]) value = raw >> 2 return value, 8, nil default: // Unreachable — mark is masked to 2 bits. - return 0, 0, ErrVarintTruncated + return 0, 0, ErrorVarintTruncated } } diff --git a/node/message.go b/node/message.go index a10aa96..5b30a8a 100644 --- a/node/message.go +++ b/node/message.go @@ -8,11 +8,11 @@ import ( "github.com/google/uuid" ) -// Protocol version constants +// Protocol version constants. const ( - // ProtocolVersion is the current protocol version + // ProtocolVersion is the current protocol version. ProtocolVersion = "1.0" - // MinProtocolVersion is the minimum supported version + // MinProtocolVersion is the minimum supported version. MinProtocolVersion = "1.0" ) @@ -273,26 +273,44 @@ type DeployAckPayload struct { // ErrorPayload contains error information. // -// payload := ErrorPayload{Code: ErrCodeOperationFailed, Message: "start failed"} +// payload := ErrorPayload{Code: ErrorCodeOperationFailed, Message: "start failed"} type ErrorPayload struct { Code int `json:"code"` Message string `json:"message"` Details string `json:"details,omitempty"` } -// Common error codes +// Common error codes. const ( - ErrCodeUnknown = 1000 - ErrCodeInvalidMessage = 1001 - ErrCodeUnauthorized = 1002 - ErrCodeNotFound = 1003 - ErrCodeOperationFailed = 1004 - ErrCodeTimeout = 1005 + ErrorCodeUnknown = 1000 + ErrorCodeInvalidMessage = 1001 + ErrorCodeUnauthorized = 1002 + ErrorCodeNotFound = 1003 + ErrorCodeOperationFailed = 1004 + ErrorCodeTimeout = 1005 + + // Deprecated: use ErrorCodeUnknown. + ErrCodeUnknown = ErrorCodeUnknown + + // Deprecated: use ErrorCodeInvalidMessage. + ErrCodeInvalidMessage = ErrorCodeInvalidMessage + + // Deprecated: use ErrorCodeUnauthorized. + ErrCodeUnauthorized = ErrorCodeUnauthorized + + // Deprecated: use ErrorCodeNotFound. + ErrCodeNotFound = ErrorCodeNotFound + + // Deprecated: use ErrorCodeOperationFailed. + ErrCodeOperationFailed = ErrorCodeOperationFailed + + // Deprecated: use ErrorCodeTimeout. + ErrCodeTimeout = ErrorCodeTimeout ) // NewErrorMessage creates an error response message. // -// msg, err := NewErrorMessage("worker", "controller", ErrCodeOperationFailed, "miner start failed", "req-1") +// msg, err := NewErrorMessage("worker", "controller", ErrorCodeOperationFailed, "miner start failed", "req-1") func NewErrorMessage(from, to string, code int, message string, replyTo string) (*Message, error) { msg, err := NewMessage(MsgError, from, to, ErrorPayload{ Code: code, diff --git a/node/protocol.go b/node/protocol.go index 36c51c6..790fb07 100644 --- a/node/protocol.go +++ b/node/protocol.go @@ -6,7 +6,7 @@ import ( // ProtocolError represents an error from the remote peer. // -// err := &ProtocolError{Code: ErrCodeOperationFailed, Message: "start failed"} +// err := &ProtocolError{Code: ErrorCodeOperationFailed, Message: "start failed"} type ProtocolError struct { Code int Message string @@ -35,7 +35,7 @@ func (h *ResponseHandler) ValidateResponse(resp *Message, expectedType MessageTy if resp.Type == MsgError { var errPayload ErrorPayload if err := resp.ParsePayload(&errPayload); err != nil { - return &ProtocolError{Code: ErrCodeUnknown, Message: "unable to parse error response"} + return &ProtocolError{Code: ErrorCodeUnknown, Message: "unable to parse error response"} } return &ProtocolError{Code: errPayload.Code, Message: errPayload.Message} } diff --git a/node/transport.go b/node/transport.go index fe6e282..e7bd859 100644 --- a/node/transport.go +++ b/node/transport.go @@ -641,7 +641,7 @@ func (t *Transport) performHandshake(pc *PeerConnection) error { identity := t.node.GetIdentity() if identity == nil { - return ErrIdentityNotInitialized + return ErrorIdentityNotInitialized } // Generate challenge for the server to prove it has the matching private key diff --git a/node/worker.go b/node/worker.go index 23d3178..9b32b36 100644 --- a/node/worker.go +++ b/node/worker.go @@ -103,7 +103,7 @@ func (w *Worker) HandleMessage(conn *PeerConnection, msg *Message) { errMsg, _ := NewErrorMessage( identity.ID, msg.From, - ErrCodeOperationFailed, + ErrorCodeOperationFailed, err.Error(), msg.ID, ) @@ -141,7 +141,7 @@ func (w *Worker) handlePing(msg *Message) (*Message, error) { func (w *Worker) handleGetStats(msg *Message) (*Message, error) { identity := w.node.GetIdentity() if identity == nil { - return nil, ErrIdentityNotInitialized + return nil, ErrorIdentityNotInitialized } stats := StatsPayload{ @@ -204,7 +204,7 @@ func convertMinerStats(miner MinerInstance, rawStats any) MinerStatsItem { // handleStartMiner starts a miner with the given profile. func (w *Worker) handleStartMiner(msg *Message) (*Message, error) { if w.minerManager == nil { - return nil, ErrMinerManagerNotConfigured + return nil, ErrorMinerManagerNotConfigured } var payload StartMinerPayload @@ -251,7 +251,7 @@ func (w *Worker) handleStartMiner(msg *Message) (*Message, error) { // handleStopMiner stops a running miner. func (w *Worker) handleStopMiner(msg *Message) (*Message, error) { if w.minerManager == nil { - return nil, ErrMinerManagerNotConfigured + return nil, ErrorMinerManagerNotConfigured } var payload StopMinerPayload @@ -274,7 +274,7 @@ func (w *Worker) handleStopMiner(msg *Message) (*Message, error) { // handleGetLogs returns console logs from a miner. func (w *Worker) handleGetLogs(msg *Message) (*Message, error) { if w.minerManager == nil { - return nil, ErrMinerManagerNotConfigured + return nil, ErrorMinerManagerNotConfigured } var payload GetLogsPayload diff --git a/specs/node-levin.md b/specs/node-levin.md index b5e8912..2c60cb1 100644 --- a/specs/node-levin.md +++ b/specs/node-levin.md @@ -99,19 +99,19 @@ Tagged portable-storage value. The exported `Type` field identifies which intern | Name | Signature | Description | | --- | --- | --- | -| `AsUint64` | `func (v Value) AsUint64() (uint64, error)` | Returns the scalar `uint64` value or `ErrStorageTypeMismatch`. | -| `AsUint32` | `func (v Value) AsUint32() (uint32, error)` | Returns the scalar `uint32` value or `ErrStorageTypeMismatch`. | -| `AsUint16` | `func (v Value) AsUint16() (uint16, error)` | Returns the scalar `uint16` value or `ErrStorageTypeMismatch`. | -| `AsUint8` | `func (v Value) AsUint8() (uint8, error)` | Returns the scalar `uint8` value or `ErrStorageTypeMismatch`. | -| `AsInt64` | `func (v Value) AsInt64() (int64, error)` | Returns the scalar `int64` value or `ErrStorageTypeMismatch`. | -| `AsInt32` | `func (v Value) AsInt32() (int32, error)` | Returns the scalar `int32` value or `ErrStorageTypeMismatch`. | -| `AsInt16` | `func (v Value) AsInt16() (int16, error)` | Returns the scalar `int16` value or `ErrStorageTypeMismatch`. | -| `AsInt8` | `func (v Value) AsInt8() (int8, error)` | Returns the scalar `int8` value or `ErrStorageTypeMismatch`. | -| `AsBool` | `func (v Value) AsBool() (bool, error)` | Returns the scalar `bool` value or `ErrStorageTypeMismatch`. | -| `AsDouble` | `func (v Value) AsDouble() (float64, error)` | Returns the scalar `float64` value or `ErrStorageTypeMismatch`. | -| `AsString` | `func (v Value) AsString() ([]byte, error)` | Returns the scalar byte-string or `ErrStorageTypeMismatch`. | -| `AsSection` | `func (v Value) AsSection() (Section, error)` | Returns the nested `Section` or `ErrStorageTypeMismatch`. | -| `AsUint64Array` | `func (v Value) AsUint64Array() ([]uint64, error)` | Returns the `[]uint64` array or `ErrStorageTypeMismatch`. | -| `AsUint32Array` | `func (v Value) AsUint32Array() ([]uint32, error)` | Returns the `[]uint32` array or `ErrStorageTypeMismatch`. | -| `AsStringArray` | `func (v Value) AsStringArray() ([][]byte, error)` | Returns the `[][]byte` array or `ErrStorageTypeMismatch`. | -| `AsSectionArray` | `func (v Value) AsSectionArray() ([]Section, error)` | Returns the `[]Section` array or `ErrStorageTypeMismatch`. | +| `AsUint64` | `func (v Value) AsUint64() (uint64, error)` | Returns the scalar `uint64` value or `ErrorStorageTypeMismatch`. | +| `AsUint32` | `func (v Value) AsUint32() (uint32, error)` | Returns the scalar `uint32` value or `ErrorStorageTypeMismatch`. | +| `AsUint16` | `func (v Value) AsUint16() (uint16, error)` | Returns the scalar `uint16` value or `ErrorStorageTypeMismatch`. | +| `AsUint8` | `func (v Value) AsUint8() (uint8, error)` | Returns the scalar `uint8` value or `ErrorStorageTypeMismatch`. | +| `AsInt64` | `func (v Value) AsInt64() (int64, error)` | Returns the scalar `int64` value or `ErrorStorageTypeMismatch`. | +| `AsInt32` | `func (v Value) AsInt32() (int32, error)` | Returns the scalar `int32` value or `ErrorStorageTypeMismatch`. | +| `AsInt16` | `func (v Value) AsInt16() (int16, error)` | Returns the scalar `int16` value or `ErrorStorageTypeMismatch`. | +| `AsInt8` | `func (v Value) AsInt8() (int8, error)` | Returns the scalar `int8` value or `ErrorStorageTypeMismatch`. | +| `AsBool` | `func (v Value) AsBool() (bool, error)` | Returns the scalar `bool` value or `ErrorStorageTypeMismatch`. | +| `AsDouble` | `func (v Value) AsDouble() (float64, error)` | Returns the scalar `float64` value or `ErrorStorageTypeMismatch`. | +| `AsString` | `func (v Value) AsString() ([]byte, error)` | Returns the scalar byte-string or `ErrorStorageTypeMismatch`. | +| `AsSection` | `func (v Value) AsSection() (Section, error)` | Returns the nested `Section` or `ErrorStorageTypeMismatch`. | +| `AsUint64Array` | `func (v Value) AsUint64Array() ([]uint64, error)` | Returns the `[]uint64` array or `ErrorStorageTypeMismatch`. | +| `AsUint32Array` | `func (v Value) AsUint32Array() ([]uint32, error)` | Returns the `[]uint32` array or `ErrorStorageTypeMismatch`. | +| `AsStringArray` | `func (v Value) AsStringArray() ([][]byte, error)` | Returns the `[][]byte` array or `ErrorStorageTypeMismatch`. | +| `AsSectionArray` | `func (v Value) AsSectionArray() ([]Section, error)` | Returns the `[]Section` array or `ErrorStorageTypeMismatch`. |