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

Add option to filter /contracts endpoint by contract set and return sets in contract metadata #841

Merged
merged 6 commits into from
Dec 20, 2023
Merged
Show file tree
Hide file tree
Changes from 5 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
6 changes: 6 additions & 0 deletions api/contract.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ type (
RenewedFrom types.FileContractID `json:"renewedFrom"`
Spending ContractSpending `json:"spending"`
TotalCost types.Currency `json:"totalCost"`

Sets []string `json:"sets"`
ChrisSchinnerl marked this conversation as resolved.
Show resolved Hide resolved
}

// ContractPrunableData wraps a contract's size information with its id.
Expand Down Expand Up @@ -176,6 +178,10 @@ type (
TotalPrunable uint64 `json:"totalPrunable"`
TotalSize uint64 `json:"totalSize"`
}

ContractsOpts struct {
ContractSet string `json:"contractset"`
}
)

// Add returns the sum of the current and given contract spending.
Expand Down
7 changes: 3 additions & 4 deletions autopilot/accounts.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,7 @@ type AccountStore interface {
}

type ContractStore interface {
Contracts(ctx context.Context) ([]api.ContractMetadata, error)
ContractSetContracts(ctx context.Context, set string) ([]api.ContractMetadata, error)
Contracts(ctx context.Context, opts api.ContractsOpts) ([]api.ContractMetadata, error)
}

func newAccounts(ap *Autopilot, a AccountStore, c ContractStore, w *workerPool, l *zap.SugaredLogger, refillInterval time.Duration) *accounts {
Expand Down Expand Up @@ -114,7 +113,7 @@ func (a *accounts) refillWorkerAccounts(ctx context.Context, w Worker) {
}

// fetch all contracts
contracts, err := a.c.Contracts(ctx)
contracts, err := a.c.Contracts(ctx, api.ContractsOpts{})
if err != nil {
a.l.Errorw(fmt.Sprintf("failed to fetch contracts for refill: %v", err))
return
Expand All @@ -123,7 +122,7 @@ func (a *accounts) refillWorkerAccounts(ctx context.Context, w Worker) {
}

// fetch all contract set contracts
contractSetContracts, err := a.c.ContractSetContracts(ctx, state.cfg.Contracts.Set)
contractSetContracts, err := a.c.Contracts(ctx, api.ContractsOpts{ContractSet: state.cfg.Contracts.Set})
if err != nil {
a.l.Errorw(fmt.Sprintf("failed to fetch contract set contracts: %v", err))
return
Expand Down
3 changes: 1 addition & 2 deletions autopilot/autopilot.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,7 @@ type Bus interface {
AncestorContracts(ctx context.Context, id types.FileContractID, minStartHeight uint64) ([]api.ArchivedContract, error)
ArchiveContracts(ctx context.Context, toArchive map[types.FileContractID]string) error
Contract(ctx context.Context, id types.FileContractID) (api.ContractMetadata, error)
Contracts(ctx context.Context) (contracts []api.ContractMetadata, err error)
ContractSetContracts(ctx context.Context, set string) ([]api.ContractMetadata, error)
Contracts(ctx context.Context, opts api.ContractsOpts) (contracts []api.ContractMetadata, err error)
FileContractTax(ctx context.Context, payout types.Currency) (types.Currency, error)
SetContractSet(ctx context.Context, set string, contracts []types.FileContractID) error
PrunableData(ctx context.Context) (prunableData api.ContractsPrunableDataResponse, err error)
Expand Down
2 changes: 1 addition & 1 deletion autopilot/contract_pruning.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ func (c *contractor) fetchPrunableContracts() (prunable []api.ContractPrunableDa
}

// fetch contract set contracts
csc, err := c.ap.bus.ContractSetContracts(ctx, c.ap.state.cfg.Contracts.Set)
csc, err := c.ap.bus.Contracts(ctx, api.ContractsOpts{ContractSet: c.ap.state.cfg.Contracts.Set})
if err != nil {
return nil, err
}
Expand Down
2 changes: 1 addition & 1 deletion autopilot/contractor.go
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ func (c *contractor) performContractMaintenance(ctx context.Context, w Worker) (
}

// fetch current contract set
currentSet, err := c.ap.bus.ContractSetContracts(ctx, state.cfg.Contracts.Set)
currentSet, err := c.ap.bus.Contracts(ctx, api.ContractsOpts{ContractSet: state.cfg.Contracts.Set})
if err != nil && !strings.Contains(err.Error(), api.ErrContractSetNotFound.Error()) {
return false, err
}
Expand Down
18 changes: 13 additions & 5 deletions bus/bus.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,8 +115,7 @@ type (
ArchiveContracts(ctx context.Context, toArchive map[types.FileContractID]string) error
ArchiveAllContracts(ctx context.Context, reason string) error
Contract(ctx context.Context, id types.FileContractID) (api.ContractMetadata, error)
Contracts(ctx context.Context) ([]api.ContractMetadata, error)
ContractSetContracts(ctx context.Context, set string) ([]api.ContractMetadata, error)
Contracts(ctx context.Context, opts api.ContractsOpts) ([]api.ContractMetadata, error)
ContractSets(ctx context.Context) ([]string, error)
RecordContractSpending(ctx context.Context, records []api.ContractSpendingRecord) error
RemoveContractSet(ctx context.Context, name string) error
Expand Down Expand Up @@ -903,9 +902,15 @@ func (b *bus) hostsBlocklistHandlerPUT(jc jape.Context) {
}

func (b *bus) contractsHandlerGET(jc jape.Context) {
cs, err := b.ms.Contracts(jc.Request.Context())
var cs string
if jc.DecodeForm("contractset", &cs) != nil {
return
}
contracts, err := b.ms.Contracts(jc.Request.Context(), api.ContractsOpts{
ContractSet: cs,
})
if jc.Check("couldn't load contracts", err) == nil {
jc.Encode(cs)
jc.Encode(contracts)
}
}

Expand All @@ -931,7 +936,10 @@ func (b *bus) contractsArchiveHandlerPOST(jc jape.Context) {
}

func (b *bus) contractsSetHandlerGET(jc jape.Context) {
cs, err := b.ms.ContractSetContracts(jc.Request.Context(), jc.PathParam("set"))
cs, err := b.ms.Contracts(jc.Request.Context(),
api.ContractsOpts{
ContractSet: jc.PathParam("set"),
})
if jc.Check("couldn't load contracts", err) == nil {
jc.Encode(cs)
}
Expand Down
8 changes: 6 additions & 2 deletions bus/client/contracts.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,8 +102,12 @@ func (c *Client) ContractSetContracts(ctx context.Context, set string) (contract
}

// Contracts returns all contracts in the metadata store.
func (c *Client) Contracts(ctx context.Context) (contracts []api.ContractMetadata, err error) {
err = c.c.WithContext(ctx).GET("/contracts", &contracts)
func (c *Client) Contracts(ctx context.Context, opts api.ContractsOpts) (contracts []api.ContractMetadata, err error) {
ChrisSchinnerl marked this conversation as resolved.
Show resolved Hide resolved
values := url.Values{}
if opts.ContractSet != "" {
values.Set("contractset", opts.ContractSet)
}
err = c.c.WithContext(ctx).GET("/contracts?"+values.Encode(), &contracts)
return
}

Expand Down
2 changes: 1 addition & 1 deletion internal/testing/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -881,7 +881,7 @@ func (c *TestCluster) WaitForContractSet(set string, n int) {
func (c *TestCluster) waitForHostContracts(hosts map[types.PublicKey]struct{}) {
c.tt.Helper()
c.tt.Retry(300, 100*time.Millisecond, func() error {
contracts, err := c.Bus.Contracts(context.Background())
contracts, err := c.Bus.Contracts(context.Background(), api.ContractsOpts{})
if err != nil {
return err
}
Expand Down
39 changes: 26 additions & 13 deletions internal/testing/cluster_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,12 +77,25 @@ func TestNewTestCluster(t *testing.T) {
t.Fatal("TotalCost and ContractPrice shouldn't be zero")
}

// Make sure the contracts are part of the set.
busContracts, err := cluster.Bus.Contracts(context.Background(), api.ContractsOpts{})
if err != nil {
t.Fatal(err)
}
for _, c := range busContracts {
if len(c.Sets) != 1 {
t.Fatal("contract should be part of one set", len(c.Sets))
} else if c.Sets[0] != sets[0] {
t.Fatalf("contract should be part of set %v but was %v", sets[0], c.Sets[0])
}
}

// Mine blocks until contracts start renewing.
cluster.MineToRenewWindow()

// Wait for the contract to be renewed.
tt.Retry(100, 100*time.Millisecond, func() error {
contracts, err := cluster.Bus.Contracts(context.Background())
contracts, err := cluster.Bus.Contracts(context.Background(), api.ContractsOpts{})
if err != nil {
return err
}
Expand Down Expand Up @@ -120,7 +133,7 @@ func TestNewTestCluster(t *testing.T) {
cluster.MineBlocks(1)

// Fetch renewed contract and make sure we caught the proof and revision.
contracts, err := cluster.Bus.Contracts(context.Background())
contracts, err := cluster.Bus.Contracts(context.Background(), api.ContractsOpts{})
if err != nil {
t.Fatal(err)
}
Expand Down Expand Up @@ -567,7 +580,7 @@ func TestUploadDownloadBasic(t *testing.T) {
}

// fetch the contracts.
contracts, err := cluster.Bus.Contracts(context.Background())
contracts, err := cluster.Bus.Contracts(context.Background(), api.ContractsOpts{})
tt.OK(err)

// broadcast the revision for each contract and assert the revision height
Expand All @@ -585,7 +598,7 @@ func TestUploadDownloadBasic(t *testing.T) {
// check the revision height was updated.
tt.Retry(100, 100*time.Millisecond, func() error {
// fetch the contracts.
contracts, err := cluster.Bus.Contracts(context.Background())
contracts, err := cluster.Bus.Contracts(context.Background(), api.ContractsOpts{})
if err != nil {
return err
}
Expand Down Expand Up @@ -755,7 +768,7 @@ func TestUploadDownloadSpending(t *testing.T) {

// check that the funding was recorded
tt.Retry(100, testBusFlushInterval, func() error {
cms, err := cluster.Bus.Contracts(context.Background())
cms, err := cluster.Bus.Contracts(context.Background(), api.ContractsOpts{})
tt.OK(err)
if len(cms) == 0 {
t.Fatal("no contracts found")
Expand Down Expand Up @@ -849,7 +862,7 @@ func TestUploadDownloadSpending(t *testing.T) {
// wait for the contract to be renewed
tt.Retry(100, 100*time.Millisecond, func() error {
// fetch contracts
cms, err := cluster.Bus.Contracts(context.Background())
cms, err := cluster.Bus.Contracts(context.Background(), api.ContractsOpts{})
tt.OK(err)
if len(cms) == 0 {
t.Fatal("no contracts found")
Expand Down Expand Up @@ -880,7 +893,7 @@ func TestUploadDownloadSpending(t *testing.T) {

// check that the spending was recorded
tt.Retry(100, testBusFlushInterval, func() error {
cms, err := cluster.Bus.Contracts(context.Background())
cms, err := cluster.Bus.Contracts(context.Background(), api.ContractsOpts{})
if err != nil {
t.Fatal(err)
}
Expand Down Expand Up @@ -1301,7 +1314,7 @@ func TestContractArchival(t *testing.T) {
tt := cluster.tt

// check that we have 1 contract
contracts, err := cluster.Bus.Contracts(context.Background())
contracts, err := cluster.Bus.Contracts(context.Background(), api.ContractsOpts{})
tt.OK(err)
if len(contracts) != 1 {
t.Fatal("expected 1 contract", len(contracts))
Expand All @@ -1318,7 +1331,7 @@ func TestContractArchival(t *testing.T) {

// check that we have 0 contracts
tt.Retry(100, 100*time.Millisecond, func() error {
contracts, err := cluster.Bus.Contracts(context.Background())
contracts, err := cluster.Bus.Contracts(context.Background(), api.ContractsOpts{})
if err != nil {
return err
}
Expand Down Expand Up @@ -1346,7 +1359,7 @@ func TestUnconfirmedContractArchival(t *testing.T) {
tt.OK(err)

// we should have a contract with the host
contracts, err := cluster.Bus.Contracts(context.Background())
contracts, err := cluster.Bus.Contracts(context.Background(), api.ContractsOpts{})
tt.OK(err)
if len(contracts) != 1 {
t.Fatalf("expected 1 contract, got %v", len(contracts))
Expand Down Expand Up @@ -1377,7 +1390,7 @@ func TestUnconfirmedContractArchival(t *testing.T) {
tt.OK(err)

// should have 2 contracts now
contracts, err = cluster.Bus.Contracts(context.Background())
contracts, err = cluster.Bus.Contracts(context.Background(), api.ContractsOpts{})
tt.OK(err)
if len(contracts) != 2 {
t.Fatalf("expected 2 contracts, got %v", len(contracts))
Expand All @@ -1388,7 +1401,7 @@ func TestUnconfirmedContractArchival(t *testing.T) {
cluster.MineBlocks(20)

tt.Retry(100, 100*time.Millisecond, func() error {
contracts, err := cluster.Bus.Contracts(context.Background())
contracts, err := cluster.Bus.Contracts(context.Background(), api.ContractsOpts{})
tt.OK(err)
if len(contracts) != 1 {
return fmt.Errorf("expected 1 contract, got %v", len(contracts))
Expand Down Expand Up @@ -2158,7 +2171,7 @@ func TestWalletFormUnconfirmed(t *testing.T) {
}

// There shouldn't be any contracts at this point.
contracts, err := b.Contracts(context.Background())
contracts, err := b.Contracts(context.Background(), api.ContractsOpts{})
tt.OK(err)
if len(contracts) != 0 {
t.Fatal("expected 0 contracts", len(contracts))
Expand Down
2 changes: 1 addition & 1 deletion internal/testing/pruning_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ func TestSectorPruning(t *testing.T) {
cluster.ShutdownAutopilot(context.Background())

// create a contracts dict
contracts, err := b.Contracts(context.Background())
contracts, err := b.Contracts(context.Background(), api.ContractsOpts{})
tt.OK(err)

// compare database against roots returned by the host
Expand Down
2 changes: 1 addition & 1 deletion internal/testing/uploads_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ func TestUploadingSectorsCache(t *testing.T) {
}

// fetch contracts
contracts, err := b.Contracts(context.Background())
contracts, err := b.Contracts(context.Background(), api.ContractsOpts{})
tt.OK(err)

// fetch pending roots for all contracts
Expand Down
Loading