Skip to content

Commit

Permalink
Datalayer RPCs (#141)
Browse files Browse the repository at this point in the history
* Add get_subscriptions endpoint + fix config parsing

* Fix initial config

* Add wonkydict to account for default empty values of either [] or {}

* Add get_owned_stores endpoint

* Add get_mirrors endpoint

* Add delete_mirror

* Datalayer add_mirror endpoint

* Add unsubscribe endpoint

* Return a better error when wonkyset can't be unmarshalled

* Update pkg/types/wonkyset_test.go

Co-authored-by: Patrick Maslana <79757486+pmaslana@users.noreply.github.com>

* Update pkg/types/wonkyset.go

Co-authored-by: Starttoaster <b.butler@chia.net>

---------

Co-authored-by: Patrick Maslana <79757486+pmaslana@users.noreply.github.com>
Co-authored-by: Starttoaster <b.butler@chia.net>
  • Loading branch information
3 people authored Aug 2, 2024
1 parent f278718 commit ac5fb4a
Show file tree
Hide file tree
Showing 6 changed files with 266 additions and 2 deletions.
2 changes: 1 addition & 1 deletion pkg/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ type PoolConfig struct {
// FarmerConfig farmer configuration section
type FarmerConfig struct {
FullNodePeers []Peer `yaml:"full_node_peers"`
PoolPublicKeys []string `yaml:"pool_public_keys"` // @TODO test if the !!set notation parses correctly
PoolPublicKeys types.WonkySet `yaml:"pool_public_keys"`
XCHTargetAddress string `yaml:"xch_target_address,omitempty"`
StartRPCServer bool `yaml:"start_rpc_server"`
EnableProfiler bool `yaml:"enable_profiler"`
Expand Down
2 changes: 1 addition & 1 deletion pkg/config/initial-config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,7 @@ farmer:
- host: *self_hostname
port: 8444

pool_public_keys: []
pool_public_keys: !!set {}

# Replace this with a real receive address
# xch_target_address: txch102gkhhzs60grx7cfnpng5n6rjecr89r86l5s8xux2za8k820cxsq64ssdg
Expand Down
173 changes: 173 additions & 0 deletions pkg/rpc/datalayer.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"net/http"

"github.com/chia-network/go-chia-libs/pkg/rpcinterface"
"github.com/chia-network/go-chia-libs/pkg/types"
)

// DataLayerService encapsulates data layer RPC methods
Expand Down Expand Up @@ -36,3 +37,175 @@ func (s *DataLayerService) GetVersion(opts *GetVersionOptions) (*GetVersionRespo

return r, resp, nil
}

// DatalayerGetSubscriptionsOptions options for get_subscriptions
type DatalayerGetSubscriptionsOptions struct{}

// DatalayerGetSubscriptionsResponse response for get_subscriptions
type DatalayerGetSubscriptionsResponse struct {
Response
StoreIDs []string `json:"store_ids"`
}

// GetSubscriptions is just an alias for Subscriptions, since the CLI command is get_subscriptions
// Makes this easier to find
func (s *DataLayerService) GetSubscriptions(opts *DatalayerGetSubscriptionsOptions) (*DatalayerGetSubscriptionsResponse, *http.Response, error) {
return s.Subscriptions(opts)
}

// Subscriptions calls the subscriptions endpoint to list all subscriptions
func (s *DataLayerService) Subscriptions(opts *DatalayerGetSubscriptionsOptions) (*DatalayerGetSubscriptionsResponse, *http.Response, error) {
request, err := s.NewRequest("subscriptions", opts)
if err != nil {
return nil, nil, err
}

r := &DatalayerGetSubscriptionsResponse{}

resp, err := s.Do(request, r)
if err != nil {
return nil, resp, err
}

return r, resp, nil
}

// DatalayerGetOwnedStoresOptions Options for get_owned_stores
type DatalayerGetOwnedStoresOptions struct{}

// DatalayerGetOwnedStoresResponse Response for get_owned_stores
type DatalayerGetOwnedStoresResponse struct {
Response
StoreIDs []string `json:"store_ids"`
}

// GetOwnedStores RPC endpoint get_owned_stores
func (s *DataLayerService) GetOwnedStores(opts *DatalayerGetOwnedStoresOptions) (*DatalayerGetOwnedStoresResponse, *http.Response, error) {
request, err := s.NewRequest("get_owned_stores", opts)
if err != nil {
return nil, nil, err
}

r := &DatalayerGetOwnedStoresResponse{}

resp, err := s.Do(request, r)
if err != nil {
return nil, resp, err
}

return r, resp, nil
}

// DatalayerGetMirrorsOptions Options for get_mirrors
type DatalayerGetMirrorsOptions struct {
ID string `json:"id"` // Hex String
}

// DatalayerGetMirrorsResponse Response from the get_mirrors RPC
type DatalayerGetMirrorsResponse struct {
Response
Mirrors []types.DatalayerMirror `json:"mirrors"`
}

// GetMirrors lists the mirrors for the given datalayer store
func (s *DataLayerService) GetMirrors(opts *DatalayerGetMirrorsOptions) (*DatalayerGetMirrorsResponse, *http.Response, error) {
request, err := s.NewRequest("get_mirrors", opts)
if err != nil {
return nil, nil, err
}

r := &DatalayerGetMirrorsResponse{}

resp, err := s.Do(request, r)
if err != nil {
return nil, resp, err
}

return r, resp, nil
}

// DatalayerDeleteMirrorOptions options for delete_mirror RPC call
type DatalayerDeleteMirrorOptions struct {
CoinID string `json:"coin_id"` // hex string
Fee uint64 `json:"fee"` // not required
}

// DatalayerDeleteMirrorResponse response data for delete_mirror
type DatalayerDeleteMirrorResponse struct {
Response
}

// DeleteMirror deletes a datalayer mirror
func (s *DataLayerService) DeleteMirror(opts *DatalayerDeleteMirrorOptions) (*DatalayerDeleteMirrorResponse, *http.Response, error) {
request, err := s.NewRequest("delete_mirror", opts)
if err != nil {
return nil, nil, err
}

r := &DatalayerDeleteMirrorResponse{}

resp, err := s.Do(request, r)
if err != nil {
return nil, resp, err
}

return r, resp, nil
}

// DatalayerAddMirrorOptions options for delete_mirror RPC call
type DatalayerAddMirrorOptions struct {
ID string `json:"id"` // hex string datastore ID
URLs []string `json:"urls"`
Amount uint64 `json:"amount"`
Fee uint64 `json:"fee"`
}

// DatalayerAddMirrorResponse response data for add_mirror
type DatalayerAddMirrorResponse struct {
Response
}

// AddMirror deletes a datalayer mirror
func (s *DataLayerService) AddMirror(opts *DatalayerAddMirrorOptions) (*DatalayerAddMirrorResponse, *http.Response, error) {
request, err := s.NewRequest("add_mirror", opts)
if err != nil {
return nil, nil, err
}

r := &DatalayerAddMirrorResponse{}

resp, err := s.Do(request, r)
if err != nil {
return nil, resp, err
}

return r, resp, nil
}

// DatalayerUnsubscribeOptions options for unsubscribing to a datastore
type DatalayerUnsubscribeOptions struct {
ID string `json:"id"` // hex string datastore id
RetainData bool `json:"retain"`
}

// DatalayerUnsubscribeResponse response data for unsubscribe
type DatalayerUnsubscribeResponse struct {
Response
}

// Unsubscribe deletes a datalayer mirror
func (s *DataLayerService) Unsubscribe(opts *DatalayerUnsubscribeOptions) (*DatalayerUnsubscribeResponse, *http.Response, error) {
request, err := s.NewRequest("unsubscribe", opts)
if err != nil {
return nil, nil, err
}

r := &DatalayerUnsubscribeResponse{}

resp, err := s.Do(request, r)
if err != nil {
return nil, resp, err
}

return r, resp, nil
}
15 changes: 15 additions & 0 deletions pkg/types/datalayer.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package types

import (
"github.com/samber/mo"
)

// DatalayerMirror represents a single mirror for a data store
type DatalayerMirror struct {
CoinID Bytes32 `json:"coin_id"`
LauncherID Bytes32 `json:"launcher_id"`
Amount uint64 `json:"amount"`
URLs []string `json:"urls"`
Ours bool `json:"ours"`
ConfirmedAtHeight mo.Option[uint32] `json:"confirmed_at_height"`
}
31 changes: 31 additions & 0 deletions pkg/types/wonkyset.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package types

import (
"fmt"
)

// WonkySet is just an alias for map[string]string that will unmarshal correctly from the empty forms {} and []
// In chia-blockchain, the default for some sets was incorrectly [] in the initial config
// so this ensures compatability with both ways the empty values could show up
type WonkySet map[string]string

// UnmarshalYAML implements the yaml.Unmarshaler interface.
func (ws *WonkySet) UnmarshalYAML(unmarshal func(interface{}) error) error {
// Attempt to unmarshal into a slice of strings.
var sliceErr error
var mapErr error
var slice []string
if sliceErr = unmarshal(&slice); sliceErr == nil {
*ws = make(map[string]string)
return nil
}

// Attempt to unmarshal into a map.
var m map[string]string
if mapErr = unmarshal(&m); mapErr != nil {
return fmt.Errorf("failed to unmarshal as either string slice or map: slice err: %s | map err: %s", sliceErr.Error(), mapErr.Error())
}

*ws = m
return nil
}
45 changes: 45 additions & 0 deletions pkg/types/wonkyset_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package types_test

import (
"testing"

"github.com/stretchr/testify/assert"
"gopkg.in/yaml.v3"

"github.com/chia-network/go-chia-libs/pkg/config"
)

// TestWonkySet_UnmarshalYAML ensures that this will unmarshal both empty list [] and dict {} into empty map[string]string
// And also ensures an actual !!set as it would show up in the yaml unmarshals correctly
func TestWonkySet_UnmarshalYAML(t *testing.T) {
var yamlWithList = []byte(`
farmer:
pool_public_keys: []
`)
var yamlWithDict = []byte(`
farmer:
pool_public_keys: {}
`)

var yamlWithData = []byte(`
farmer:
pool_public_keys: !!set
abc123: null
456xyz: null
`)

cfg := &config.ChiaConfig{}
err := yaml.Unmarshal(yamlWithList, cfg)
assert.NoError(t, err)
assert.Len(t, cfg.Farmer.PoolPublicKeys, 0)

cfg = &config.ChiaConfig{}
err = yaml.Unmarshal(yamlWithDict, cfg)
assert.NoError(t, err)
assert.Len(t, cfg.Farmer.PoolPublicKeys, 0)

cfg = &config.ChiaConfig{}
err = yaml.Unmarshal(yamlWithData, cfg)
assert.NoError(t, err)
assert.Len(t, cfg.Farmer.PoolPublicKeys, 2)
}

0 comments on commit ac5fb4a

Please sign in to comment.