From fa49daa7e99a6fb8bb11feff3442005a3b2b5c9f Mon Sep 17 00:00:00 2001 From: Narbeh Shahnazarian Date: Mon, 28 Jul 2025 11:40:13 -0700 Subject: [PATCH 01/10] adds contains endpoints to admin service client --- pkg/adminService/client.go | 70 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/pkg/adminService/client.go b/pkg/adminService/client.go index 115e4604..860b6c54 100644 --- a/pkg/adminService/client.go +++ b/pkg/adminService/client.go @@ -15,6 +15,10 @@ type ResourceProviderListItem struct { ResourceProvider string `json:"resource_provider"` } +type ResourceProviderInListResponse struct { + InAllowList bool `json:"in_allow_list"` +} + type AdminServiceClient interface { GetAllowList() ([]ResourceProviderListItem, error) GetTestList() ([]ResourceProviderListItem, error) @@ -114,3 +118,69 @@ func (a *adminServiceClient) GetAllowList() ([]ResourceProviderListItem, error) return response, nil } + +func (a *adminServiceClient) isRPonAllowList(resourceProvider string) (ResourceProviderInListResponse, error) { + isRpOnAllowListUrl := a.clientOptions.BaseURL + "/api/v1/allow-list/contains/" + resourceProvider + + req, err := http.NewRequest("GET", isRpOnAllowListUrl, nil) + if err != nil { + log.Error().Err(err).Msg("Unable to build admin service rp contained on allow list request") + return ResourceProviderInListResponse{}, err + } + + req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", a.clientOptions.ApiKey)) + resp, err := a.client.Do(req) + if err != nil { + log.Error().Err(err).Msg("Failed admin service call to check if RP is on allow list request") + return ResourceProviderInListResponse{}, err + } + defer resp.Body.Close() + + body, err := io.ReadAll(resp.Body) + if err != nil { + log.Error().Err(err).Msg("Failed reading get rp contained on allow list response") + return ResourceProviderInListResponse{}, err + } + + var response ResourceProviderInListResponse + err = json.Unmarshal(body, &response) + if err != nil { + log.Error().Err(err).Msg("Failed unmarshelling get rp contained on allow list response") + return ResourceProviderInListResponse{}, err + } + + return response, nil +} + +func (a *adminServiceClient) isRPonTestList(resourceProvider string) (ResourceProviderInListResponse, error) { + isRpOnAllowListUrl := a.clientOptions.BaseURL + "/api/v1/test-list/contains/" + resourceProvider + + req, err := http.NewRequest("GET", isRpOnAllowListUrl, nil) + if err != nil { + log.Error().Err(err).Msg("Unable to build admin service rp contained on test list request") + return ResourceProviderInListResponse{}, err + } + + req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", a.clientOptions.ApiKey)) + resp, err := a.client.Do(req) + if err != nil { + log.Error().Err(err).Msg("Failed admin service call to check if RP is on test list request") + return ResourceProviderInListResponse{}, err + } + defer resp.Body.Close() + + body, err := io.ReadAll(resp.Body) + if err != nil { + log.Error().Err(err).Msg("Failed reading get rp contained on test list response") + return ResourceProviderInListResponse{}, err + } + + var response ResourceProviderInListResponse + err = json.Unmarshal(body, &response) + if err != nil { + log.Error().Err(err).Msg("Failed unmarshelling get rp contained on test list response") + return ResourceProviderInListResponse{}, err + } + + return response, nil +} From 7fd41ea9200ac9204c2058d23a46fd9cd582d4cc Mon Sep 17 00:00:00 2001 From: Narbeh Shahnazarian Date: Mon, 28 Jul 2025 11:44:30 -0700 Subject: [PATCH 02/10] exposes contains methods in client interface def --- pkg/adminService/client.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/pkg/adminService/client.go b/pkg/adminService/client.go index 860b6c54..66a9bca4 100644 --- a/pkg/adminService/client.go +++ b/pkg/adminService/client.go @@ -22,6 +22,8 @@ type ResourceProviderInListResponse struct { type AdminServiceClient interface { GetAllowList() ([]ResourceProviderListItem, error) GetTestList() ([]ResourceProviderListItem, error) + IsRPonAllowList(resourceProvider string) (bool, error) + IsRPonTestList(resourceProvider string) (bool, error) } type AdminServiceClientOptions struct { @@ -119,7 +121,7 @@ func (a *adminServiceClient) GetAllowList() ([]ResourceProviderListItem, error) return response, nil } -func (a *adminServiceClient) isRPonAllowList(resourceProvider string) (ResourceProviderInListResponse, error) { +func (a *adminServiceClient) IsRPonAllowList(resourceProvider string) (ResourceProviderInListResponse, error) { isRpOnAllowListUrl := a.clientOptions.BaseURL + "/api/v1/allow-list/contains/" + resourceProvider req, err := http.NewRequest("GET", isRpOnAllowListUrl, nil) @@ -152,7 +154,7 @@ func (a *adminServiceClient) isRPonAllowList(resourceProvider string) (ResourceP return response, nil } -func (a *adminServiceClient) isRPonTestList(resourceProvider string) (ResourceProviderInListResponse, error) { +func (a *adminServiceClient) IsRPonTestList(resourceProvider string) (ResourceProviderInListResponse, error) { isRpOnAllowListUrl := a.clientOptions.BaseURL + "/api/v1/test-list/contains/" + resourceProvider req, err := http.NewRequest("GET", isRpOnAllowListUrl, nil) From 526186f7a5cd7525d4ec2fc609640c40f4de94f6 Mon Sep 17 00:00:00 2001 From: Narbeh Shahnazarian Date: Mon, 28 Jul 2025 11:46:16 -0700 Subject: [PATCH 03/10] fixes return type on contains methods in client --- pkg/adminService/client.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/adminService/client.go b/pkg/adminService/client.go index 66a9bca4..b36c3b1e 100644 --- a/pkg/adminService/client.go +++ b/pkg/adminService/client.go @@ -22,8 +22,8 @@ type ResourceProviderInListResponse struct { type AdminServiceClient interface { GetAllowList() ([]ResourceProviderListItem, error) GetTestList() ([]ResourceProviderListItem, error) - IsRPonAllowList(resourceProvider string) (bool, error) - IsRPonTestList(resourceProvider string) (bool, error) + IsRPonAllowList(resourceProvider string) (ResourceProviderInListResponse, error) + IsRPonTestList(resourceProvider string) (ResourceProviderInListResponse, error) } type AdminServiceClientOptions struct { From 67c15cc924c73c55f461cec5c1afe69f4266c1fd Mon Sep 17 00:00:00 2001 From: Narbeh Shahnazarian Date: Mon, 28 Jul 2025 11:50:42 -0700 Subject: [PATCH 04/10] readjusts response objects for testlist and allowlist endpoints --- pkg/adminService/client.go | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/pkg/adminService/client.go b/pkg/adminService/client.go index b36c3b1e..72aa7488 100644 --- a/pkg/adminService/client.go +++ b/pkg/adminService/client.go @@ -15,15 +15,19 @@ type ResourceProviderListItem struct { ResourceProvider string `json:"resource_provider"` } -type ResourceProviderInListResponse struct { - InAllowList bool `json:"in_allow_list"` +type ResourceProviderInAllowListResponse struct { + InAllowList bool `json:"inAllowList"` +} + +type ResourceProviderInTestListResponse struct { + InTestList bool `json:"inTestList"` } type AdminServiceClient interface { GetAllowList() ([]ResourceProviderListItem, error) GetTestList() ([]ResourceProviderListItem, error) - IsRPonAllowList(resourceProvider string) (ResourceProviderInListResponse, error) - IsRPonTestList(resourceProvider string) (ResourceProviderInListResponse, error) + IsRPonAllowList(resourceProvider string) (ResourceProviderInAllowListResponse, error) + IsRPonTestList(resourceProvider string) (ResourceProviderInTestListResponse, error) } type AdminServiceClientOptions struct { @@ -121,67 +125,67 @@ func (a *adminServiceClient) GetAllowList() ([]ResourceProviderListItem, error) return response, nil } -func (a *adminServiceClient) IsRPonAllowList(resourceProvider string) (ResourceProviderInListResponse, error) { +func (a *adminServiceClient) IsRPonAllowList(resourceProvider string) (ResourceProviderInAllowListResponse, error) { isRpOnAllowListUrl := a.clientOptions.BaseURL + "/api/v1/allow-list/contains/" + resourceProvider req, err := http.NewRequest("GET", isRpOnAllowListUrl, nil) if err != nil { log.Error().Err(err).Msg("Unable to build admin service rp contained on allow list request") - return ResourceProviderInListResponse{}, err + return ResourceProviderInAllowListResponse{}, err } req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", a.clientOptions.ApiKey)) resp, err := a.client.Do(req) if err != nil { log.Error().Err(err).Msg("Failed admin service call to check if RP is on allow list request") - return ResourceProviderInListResponse{}, err + return ResourceProviderInAllowListResponse{}, err } defer resp.Body.Close() body, err := io.ReadAll(resp.Body) if err != nil { log.Error().Err(err).Msg("Failed reading get rp contained on allow list response") - return ResourceProviderInListResponse{}, err + return ResourceProviderInAllowListResponse{}, err } var response ResourceProviderInListResponse err = json.Unmarshal(body, &response) if err != nil { log.Error().Err(err).Msg("Failed unmarshelling get rp contained on allow list response") - return ResourceProviderInListResponse{}, err + return ResourceProviderInAllowListResponse{}, err } return response, nil } -func (a *adminServiceClient) IsRPonTestList(resourceProvider string) (ResourceProviderInListResponse, error) { +func (a *adminServiceClient) IsRPonTestList(resourceProvider string) (ResourceProviderInTestListResponse, error) { isRpOnAllowListUrl := a.clientOptions.BaseURL + "/api/v1/test-list/contains/" + resourceProvider req, err := http.NewRequest("GET", isRpOnAllowListUrl, nil) if err != nil { log.Error().Err(err).Msg("Unable to build admin service rp contained on test list request") - return ResourceProviderInListResponse{}, err + return ResourceProviderInTestListResponse{}, err } req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", a.clientOptions.ApiKey)) resp, err := a.client.Do(req) if err != nil { log.Error().Err(err).Msg("Failed admin service call to check if RP is on test list request") - return ResourceProviderInListResponse{}, err + return ResourceProviderInTestListResponse{}, err } defer resp.Body.Close() body, err := io.ReadAll(resp.Body) if err != nil { log.Error().Err(err).Msg("Failed reading get rp contained on test list response") - return ResourceProviderInListResponse{}, err + return ResourceProviderInTestListResponse{}, err } - var response ResourceProviderInListResponse + var response ResourceProviderInTestListResponse err = json.Unmarshal(body, &response) if err != nil { log.Error().Err(err).Msg("Failed unmarshelling get rp contained on test list response") - return ResourceProviderInListResponse{}, err + return ResourceProviderInTestListResponse{}, err } return response, nil From 91560a5004fdd3a0c06c5bc7f6c3966abe63c9ae Mon Sep 17 00:00:00 2001 From: Narbeh Shahnazarian Date: Mon, 28 Jul 2025 11:51:19 -0700 Subject: [PATCH 05/10] adds contains methods to solver controller --- pkg/solver/controller.go | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/pkg/solver/controller.go b/pkg/solver/controller.go index 2dec302c..a489491c 100644 --- a/pkg/solver/controller.go +++ b/pkg/solver/controller.go @@ -870,3 +870,35 @@ func (controller *SolverController) getAllowList() ([]string, error) { return allowList, nil } + +func (controller *SolverController) isRpOnAllowList(resourceProvider string) (bool, error) { + client, err := adminService.NewAdminServiceClient(controller.options.AdminService) + if err != nil { + controller.log.Error().Err(err).Msg("failed to create admin service client") + return false, err + } + + response, err := client.IsRPonAllowList(resourceProvider) + if err != nil { + controller.log.Error().Err(err).Msg("failed to check if RP is on allow list thru admin service") + return false, err + } + + return response.InAllowList, nil +} + +func (controller *SolverController) isRpOnTestList(resourceProvider string) (bool, error) { + client, err := adminService.NewAdminServiceClient(controller.options.AdminService) + if err != nil { + controller.log.Error().Err(err).Msg("failed to create admin service client") + return false, err + } + + response, err := client.IsRPonTestList(resourceProvider) + if err != nil { + controller.log.Error().Err(err).Msg("failed to check if RP is on test list thru admin service") + return false, err + } + + return response.InTestList, nil +} From ea0d898a8ed3fdafe4bb619c0f1d977dc2e3ad2c Mon Sep 17 00:00:00 2001 From: Narbeh Shahnazarian Date: Mon, 28 Jul 2025 14:20:25 -0700 Subject: [PATCH 06/10] fixes compile error --- pkg/adminService/client.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/adminService/client.go b/pkg/adminService/client.go index 72aa7488..e4776828 100644 --- a/pkg/adminService/client.go +++ b/pkg/adminService/client.go @@ -148,7 +148,7 @@ func (a *adminServiceClient) IsRPonAllowList(resourceProvider string) (ResourceP return ResourceProviderInAllowListResponse{}, err } - var response ResourceProviderInListResponse + var response ResourceProviderInAllowListResponse err = json.Unmarshal(body, &response) if err != nil { log.Error().Err(err).Msg("Failed unmarshelling get rp contained on allow list response") From 0b8ee8f6cf1fd1f6b9a048f2d4f758065089344c Mon Sep 17 00:00:00 2001 From: Narbeh Shahnazarian Date: Mon, 28 Jul 2025 14:55:50 -0700 Subject: [PATCH 07/10] adds new TestingNeeded agreement state --- pkg/data/enums.go | 1 + 1 file changed, 1 insertion(+) diff --git a/pkg/data/enums.go b/pkg/data/enums.go index f6de5232..f7f5b9c4 100644 --- a/pkg/data/enums.go +++ b/pkg/data/enums.go @@ -35,6 +35,7 @@ var AgreementState = []string{ "TimeoutMatch", "TimeoutExecution", "TimeoutDownload", + "TestingNeeded", } // PaymentReason corresponds to PaymentReason in TypeScript From 3fa6a5dddd3362f6809cda148e188cdf2b2e09f8 Mon Sep 17 00:00:00 2001 From: Narbeh Shahnazarian Date: Mon, 28 Jul 2025 15:22:07 -0700 Subject: [PATCH 08/10] Change check in addResourceOffer to be based on test list --- pkg/solver/server.go | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/pkg/solver/server.go b/pkg/solver/server.go index 93417720..7c2ad26a 100644 --- a/pkg/solver/server.go +++ b/pkg/solver/server.go @@ -569,29 +569,39 @@ func (server *solverServer) addResourceOffer(resourceOffer data.ResourceOffer, r return nil, fmt.Errorf("resource provider address does not match signer address") } + // Boolean flag representing whether the RP is on the testing list i.e. needs to prove they can run a job before joining the network + var isOnTestList = false + // Resource provider must be in allowlist when enabled if server.options.AccessControl.EnableResourceProviderAllowlist { - var allowedProviders []string // Feature Flag to control where the allow list surfaces from if server.controller.options.AdminService.EnableAdminService { - allowedProviders, err = server.controller.getAllowList() + // Compute whether the RP is on the test list + isOnTestList, err = server.controller.isRpOnTestList(signerAddress) if err != nil { - server.log.Error().Err(err).Msgf("Unable to load resource provider allowlist from Admin Service") + server.log.Error().Err(err).Msgf("Unable to test if resource provider allowlist from Admin Service") return nil, err } + + if isOnTestList { + server.log.Debug().Str("address", resourceOffer.ResourceProvider).Msg("resource provider is in test list") + return nil, errors.New("resource provider is on test list") + } } else { - allowedProviders, err = server.store.GetAllowedResourceProviders() + var allowedProviders []string + allowedProviders, err := server.store.GetAllowedResourceProviders() if err != nil { server.log.Error().Err(err).Msgf("Unable to load resource provider allowlist from DB") return nil, err } - } - if !slices.Contains(allowedProviders, resourceOffer.ResourceProvider) { - server.log.Debug().Str("address", resourceOffer.ResourceProvider).Msg("resource provider not in allowlist") - return nil, errors.New("resource provider not in beta program, request beta program access here: https://forms.gle/XaE3rRuXVLxTnZto7") + if !slices.Contains(allowedProviders, resourceOffer.ResourceProvider) { + server.log.Debug().Str("address", resourceOffer.ResourceProvider).Msg("resource provider not in allowlist") + return nil, errors.New("resource provider not in beta program, request beta program access here: https://forms.gle/XaE3rRuXVLxTnZto7") + } } + } if server.options.AccessControl.EnableVersionCheck { From 5c546864f631bf87dc54881f930b2c6e6fde7238 Mon Sep 17 00:00:00 2001 From: Narbeh Shahnazarian Date: Tue, 29 Jul 2025 16:51:46 -0700 Subject: [PATCH 09/10] changes enum state to PendingTesting --- pkg/data/enums.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/pkg/data/enums.go b/pkg/data/enums.go index f7f5b9c4..2d460eba 100644 --- a/pkg/data/enums.go +++ b/pkg/data/enums.go @@ -35,7 +35,7 @@ var AgreementState = []string{ "TimeoutMatch", "TimeoutExecution", "TimeoutDownload", - "TestingNeeded", + "PendingTesting", } // PaymentReason corresponds to PaymentReason in TypeScript @@ -88,6 +88,10 @@ func GetDefaultAgreementState() uint8 { return GetAgreementStateIndex("DealNegotiating") } +func GetTestPendingAgreementState() uint8 { + return GetAgreementStateIndex("PendingTesting") +} + func IsActiveAgreementState(itemType uint8) bool { return itemType == GetAgreementStateIndex("DealNegotiating") || itemType == GetAgreementStateIndex("DealAgreed") } From 604ba090b389bbb392c4d3cd606f3e2e9ae17d78 Mon Sep 17 00:00:00 2001 From: Narbeh Shahnazarian Date: Tue, 29 Jul 2025 16:53:34 -0700 Subject: [PATCH 10/10] rewires a testlist rp to post a PendingTesting offer and to recieve corresponding log message --- pkg/data/utils.go | 12 ++++++ pkg/solver/controller.go | 78 +++++++++++++++++++++++++++++++++++++++ pkg/solver/server.go | 27 +++++++++++++- pkg/solver/store/db/db.go | 7 ++++ pkg/solver/store/store.go | 2 + 5 files changed, 124 insertions(+), 2 deletions(-) diff --git a/pkg/data/utils.go b/pkg/data/utils.go index 22feb7a0..2e4a12b5 100644 --- a/pkg/data/utils.go +++ b/pkg/data/utils.go @@ -153,6 +153,18 @@ func GetResourceOfferContainer( } } +func GetTestListResourceOfferContainer( + resourceOffer ResourceOffer, +) ResourceOfferContainer { + return ResourceOfferContainer{ + ID: resourceOffer.ID, + DealID: "", + ResourceProvider: resourceOffer.ResourceProvider, + State: GetTestPendingAgreementState(), + ResourceOffer: resourceOffer, + } +} + func GetDealContainer( deal Deal, ) DealContainer { diff --git a/pkg/solver/controller.go b/pkg/solver/controller.go index a489491c..6e1d13a2 100644 --- a/pkg/solver/controller.go +++ b/pkg/solver/controller.go @@ -29,6 +29,7 @@ type SolverEventType string const ( JobOfferAdded SolverEventType = "JobOfferAdded" ResourceOfferAdded SolverEventType = "ResourceOfferAdded" + TestListResourceOfferAdded SolverEventType = "TestListResourceOfferAdded" ResourceOfferRemoved SolverEventType = "ResourceOfferRemoved" DealAdded SolverEventType = "DealAdded" JobOfferStateUpdated SolverEventType = "JobOfferStateUpdated" @@ -610,6 +611,83 @@ func (controller *SolverController) addResourceOffer(resourceOffer data.Resource return ret, nil } +func (controller *SolverController) addTestResourceOffer(resourceOffer data.ResourceOffer) (*data.ResourceOfferContainer, error) { + id, err := data.GetResourceOfferID(resourceOffer) + if err != nil { + return nil, err + } + resourceOffer.ID = id + + // Check if we have an unmatched resource offer for the resource provider + existingOffers, err := controller.store.GetResourceOffers(store.GetResourceOffersQuery{ + ResourceProvider: resourceOffer.ResourceProvider, + NotMatched: true, + PendingTesting: true, + }) + if len(existingOffers) > 0 { + controller.log.Warn(). + Str("address", resourceOffer.ResourceProvider). + Msg("resource provider posted a test list resource offer when an unmatched offer already exists") + // TODO(bgins) Return error to resource provider + // The resource provider currently crashes when an error is returned. Once we update the + // resource provider to selectively handle errors, we should return one here. + return nil, nil + } + + // Check the resource provider's ETH balance + balance, err := controller.web3SDK.GetBalance(resourceOffer.ResourceProvider) + if err != nil { + return nil, fmt.Errorf("failed to retrieve ETH balance for resource provider: %v", err) + } + // Convert InstructionPrice from ETH to Wei + requiredBalanceWei := web3.EtherToWei(REQUIRED_BALANCE_IN_WEI) // 0.0006 based on the required balance for a job + + // If the balance is less than the required balance, don't add the resource offer + if balance.Cmp(requiredBalanceWei) < 0 { + controller.log.Error().Err(err). + Str("addresss", resourceOffer.ResourceProvider). + Str("balance", balance.String()). + Str("requiredBalance", requiredBalanceWei.String()). + Msg("resource provider does not have enough ETH to post test resource offer") + return nil, nil + } + + // required LP balance + requiredBalanceLp := web3.EtherToWei(float64(resourceOffer.DefaultPricing.InstructionPrice)) // based on the required LP balance for a job + balanceLp, err := controller.web3SDK.GetLPBalance(resourceOffer.ResourceProvider) + if err != nil { + controller.log.Error().Err(err).Msg("failed to retrieve LP balance for resource provider") + return nil, nil + } + if balanceLp.Cmp(requiredBalanceLp) < 0 { + controller.log.Error().Err(err). + Str("addresss", resourceOffer.ResourceProvider). + Str("balance", balanceLp.String()). + Str("requiredBalance", requiredBalanceLp.String()). + Msg("resource provider does not have enough LP to post test resource offer") + return nil, nil + } + + controller.log.Info().Str("cid", resourceOffer.ID). + Str("address", resourceOffer.ResourceProvider). + Any("test resourceOffer", resourceOffer). + Msg("adding test list resource offer") + + //TODO: figure out how you want to track this + //metricsDashboard.TrackNodeInfo(resourceOffer) + + ret, err := controller.store.AddResourceOffer(data.GetTestListResourceOfferContainer(resourceOffer)) + if err != nil { + return nil, err + } + + controller.writeEvent(SolverEvent{ + EventType: TestListResourceOfferAdded, + ResourceOffer: ret, + }) + return ret, nil +} + // Remove resource offers in an unmatched DealNegotiating[0] state func (controller *SolverController) removeUnmatchedResourceOffers(resourceProviderID string) error { controller.log.Info().Str("address", resourceProviderID).Msg("remove unmatched resource offers") diff --git a/pkg/solver/server.go b/pkg/solver/server.go index 7c2ad26a..f9b9f0a1 100644 --- a/pkg/solver/server.go +++ b/pkg/solver/server.go @@ -584,9 +584,16 @@ func (server *solverServer) addResourceOffer(resourceOffer data.ResourceOffer, r return nil, err } + // If the RP is on the test list, we will post its offer but set it so that it's pending a test (i.e. proving it can run a job) before it can join the network if isOnTestList { - server.log.Debug().Str("address", resourceOffer.ResourceProvider).Msg("resource provider is in test list") - return nil, errors.New("resource provider is on test list") + resourceOfferContainer, err := server.addTestListResourceOffer(resourceOffer) + if err != nil { + server.log.Error().Err(err).Msg("Error adding resource offer for test list") + } + + server.log.Info().Str("address", resourceOffer.ResourceProvider).Any("Resource Offer", resourceOfferContainer).Msg("resource provider is in test list and posted TestPending Offer") + // Return an error here to notify the RP that it needs to undergo testing + return nil, errors.New("resource provider is on test list, your machine will under go automated testing before it will be allowed to post an official resource offer on the network") } } else { var allowedProviders []string @@ -631,6 +638,22 @@ func (server *solverServer) addResourceOffer(resourceOffer data.ResourceOffer, r return server.controller.addResourceOffer(resourceOffer) } +func (server *solverServer) addTestListResourceOffer(resourceOffer data.ResourceOffer) (*data.ResourceOfferContainer, error) { + offerRecent := isTimestampRecent(resourceOffer.CreatedAt, server.options.AccessControl.OfferTimestampDiffSeconds*1000) + if !offerRecent { + server.log.Debug().Str("cid", resourceOffer.ID).Str("address", resourceOffer.ResourceProvider).Msg("resource offer rejected because timestamp was not recent") + return nil, errors.New("resource offer rejected because CreatedAt time is not recent, check your computer's time settings and network connection") + } + + err := data.CheckResourceOffer(resourceOffer) + if err != nil { + server.log.Error().Err(err).Msg("Error checking resource offer") + return nil, err + } + + return server.controller.addTestResourceOffer(resourceOffer) +} + func (server *solverServer) addResult(results data.Result, res corehttp.ResponseWriter, req *corehttp.Request) (*data.Result, error) { vars := mux.Vars(req) id := vars["id"] diff --git a/pkg/solver/store/db/db.go b/pkg/solver/store/db/db.go index 2e9c3b2d..144a6edf 100644 --- a/pkg/solver/store/db/db.go +++ b/pkg/solver/store/db/db.go @@ -246,6 +246,13 @@ func (store *SolverStoreDatabase) GetResourceOffers(query store.GetResourceOffer data.GetAgreementStateIndex("DealAgreed"), }) } + + if query.PendingTesting { + q = q.Where("state IN (?)", []uint8{ + data.GetAgreementStateIndex("PendingTesting"), + }) + } + if query.OrderOldestFirst { q = q.Order("created_at ASC") } diff --git a/pkg/solver/store/store.go b/pkg/solver/store/store.go index ff6ecdc6..f6a910df 100644 --- a/pkg/solver/store/store.go +++ b/pkg/solver/store/store.go @@ -55,6 +55,8 @@ type GetResourceOffersQuery struct { // Sort resource offers oldest first OrderOldestFirst bool `json:"order_oldest_first"` + + PendingTesting bool `json:"pending_test"` } type GetDealsQuery struct {