diff --git a/pkg/config/config.go b/pkg/config/config.go index 6dacbf3..f1cde2b 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -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"` diff --git a/pkg/config/initial-config.yml b/pkg/config/initial-config.yml index 934010d..4c4eadc 100644 --- a/pkg/config/initial-config.yml +++ b/pkg/config/initial-config.yml @@ -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 diff --git a/pkg/rpc/datalayer.go b/pkg/rpc/datalayer.go index 588cd73..83be423 100644 --- a/pkg/rpc/datalayer.go +++ b/pkg/rpc/datalayer.go @@ -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 @@ -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 +} diff --git a/pkg/types/datalayer.go b/pkg/types/datalayer.go new file mode 100644 index 0000000..8d437f3 --- /dev/null +++ b/pkg/types/datalayer.go @@ -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"` +} diff --git a/pkg/types/wonkyset.go b/pkg/types/wonkyset.go new file mode 100644 index 0000000..c2e14c0 --- /dev/null +++ b/pkg/types/wonkyset.go @@ -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 +} diff --git a/pkg/types/wonkyset_test.go b/pkg/types/wonkyset_test.go new file mode 100644 index 0000000..f334d23 --- /dev/null +++ b/pkg/types/wonkyset_test.go @@ -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) +}