diff --git a/routes/server.go b/routes/server.go index ee64758f..d85e9ffd 100644 --- a/routes/server.go +++ b/routes/server.go @@ -72,6 +72,7 @@ const ( RoutePathGetSingleProfile = "/api/v0/get-single-profile" RoutePathGetSingleProfilePicture = "/api/v0/get-single-profile-picture" RoutePathGetHodlersForPublicKey = "/api/v0/get-hodlers-for-public-key" + RoutePathGetHodlersForPublicKeys = "/api/v0/get-hodlers-for-public-keys" RoutePathGetHodlersCountForPublicKeys = "/api/v0/get-hodlers-count-for-public-keys" RoutePathGetDiamondsForPublicKey = "/api/v0/get-diamonds-for-public-key" RoutePathGetFollowsStateless = "/api/v0/get-follows-stateless" @@ -824,7 +825,14 @@ func (fes *APIServer) NewRouter() *muxtrace.Router { "GetHodlersForPublicKey", []string{"POST", "OPTIONS"}, RoutePathGetHodlersForPublicKey, - fes.GetHodlersForPublicKey, + fes.GetHodlersForPublicKeyEndpoint, + PublicAccess, + }, + { + "GetHodlersForPublicKeys", + []string{"POST", "OPTIONS"}, + RoutePathGetHodlersForPublicKeys, + fes.GetHodlersForPublicKeysEndpoint, PublicAccess, }, { diff --git a/routes/user.go b/routes/user.go index 6ebab6ba..b3cdce6a 100644 --- a/routes/user.go +++ b/routes/user.go @@ -1310,6 +1310,30 @@ type GetHodlersForPublicKeyResponse struct { LastPublicKeyBase58Check string } +type GetHodlersForPublicKeysRequest struct { + // Array of Public Keys to retrieve hodlers for. + PublicKeysBase58Check []string `safeForLogging:"true"` + + // If true, fetch DAO coin balance entries instead of creator coin balance entries. + IsDAOCoin bool `safeForLogging:"true"` + + // If true, fetch balance entries for your hodlings instead of balance entries for hodler's of your coin. + FetchHodlings bool + + // The sorting method to use when returning profiles. Defaults to + // "coin_balance" when unset. + SortType TopHodlerSortType +} + +type GetHodlersForPublicKeysSingleResponse struct { + Hodlers []*BalanceEntryResponse + PublicKeyBase58Check string +} + +type GetHodlersForPublicKeysResponse struct { + HodlersForPublicKeys []*GetHodlersForPublicKeysSingleResponse +} + // Helper function to get the creator public key or the hodler public key depending upon fetchHodlings. func getHodlerOrHodlingPublicKey(balanceEntryResponse *BalanceEntryResponse, fetchHodlings bool) (_publicKeyBase58Check string) { if fetchHodlings { @@ -1336,7 +1360,7 @@ func (fes *APIServer) ComputeWealth( } // GetHodlersForPublicKey... Get BalanceEntryResponses for hodlings. -func (fes *APIServer) GetHodlersForPublicKey(ww http.ResponseWriter, req *http.Request) { +func (fes *APIServer) GetHodlersForPublicKeyEndpoint(ww http.ResponseWriter, req *http.Request) { decoder := json.NewDecoder(io.LimitReader(req.Body, MaxRequestBodySizeBytes)) requestData := GetHodlersForPublicKeyRequest{} if err := decoder.Decode(&requestData); err != nil { @@ -1352,13 +1376,88 @@ func (fes *APIServer) GetHodlersForPublicKey(ww http.ResponseWriter, req *http.R return } + res, err := fes.GetHodlersForPublicKey(&requestData, utxoView) + + if err != nil { + _AddBadRequestError(ww, fmt.Sprintf( + "GetHodlersForPublicKeyEndpoint: Problem getting hodlers for public key: %v", err)) + return + } + + if err = json.NewEncoder(ww).Encode(res); err != nil { + _AddBadRequestError(ww, fmt.Sprintf( + "GetHodlersForPublicKeyEndpoint: Problem encoding response as JSON: %v", err)) + return + } + +} + +func (fes *APIServer) GetHodlersForPublicKeysEndpoint(ww http.ResponseWriter, req *http.Request) { + decoder := json.NewDecoder(io.LimitReader(req.Body, MaxRequestBodySizeBytes)) + requestData := GetHodlersForPublicKeysRequest{} + if err := decoder.Decode(&requestData); err != nil { + _AddBadRequestError(ww, fmt.Sprintf( + "GetHodlersForPublicKey: Problem parsing request body: %v", err)) + return + } + + // Get a view + utxoView, err := fes.backendServer.GetMempool().GetAugmentedUniversalView() + if err != nil { + _AddBadRequestError(ww, fmt.Sprintf("GetHodlersForPublicKey: Error getting utxoView: %v", err)) + return + } + + if len(requestData.PublicKeysBase58Check) == 0 { + _AddBadRequestError(ww, fmt.Sprintf( + "GetHodlersForPublicKeysEndpoint: Must provide at least one public key.")) + return + } + + var hodlersForPublicKeys []*GetHodlersForPublicKeysSingleResponse + + for _, publicKey := range requestData.PublicKeysBase58Check { + publicKeyRequestData := &GetHodlersForPublicKeyRequest{ + PublicKeyBase58Check: publicKey, + IsDAOCoin: requestData.IsDAOCoin, + FetchHodlings: requestData.FetchHodlings, + SortType: requestData.SortType, + FetchAll: true, + } + res, err := fes.GetHodlersForPublicKey(publicKeyRequestData, utxoView) + if err != nil { + _AddBadRequestError(ww, fmt.Sprintf( + "GetHodlersForPublicKeyEndpoint: Problem getting hodlers for public key: %v", err)) + return + } + hodlersForPublicKey := &GetHodlersForPublicKeysSingleResponse{ + Hodlers: res.Hodlers, + PublicKeyBase58Check: publicKey, + } + hodlersForPublicKeys = append(hodlersForPublicKeys, hodlersForPublicKey) + } + + res := &GetHodlersForPublicKeysResponse{ + HodlersForPublicKeys: hodlersForPublicKeys, + } + + if err = json.NewEncoder(ww).Encode(res); err != nil { + _AddBadRequestError(ww, fmt.Sprintf( + "GetHodlersForPublicKeyEndpoint: Problem encoding response as JSON: %v", err)) + return + } + +} + +// GetHodlersForPublicKey... Get BalanceEntryResponses for hodlings. +func (fes *APIServer) GetHodlersForPublicKey(requestData *GetHodlersForPublicKeyRequest, utxoView *lib.UtxoView) (*GetHodlersForPublicKeyResponse, error) { // Decode the public key for which we are fetching hodlers / hodlings. If public key is not provided, use username var publicKeyBytes []byte + var err error if requestData.PublicKeyBase58Check != "" { publicKeyBytes, _, err = lib.Base58CheckDecode(requestData.PublicKeyBase58Check) if err != nil { - _AddBadRequestError(ww, fmt.Sprintf("GetHodlersForPublicKey: Problem decoding user public key: %v", err)) - return + return nil, fmt.Errorf("GetHodlersForPublicKey: Problem decoding user public key: %v", err) } } else { username := requestData.Username @@ -1366,8 +1465,7 @@ func (fes *APIServer) GetHodlersForPublicKey(ww http.ResponseWriter, req *http.R // Return an error if we failed to find a profile entry if profileEntry == nil { - _AddNotFoundError(ww, fmt.Sprintf("GetHodlersForPublicKey: could not find profile for username: %v", username)) - return + return nil, fmt.Errorf("GetHodlersForPublicKey: could not find profile for username: %v", username) } publicKeyBytes = profileEntry.PublicKey } @@ -1379,16 +1477,14 @@ func (fes *APIServer) GetHodlersForPublicKey(ww http.ResponseWriter, req *http.R hodlMap, err = fes.GetYouHodlMap( utxoView.GetPKIDForPublicKey(publicKeyBytes), false, requestData.IsDAOCoin, utxoView) if err != nil { - _AddBadRequestError(ww, fmt.Sprintf("GetHodlersForPublicKey: error getting youHodlMap: %v", err)) - return + return nil, fmt.Errorf("GetHodlersForPublicKey: error getting youHodlMap: %v", err) } } else { hodlMap, err = fes.GetHodlYouMap( utxoView.GetPKIDForPublicKey(publicKeyBytes), false, requestData.IsDAOCoin, utxoView) if err != nil { - _AddBadRequestError(ww, fmt.Sprintf("GetHodlersForPublicKey: error getting youHodlMap: %v", err)) - return + return nil, fmt.Errorf("GetHodlersForPublicKey: error getting youHodlMap: %v", err) } } for _, balanceEntryResponse := range hodlMap { @@ -1399,10 +1495,7 @@ func (fes *APIServer) GetHodlersForPublicKey(ww http.ResponseWriter, req *http.R if requestData.SortType != TopHodlerSortTypeNone && requestData.SortType != TopHodlerSortTypeCoinBalance && requestData.SortType != TopHodlerSortTypeWealth { - - _AddBadRequestError(ww, fmt.Sprintf("GetHodlersForPublicKey: Unrecognized "+ - "sort type: %v", requestData.SortType)) - return + return nil, fmt.Errorf("GetHodlersForPublicKey: Unrecognized sort type: %v", requestData.SortType) } sort.Slice(hodlList, func(ii, jj int) bool { if hodlList[ii].CreatorPublicKeyBase58Check == hodlList[ii].HODLerPublicKeyBase58Check { @@ -1426,9 +1519,6 @@ func (fes *APIServer) GetHodlersForPublicKey(ww http.ResponseWriter, req *http.R jjWealth := fes.ComputeWealth(hodlList[jj], utxoView) return iiWealth > jjWealth } else { - _AddBadRequestError(ww, fmt.Sprintf("GetHodlersForPublicKey: Unrecognized "+ - "sort type: %v", requestData.SortType)) - // TODO: We can't break the execution here but we should return false } }) @@ -1470,11 +1560,7 @@ func (fes *APIServer) GetHodlersForPublicKey(ww http.ResponseWriter, req *http.R Hodlers: hodlList, LastPublicKeyBase58Check: resLastPublicKey, } - if err = json.NewEncoder(ww).Encode(res); err != nil { - _AddBadRequestError(ww, fmt.Sprintf( - "GetHodlersForPublicKey: Problem encoding response as JSON: %v", err)) - return - } + return res, nil } type GetHolderCountForPublicKeysRequest struct {