Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: module allowlist #166

Closed
wants to merge 16 commits into from
Closed
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions pkg/data/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,9 @@ import (
"fmt"
"math/big"

"github.com/lilypad-tech/lilypad/pkg/web3/bindings/controller"
"github.com/ethereum/go-ethereum/common"

mdag "github.com/ipfs/go-merkledag"
"github.com/lilypad-tech/lilypad/pkg/web3/bindings/controller"
)

// CalculateCID takes an interface, serializes it to JSON, and returns its IPFS CID
Expand Down
31 changes: 30 additions & 1 deletion pkg/http/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,10 @@ import (
"net/http"
"net/url"
"strings"
"time"

"github.com/lilypad-tech/lilypad/pkg/web3"
"github.com/hashicorp/go-retryablehttp"
"github.com/lilypad-tech/lilypad/pkg/web3"
"github.com/rs/zerolog/log"
)

Expand Down Expand Up @@ -397,3 +398,31 @@ func newRetryClient() *retryablehttp.Client {
}
return retryClient
}

func GetRequestWithTimeout(url string, timeout time.Duration) ([]byte, error) {
// A HTTP client with the specified timeout
client := &http.Client{
Timeout: timeout,
}

// Create the HTTP request
req, err := http.NewRequest("GET", url, nil)
if err != nil {
return nil, fmt.Errorf("creating module-allowlist request failed: %s", err)
}

// Perform the HTTP request
resp, err := client.Do(req)
if err != nil {
return nil, fmt.Errorf("executing module-allowlist request failed: %s", err)
}
defer resp.Body.Close()

// Read the response body
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("reading module-allowlist response body failed: %s", err)
}

return body, nil
}
75 changes: 69 additions & 6 deletions pkg/jobcreator/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package jobcreator
import (
"context"
"fmt"
"strings"
"time"

"github.com/lilypad-tech/lilypad/pkg/data"
Expand All @@ -25,13 +26,18 @@ type JobCreatorController struct {
loop *system.ControlLoop
log *system.ServiceLogger
jobOfferSubscriptions []JobOfferSubscriber
moduleAllowlist []string
}

// the background "even if we have not heard of an event" loop
// i.e. things will not wait 10 seconds - the control loop
// reacts to events in the system - this 10 second background
// loop is just for in case we miss any events
const CONTROL_LOOP_INTERVAL = 10 * time.Second
const (
allowlistURL = "https://raw.githubusercontent.com/lilypad-tech/module-allowlist/main/allowlist.txt"

// the background "even if we have not heard of an event" loop
// i.e. things will not wait 10 seconds - the control loop
// reacts to events in the system - this 10 second background
// loop is just for in case we miss any events
CONTROL_LOOP_INTERVAL = 10 * time.Second
)

func NewJobCreatorController(
options JobCreatorOptions,
Expand Down Expand Up @@ -154,8 +160,29 @@ func (controller *JobCreatorController) subscribeToWeb3() error {
}

func (controller *JobCreatorController) Start(ctx context.Context, cm *system.CleanupManager) chan error {
// Initial fetch of the module allowlist
err := controller.UpdateModuleAllowlist()
if err != nil {
controller.log.Error("failed to fetch module allowlist", err)
}

// Periodic update logic here using a time.Ticker
ticker := time.NewTicker(1 * time.Hour)
go func() {
for {
select {
case <-ticker.C:
controller.UpdateModuleAllowlist()
case <-ctx.Done():
ticker.Stop()
return
}
}
}()

errorChan := make(chan error)
err := controller.subscribeToSolver()

err = controller.subscribeToSolver()
if err != nil {
errorChan <- err
return errorChan
Expand All @@ -165,6 +192,11 @@ func (controller *JobCreatorController) Start(ctx context.Context, cm *system.Cl
errorChan <- err
return errorChan
}
err = controller.allowlistApproved()
if err != nil {
errorChan <- err
return errorChan
}

// this connects the websocket client
err = controller.solverClient.Start(ctx, cm)
Expand Down Expand Up @@ -200,6 +232,35 @@ func (controller *JobCreatorController) Start(ctx context.Context, cm *system.Cl
return errorChan
}

func (controller *JobCreatorController) UpdateModuleAllowlist() error {
// Call the new helper function with a 5-second timeout!
body, err := http.GetRequestWithTimeout(allowlistURL, 5*time.Second)
if err != nil {
return fmt.Errorf("failed to fetch module allowlist: %s", err)
}

// Update the internal cache of the allowlist
controller.moduleAllowlist = strings.Split(strings.TrimSpace(string(body)), "\n")
return nil
}

func (controller *JobCreatorController) allowlistApproved() error {
controller.web3Events.Storage.SubscribeDealStateChange(func(ev storage.StorageDealStateChange) {
deal, err := controller.solverClient.GetDeal(ev.DealId)
if err != nil {
controller.log.Error("module allowlist error", err)
return
}
if deal.JobCreator != controller.web3SDK.GetAddress().String() {
return
}
controller.log.Debug("StorageDealStateChange", data.GetAgreementStateString(ev.State))
system.DumpObjectDebug(ev)
controller.loop.Trigger()
})
return nil
}

/*
*
*
Expand Down Expand Up @@ -237,6 +298,7 @@ func (controller *JobCreatorController) solve() error {
*
*/

// list the deals we have been assigned to that we have not yet posted and agree tx to the contract for
// list the deals we have been assigned to that we have not yet posted and agree tx to the contract for
func (controller *JobCreatorController) agreeToDeals() error {
// load the deals that are in DealNegotiating
Expand Down Expand Up @@ -287,6 +349,7 @@ func (controller *JobCreatorController) agreeToDeals() error {
// list the deals that have results posted but we have not yet checked
// we do this synchronously to prevent us racing with large result sets
// also we are the client so have a lower chance of there being a chunky backlog

func (controller *JobCreatorController) checkResults() error {
// load all deals in ResultsSubmitted state and don't have either results checked or accepted txs
completedDeals, err := controller.solverClient.GetDealsWithFilter(
Expand Down