Skip to content
This repository was archived by the owner on Jan 5, 2026. It is now read-only.
Open
54 changes: 54 additions & 0 deletions docs/proto/provider.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@
- [Status](#akash.provider.v1.Status)

- [akash/provider/v1/service.proto](#akash/provider/v1/service.proto)
- [BidPreCheckRequest](#akash.provider.v1.BidPreCheckRequest)
- [BidPreCheckResponse](#akash.provider.v1.BidPreCheckResponse)
- [GroupBidPreCheck](#akash.provider.v1.GroupBidPreCheck)

- [ProviderRPC](#akash.provider.v1.ProviderRPC)

- [akash/inventory/v1/memory.proto](#akash/inventory/v1/memory.proto)
Expand Down Expand Up @@ -646,6 +650,55 @@
## akash/provider/v1/service.proto



<a name="akash.provider.v1.BidPreCheckRequest"></a>

### BidPreCheckRequest
BidPreCheckRequest is request type for the BidPreCheck RPC method


| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `groups` | [akash.deployment.v1beta3.GroupSpec](#akash.deployment.v1beta3.GroupSpec) | repeated | |






<a name="akash.provider.v1.BidPreCheckResponse"></a>

### BidPreCheckResponse
PreBidCheckResponse is response type for the PreBidCheck RPC method


| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `group_bid_pre_checks` | [GroupBidPreCheck](#akash.provider.v1.GroupBidPreCheck) | repeated | |
| `total_price` | [cosmos.base.v1beta1.DecCoin](#cosmos.base.v1beta1.DecCoin) | | |






<a name="akash.provider.v1.GroupBidPreCheck"></a>

### GroupBidPreCheck
GroupBidPreCheck contains bid information for a specific group


| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `name` | [string](#string) | | |
| `min_bid_price` | [cosmos.base.v1beta1.DecCoin](#cosmos.base.v1beta1.DecCoin) | | |
| `reason` | [string](#string) | | |
| `can_bid` | [bool](#bool) | | |





<!-- end messages -->

<!-- end enums -->
Expand All @@ -662,6 +715,7 @@
| ----------- | ------------ | ------------- | ------------| ------- | -------- |
| `GetStatus` | [.google.protobuf.Empty](#google.protobuf.Empty) | [Status](#akash.provider.v1.Status) | GetStatus defines a method to query provider state buf:lint:ignore RPC_REQUEST_RESPONSE_UNIQUE buf:lint:ignore RPC_RESPONSE_STANDARD_NAME | GET|/v1/status|
| `StreamStatus` | [.google.protobuf.Empty](#google.protobuf.Empty) | [Status](#akash.provider.v1.Status) stream | Status defines a method to stream provider state buf:lint:ignore RPC_REQUEST_RESPONSE_UNIQUE buf:lint:ignore RPC_RESPONSE_STANDARD_NAME | |
| `BidPreCheck` | [BidPreCheckRequest](#akash.provider.v1.BidPreCheckRequest) | [BidPreCheckResponse](#akash.provider.v1.BidPreCheckResponse) | BidPreCheck defines a method to check if a provider can bid on a manifest buf:lint:ignore RPC_REQUEST_RESPONSE_UNIQUE buf:lint:ignore RPC_RESPONSE_STANDARD_NAME | POST|/v1/bidprecheck|

<!-- end services -->

Expand Down
50 changes: 50 additions & 0 deletions go/node/types/v1beta3/attribute.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package v1beta3

import (
fmt "fmt"
"path/filepath"
"reflect"
"regexp"
Expand Down Expand Up @@ -378,3 +379,52 @@ func (attr Attributes) AnyIN(group AttributesGroup) bool {
}
return false
}

// GetNonMatchingAttributes returns attributes from 'a' that don't match any attribute in 'b'.
// For example:
// a:
//
// region: us-east-1
// class: beta1
// persistent: true
//
// b:
//
// region: us-east-1
// class: beta2
//
// Returns:
//
// class: beta1
// persistent: true
//
// This is useful for finding attributes that need to be satisfied when matching requirements.
func (attr Attributes) GetNonMatchingAttributes(b Attributes) Attributes {
var nonMatching Attributes

for _, req := range attr {
found := false
for _, attr := range b {
if req.SubsetOf(attr) {
found = true
break
}
}
if !found {
nonMatching = append(nonMatching, req)
}
}

return nonMatching
}

func (attr Attributes) String() string {
out := ""
for i, v := range attr {
out += fmt.Sprintf("%s=%s", v.Key, v.Value)
if i < len(attr)-1 {
out += ", "
}
}
return out
}
77 changes: 77 additions & 0 deletions go/node/types/v1beta3/attribute_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -180,3 +180,80 @@ func TestAttributes_Dup(t *testing.T) {
dAttrs := attrs.Dup()
require.Equal(t, attrs, dAttrs)
}

func TestAttributes_GetNonMatchingAttributes(t *testing.T) {
attr1 := Attributes{
{Key: "key1", Value: "val1"},
{Key: "key2", Value: "val2"},
{Key: "key3", Value: "val3"},
}

attr2 := Attributes{
{Key: "key1", Value: "val1"},
{Key: "key3", Value: "val3"},
{Key: "key4", Value: "val4"},
}

nonMatching := attr1.GetNonMatchingAttributes(attr2)
require.Len(t, nonMatching, 1)
require.Equal(t, "key2", nonMatching[0].Key)
require.Equal(t, "val2", nonMatching[0].Value)

// Test with empty attributes
empty := Attributes{}
nonMatching = empty.GetNonMatchingAttributes(attr1)
require.Empty(t, nonMatching)

// Test with no matches
attr3 := Attributes{
{Key: "key5", Value: "val5"},
{Key: "key6", Value: "val6"},
}
nonMatching = attr3.GetNonMatchingAttributes(attr1)
require.Equal(t, nonMatching, attr3)
}

func TestAttributes_String(t *testing.T) {
tests := []struct {
name string
attrs Attributes
expected string
}{
{
"single attribute",
Attributes{
{Key: "key1", Value: "val1"},
},
"key1=val1",
},
{
"multiple attributes",
Attributes{
{Key: "key1", Value: "val1"},
{Key: "key2", Value: "val2"},
{Key: "key3", Value: "val3"},
},
"key1=val1, key2=val2, key3=val3",
},
{
"empty attributes",
Attributes{},
"",
},
{
"attributes with special characters",
Attributes{
{Key: "key/1", Value: "val/1"},
{Key: "key.2", Value: "val.2"},
},
"key/1=val/1, key.2=val.2",
},
}

for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
result := test.attrs.String()
require.Equal(t, test.expected, result)
})
}
}
43 changes: 21 additions & 22 deletions go/provider/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
dtypes "github.com/akash-network/akash-api/go/node/deployment/v1beta3"
mtypes "github.com/akash-network/akash-api/go/node/market/v1beta4"
ptypes "github.com/akash-network/akash-api/go/node/provider/v1beta3"
providerv1 "github.com/akash-network/akash-api/go/provider/v1"
ajwt "github.com/akash-network/akash-api/go/util/jwt"
atls "github.com/akash-network/akash-api/go/util/tls"
)
Expand All @@ -52,9 +53,7 @@
PingPeriod = 10 * time.Second
)

var (
ErrNotInitialized = errors.New("rest: not initialized")
)
var ErrNotInitialized = errors.New("rest: not initialized")

type ReqClient interface {
DialContext(ctx context.Context, urlStr string, requestHeader http.Header) (*websocket.Conn, *http.Response, error)
Expand All @@ -65,7 +64,7 @@
type Client interface {
NewReqClient(ctx context.Context) ReqClient
Status(ctx context.Context) (*ProviderStatus, error)
Validate(ctx context.Context, gspec dtypes.GroupSpec) (ValidateGroupSpecResult, error)
Validate(ctx context.Context, gspecs dtypes.GroupSpecs) (providerv1.BidPreCheckResponse, error)
SubmitManifest(ctx context.Context, dseq uint64, mani manifest.Manifest) error
GetManifest(ctx context.Context, id mtypes.LeaseID) (manifest.Manifest, error)
LeaseStatus(ctx context.Context, id mtypes.LeaseID) (LeaseStatus, error)
Expand Down Expand Up @@ -381,35 +380,37 @@
return &obj, nil
}

func (c *client) Validate(ctx context.Context, gspec dtypes.GroupSpec) (ValidateGroupSpecResult, error) {
func (c *client) Validate(ctx context.Context, gspecs dtypes.GroupSpecs) (providerv1.BidPreCheckResponse, error) {

Check warning on line 383 in go/provider/client/client.go

View check run for this annotation

Codecov / codecov/patch

go/provider/client/client.go#L383

Added line #L383 was not covered by tests
uri, err := MakeURI(c.host, ValidatePath())
if err != nil {
return ValidateGroupSpecResult{}, err
return providerv1.BidPreCheckResponse{}, err

Check warning on line 386 in go/provider/client/client.go

View check run for this annotation

Codecov / codecov/patch

go/provider/client/client.go#L386

Added line #L386 was not covered by tests
}

if err = gspec.ValidateBasic(); err != nil {
return ValidateGroupSpecResult{}, err
for _, gspec := range gspecs {
if err = gspec.ValidateBasic(); err != nil {
return providerv1.BidPreCheckResponse{}, err
}

Check warning on line 392 in go/provider/client/client.go

View check run for this annotation

Codecov / codecov/patch

go/provider/client/client.go#L389-L392

Added lines #L389 - L392 were not covered by tests
}

bgspec, err := json.Marshal(gspec)
bgspecs, err := json.Marshal(gspecs)

Check warning on line 395 in go/provider/client/client.go

View check run for this annotation

Codecov / codecov/patch

go/provider/client/client.go#L395

Added line #L395 was not covered by tests
if err != nil {
return ValidateGroupSpecResult{}, err
return providerv1.BidPreCheckResponse{}, err

Check warning on line 397 in go/provider/client/client.go

View check run for this annotation

Codecov / codecov/patch

go/provider/client/client.go#L397

Added line #L397 was not covered by tests
}

req, err := http.NewRequestWithContext(ctx, "GET", uri, bytes.NewReader(bgspec))
req, err := http.NewRequestWithContext(ctx, "GET", uri, bytes.NewReader(bgspecs))

Check warning on line 400 in go/provider/client/client.go

View check run for this annotation

Codecov / codecov/patch

go/provider/client/client.go#L400

Added line #L400 was not covered by tests
if err != nil {
return ValidateGroupSpecResult{}, err
return providerv1.BidPreCheckResponse{}, err

Check warning on line 402 in go/provider/client/client.go

View check run for this annotation

Codecov / codecov/patch

go/provider/client/client.go#L402

Added line #L402 was not covered by tests
}
req.Header.Set("Content-Type", contentTypeJSON)

if err = c.setAuth(req.Header); err != nil {
return ValidateGroupSpecResult{}, err
return providerv1.BidPreCheckResponse{}, err

Check warning on line 407 in go/provider/client/client.go

View check run for this annotation

Codecov / codecov/patch

go/provider/client/client.go#L407

Added line #L407 was not covered by tests
}

rCl := c.NewReqClient(ctx)
resp, err := rCl.Do(req)
if err != nil {
return ValidateGroupSpecResult{}, err
return providerv1.BidPreCheckResponse{}, err

Check warning on line 413 in go/provider/client/client.go

View check run for this annotation

Codecov / codecov/patch

go/provider/client/client.go#L413

Added line #L413 was not covered by tests
}

buf := &bytes.Buffer{}
Expand All @@ -419,17 +420,17 @@
}()

if err != nil {
return ValidateGroupSpecResult{}, err
return providerv1.BidPreCheckResponse{}, err

Check warning on line 423 in go/provider/client/client.go

View check run for this annotation

Codecov / codecov/patch

go/provider/client/client.go#L423

Added line #L423 was not covered by tests
}

err = createClientResponseErrorIfNotOK(resp, buf)
if err != nil {
return ValidateGroupSpecResult{}, err
return providerv1.BidPreCheckResponse{}, err

Check warning on line 428 in go/provider/client/client.go

View check run for this annotation

Codecov / codecov/patch

go/provider/client/client.go#L428

Added line #L428 was not covered by tests
}

var obj ValidateGroupSpecResult
var obj providerv1.BidPreCheckResponse

Check warning on line 431 in go/provider/client/client.go

View check run for this annotation

Codecov / codecov/patch

go/provider/client/client.go#L431

Added line #L431 was not covered by tests
if err = json.NewDecoder(buf).Decode(&obj); err != nil {
return ValidateGroupSpecResult{}, err
return providerv1.BidPreCheckResponse{}, err

Check warning on line 433 in go/provider/client/client.go

View check run for this annotation

Codecov / codecov/patch

go/provider/client/client.go#L433

Added line #L433 was not covered by tests
}

return obj, nil
Expand Down Expand Up @@ -459,7 +460,6 @@

rCl := c.NewReqClient(ctx)
resp, err := rCl.Do(req)

if err != nil {
return err
}
Expand Down Expand Up @@ -493,7 +493,6 @@

rCl := c.NewReqClient(ctx)
resp, err := rCl.Do(req)

if err != nil {
return nil, err
}
Expand Down Expand Up @@ -803,8 +802,8 @@
id mtypes.LeaseID,
services string,
follow bool,
_ int64) (*ServiceLogs, error) {

_ int64,
) (*ServiceLogs, error) {

Check warning on line 806 in go/provider/client/client.go

View check run for this annotation

Codecov / codecov/patch

go/provider/client/client.go#L806

Added line #L806 was not covered by tests
endpoint, err := url.Parse(c.host.String() + "/" + ServiceLogsPath(id))
if err != nil {
return nil, err
Expand Down
8 changes: 0 additions & 8 deletions go/provider/client/types.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package rest

import (
sdk "github.com/cosmos/cosmos-sdk/types"

inventoryV1 "github.com/akash-network/akash-api/go/inventory/v1"
manifest "github.com/akash-network/akash-api/go/manifest/v2beta2"
)
Expand Down Expand Up @@ -108,12 +106,6 @@ type LeaseEvent struct {
Object LeaseEventObject `json:"object" yaml:"object"`
}

// ValidateGroupSpecResult represents the result of validating a group specification,
// including the minimum bid price required.
type ValidateGroupSpecResult struct {
MinBidPrice sdk.DecCoin `json:"min_bid_price"`
}

// MigrateRequestBody represents a request to migrate hostnames to a new deployment,
// including the list of hostnames and destination deployment/group sequence numbers.
type MigrateRequestBody struct {
Expand Down
Loading
Loading