How the Akash Network Audit Module Verifies Provider Attributes and Host URIs

The Akash Network audit module verifies provider attributes and host URIs through client-side validation at entry points, ensuring malformed URIs never reach chain storage by validating them in MsgSignProviderAttributes.ValidateBasic() and genesis initialization.

The akash-network/node repository implements a decentralized compute marketplace where auditors attest to provider capabilities through cryptographically signed attribute sets. Rather than maintaining an independent copy of a provider’s host URI, the audit module stores these attested attributes and relies on rigorous validation at creation time—both during chain initialization and transaction processing—to guarantee that every host URI conforms to proper URL syntax before it is persisted.

Genesis-Time Validation in x/audit/genesis.go

When the chain boots from genesis, the audit module validates every pre-existing provider record before accepting the state. In x/audit/genesis.go:27-28, the ValidateGenesis function iterates over the Providers slice and invokes record.Attributes.Validate() on each entry.

If any attribute—including the host_uri field—fails validation, the chain aborts initialization with ErrInvalidAttributes. This prevents malformed provider metadata from entering the blockchain history at the earliest possible stage.

// x/audit/genesis.go
func ValidateGenesis(data *types.GenesisState) error {
    for _, record := range data.Providers {
        // address format checks …
        if err := record.Attributes.Validate(); err != nil {
            // fails on malformed host_uri, missing keys, etc.
            return errorsmod.Wrap(err, "audited attributes: invalid attributes")
        }
    }
    return nil
}

Transaction Validation via MsgSignProviderAttributes

Before a transaction enters the mempool, the ValidateBasic() method—generated from proto/akash/audit/v1/messages.proto and located in the generated Go file—performs syntactic checks. This method validates that both the Auditor and Owner fields are valid bech32 addresses, then delegates attribute validation to msg.Attributes.Validate().

The attributes validator (implemented in the shared pkg/akt.dev/go/node/types/attributes/v1 package) parses the host_uri string using Go’s net/url parser. It enforces that the URI uses a supported scheme—such as http, https, akash, or grpc—and contains a non-empty host component.

// generated from proto/akash/audit/v1/messages.proto
func (msg *MsgSignProviderAttributes) ValidateBasic() error {
    if _, err := sdk.AccAddressFromBech32(msg.Auditor); err != nil {
        return err
    }
    if _, err := sdk.AccAddressFromBech32(msg.Owner); err != nil {
        return err
    }
    // The Attributes validator checks each key/value,
    // and for the key "host_uri" it parses the URL.
    return msg.Attributes.Validate()
}

Keeper Storage Trusts Pre-Validated Data

Once ValidateBasic() succeeds, the message server handler in x/audit/handler/msg_server.go:44-46 invokes keeper.CreateOrUpdateProviderAttributes. The keeper implementation in x/audit/keeper/keeper.go:94-130 does not re-validate the attributes; it trusts the previous validation steps and simply merges the new key-value pairs with any existing set for the ProviderID (composed of owner and auditor addresses).

// x/audit/keeper/keeper.go – CreateOrUpdateProviderAttributes
func (k Keeper) CreateOrUpdateProviderAttributes(
    ctx sdk.Context, id types.ProviderID, attr attrv1.Attributes,
) error {
    // ... load existing, merge maps, sort, then store.
    store.Set(ProviderKey(id), k.cdc.MustMarshal(&attrRec))
    // Event emitted – no extra validation needed.
    return nil
}

Runtime Query Guarantees

When clients query the audit store through methods like AllProvidersAttributes, ProviderAttributes, or AuditorAttributes in x/audit/keeper/grpc_query.go, the keeper reads raw bytes and unmarshals them into types.AuditedProvider. Because validation occurred strictly at entry time, the returned attribute list—including any host URI—is guaranteed to be syntactically correct without requiring runtime checks.

Provider Module Host URI Validation

The canonical HostURI field—used by the network to reach the provider—is owned by the provider module, not the audit module. Before the audit module ever sees a host URI, the provider module validates it through its own ValidateBasic() implementation in x/provider/types/message.pb.go.

In x/provider/handler/server.go:36-56, both MsgCreateProvider and MsgUpdateProvider handlers call msg.ValidateBasic(), which invokes the same attribute validator on the HostURI field. The audit module subsequently stores only the signed attestation of this pre-validated data.

// x/provider/handler/server.go
func (h server) CreateProvider(goCtx context.Context, msg *types.MsgCreateProvider) (*types.MsgCreateProviderResponse, error) {
    if err := msg.ValidateBasic(); err != nil { // checks HostURI format
        return nil, err
    }
    // provider is stored in the provider keeper …
}

Error Types and Validation Failures

The audit module surfaces specific errors during the verification process:

  • sdkerrors.ErrInvalidAddress – Returned when the owner or auditor bech32 addresses are malformed.
  • types.ErrAttributeNotFound – Returned when attempting to delete an attribute that does not exist in the store.
  • types.ErrInvalidAttributes – Wrapped from Attributes.Validate() when attributes contain malformed key-value pairs, missing required keys like host_uri, or illegal URI schemes.

Summary

  • Genesis validation in x/audit/genesis.go calls Attributes.Validate() on every provider record during chain startup, preventing invalid host URIs from entering the genesis state.
  • Transaction validation in MsgSignProviderAttributes.ValidateBasic() validates bech32 addresses and delegates to the attributes validator, which parses URIs with net/url and enforces supported schemes.
  • Keeper architecture trusts pre-validated data and performs no additional validation during storage operations in CreateOrUpdateProviderAttributes.
  • Query safety relies on entry-time validation to guarantee that all returned host URIs are syntactically correct without runtime overhead.
  • Provider module integration validates the canonical HostURI before the audit module processes any related attributes, creating a defense-in-depth validation strategy.

Frequently Asked Questions

Does the audit module validate host URIs every time they are queried?

No. The audit module validates host URIs strictly at entry time—during genesis initialization and when processing MsgSignProviderAttributes transactions. The keeper stores pre-validated data, so runtime queries in x/audit/keeper/grpc_query.go simply return the stored bytes without additional validation overhead.

What URL schemes are supported for provider host URIs in Akash?

The attributes validator accepts schemes including http, https, akash, and grpc. The validation logic uses Go’s standard net/url parser to ensure the URI contains a valid scheme and a non-empty host component before the transaction is accepted.

What happens if a provider submits an invalid host URI during genesis?

The chain aborts initialization with ErrInvalidAttributes. In x/audit/genesis.go, the ValidateGenesis function wraps the underlying validation error and returns it, preventing the node from starting with malformed provider metadata in its genesis state.

How does the audit module differ from the provider module regarding host URI storage?

The provider module owns the canonical HostURI field used for network reachability and validates it during MsgCreateProvider and MsgUpdateProvider processing. The audit module stores signed attestations of provider attributes (including the host URI) tied to an auditor’s address, validating these attestations during the signing transaction but never storing an independent copy of the raw host URI.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →