diff --git a/api/contract.go b/api/contract.go index 8342e72b7..3ffd80f5b 100644 --- a/api/contract.go +++ b/api/contract.go @@ -16,6 +16,11 @@ const ( ContractStateFailed = "failed" ) +const ( + ContractUsabilityBad = "bad" + ContractUsabilityGood = "good" +) + const ( ContractArchivalReasonHostPruned = "hostpruned" ContractArchivalReasonRemoved = "removed" @@ -55,6 +60,7 @@ type ( Size uint64 `json:"size"` StartHeight uint64 `json:"startHeight"` State string `json:"state"` + Usability string `json:"usability"` WindowStart uint64 `json:"windowStart"` WindowEnd uint64 `json:"windowEnd"` diff --git a/bus/bus.go b/bus/bus.go index 9c9c67ff4..07bba5db9 100644 --- a/bus/bus.go +++ b/bus/bus.go @@ -543,6 +543,7 @@ func (b *Bus) addContract(ctx context.Context, rev rhpv2.ContractRevision, contr HostKey: rev.HostKey(), StartHeight: startHeight, State: state, + Usability: api.ContractUsabilityGood, WindowStart: rev.Revision.WindowStart, WindowEnd: rev.Revision.WindowEnd, ContractPrice: contractPrice, @@ -575,6 +576,7 @@ func (b *Bus) addRenewal(ctx context.Context, renewedFrom types.FileContractID, RenewedFrom: renewedFrom, StartHeight: startHeight, State: state, + Usability: api.ContractUsabilityGood, WindowStart: rev.Revision.WindowStart, WindowEnd: rev.Revision.WindowEnd, ContractPrice: contractPrice, diff --git a/internal/sql/migrations.go b/internal/sql/migrations.go index cb6b44a44..3915fc1ff 100644 --- a/internal/sql/migrations.go +++ b/internal/sql/migrations.go @@ -302,6 +302,12 @@ var ( return performMigration(ctx, tx, migrationsFs, dbIdentifier, "00019_settings", log) }, }, + { + ID: "00019_scan_reset", + Migrate: func(tx Tx) error { + return performMigration(ctx, tx, migrationsFs, dbIdentifier, "00019_scan_reset", log) + }, + }, // NOTE: duplicate ID (00019) due to updating core deps directly on master { ID: "00020_idx_db_directory", Migrate: func(tx Tx) error { @@ -339,15 +345,15 @@ var ( }, }, { - ID: "00019_scan_reset", + ID: "00026_key_prefix", Migrate: func(tx Tx) error { - return performMigration(ctx, tx, migrationsFs, dbIdentifier, "00019_scan_reset", log) + return performMigration(ctx, tx, migrationsFs, dbIdentifier, "00026_key_prefix", log) }, }, { - ID: "00026_key_prefix", + ID: "00027_contract_usability", Migrate: func(tx Tx) error { - return performMigration(ctx, tx, migrationsFs, dbIdentifier, "00026_key_prefix", log) + return performMigration(ctx, tx, migrationsFs, dbIdentifier, "00027_contract_usability", log) }, }, } diff --git a/internal/test/e2e/cluster_test.go b/internal/test/e2e/cluster_test.go index 76320614b..f56325644 100644 --- a/internal/test/e2e/cluster_test.go +++ b/internal/test/e2e/cluster_test.go @@ -204,6 +204,8 @@ func TestNewTestCluster(t *testing.T) { t.Fatal("wrong endHeight", contract.EndHeight(), revision.EndHeight()) } else if contract.InitialRenterFunds.IsZero() || contract.ContractPrice.IsZero() { t.Fatal("InitialRenterFunds and ContractPrice shouldn't be zero") + } else if contract.Usability != api.ContractUsabilityGood { + t.Fatal("contract should be good") } // Wait for contract set to form @@ -234,6 +236,9 @@ func TestNewTestCluster(t *testing.T) { if contracts[0].State != api.ContractStatePending { return fmt.Errorf("contract should be pending but was %v", contracts[0].State) } + if contracts[0].Usability != api.ContractUsabilityGood { + return fmt.Errorf("contract should be good but was %v", contracts[0].Usability) + } renewalID = contracts[0].ID return nil }) @@ -267,6 +272,9 @@ func TestNewTestCluster(t *testing.T) { if ac.State != api.ContractStateComplete { return fmt.Errorf("contract should be complete but was %v", ac.State) } + if ac.Usability != api.ContractUsabilityBad { + return fmt.Errorf("contract should be bad but was %v", ac.Usability) + } return nil }) @@ -1474,6 +1482,7 @@ func TestUnconfirmedContractArchival(t *testing.T) { HostKey: c.HostKey, StartHeight: cs.BlockHeight, State: api.ContractStatePending, + Usability: api.ContractUsabilityGood, WindowStart: math.MaxUint32, WindowEnd: math.MaxUint32 + 10, ContractPrice: types.NewCurrency64(1), diff --git a/stores/metadata.go b/stores/metadata.go index 33a22e9fb..18123c496 100644 --- a/stores/metadata.go +++ b/stores/metadata.go @@ -125,6 +125,7 @@ func (s *SQLStore) AddRenewal(ctx context.Context, c api.ContractMetadata) error // reinsert renewed contract renewed.ArchivalReason = api.ContractArchivalReasonRenewed renewed.RenewedTo = c.ID + renewed.Usability = api.ContractUsabilityBad return tx.PutContract(ctx, renewed) }) } diff --git a/stores/metadata_test.go b/stores/metadata_test.go index 0f4b8cd83..0a1daf1a9 100644 --- a/stores/metadata_test.go +++ b/stores/metadata_test.go @@ -389,6 +389,7 @@ func TestSQLContractStore(t *testing.T) { Size: 4, StartHeight: 5, State: api.ContractStateActive, + Usability: api.ContractUsabilityGood, WindowStart: 6, WindowEnd: 7, @@ -574,6 +575,7 @@ func TestAncestorsContracts(t *testing.T) { expected := newTestContract(fcids[len(fcids)-2-i], hk) expected.RenewedFrom = renewedFrom expected.RenewedTo = renewedTo + expected.Usability = api.ContractUsabilityBad expected.ArchivalReason = api.ContractArchivalReasonRenewed expected.StartHeight = uint64(len(fcids) - 2 - i) if !reflect.DeepEqual(contracts[i], expected) { @@ -658,6 +660,7 @@ func newTestContract(fcid types.FileContractID, hk types.PublicKey) api.Contract ID: fcid, HostKey: hk, State: api.ContractStatePending, + Usability: api.ContractUsabilityGood, ContractPrice: types.NewCurrency64(1), InitialRenterFunds: types.NewCurrency64(2), } @@ -835,6 +838,7 @@ func TestSQLMetadataStore(t *testing.T) { ID: fcid1, HostKey: hk1, State: api.ContractStatePending, + Usability: api.ContractUsabilityGood, ContractPrice: types.NewCurrency64(1), InitialRenterFunds: types.NewCurrency64(2), } @@ -857,6 +861,7 @@ func TestSQLMetadataStore(t *testing.T) { ID: fcid2, HostKey: hk2, State: api.ContractStatePending, + Usability: api.ContractUsabilityGood, ContractPrice: types.NewCurrency64(1), InitialRenterFunds: types.NewCurrency64(2), } @@ -4783,6 +4788,7 @@ func TestPutContract(t *testing.T) { Size: 6, StartHeight: 7, State: api.ContractStateComplete, + Usability: api.ContractUsabilityGood, WindowStart: 8, WindowEnd: 9, @@ -4822,6 +4828,7 @@ func TestPutContract(t *testing.T) { Size: 21, StartHeight: 22, State: api.ContractStateFailed, + Usability: api.ContractUsabilityGood, WindowStart: 23, WindowEnd: 24, diff --git a/stores/sql/consts.go b/stores/sql/consts.go index 2132dfee5..6ddc9aba6 100644 --- a/stores/sql/consts.go +++ b/stores/sql/consts.go @@ -8,7 +8,8 @@ import ( ) var ( - ErrInvalidContractState = errors.New("invalid contract state") + ErrInvalidContractState = errors.New("invalid contract state") + ErrInvalidContractUsability = errors.New("invalid contract usability") ) type ContractState uint8 @@ -40,8 +41,6 @@ func ContractStateFromString(state string) ContractState { func (s *ContractState) LoadString(state string) error { switch strings.ToLower(state) { - case api.ContractStateInvalid: - *s = contractStateInvalid case api.ContractStatePending: *s = contractStatePending case api.ContractStateActive: @@ -73,3 +72,35 @@ func (s ContractState) String() string { return api.ContractStateUnknown } } + +type ContractUsability uint8 + +const ( + contractUsabilityInvalid ContractUsability = iota + contractUsabilityBad + contractUsabilityGood +) + +func (s *ContractUsability) LoadString(usability string) error { + switch strings.ToLower(usability) { + case api.ContractUsabilityBad: + *s = contractUsabilityBad + case api.ContractUsabilityGood: + *s = contractUsabilityGood + default: + *s = contractUsabilityInvalid + return ErrInvalidContractUsability + } + return nil +} + +func (s ContractUsability) String() string { + switch s { + case contractUsabilityBad: + return api.ContractUsabilityBad + case contractUsabilityGood: + return api.ContractUsabilityGood + default: + return "invalid" + } +} diff --git a/stores/sql/main.go b/stores/sql/main.go index 287920942..a54a52776 100644 --- a/stores/sql/main.go +++ b/stores/sql/main.go @@ -149,7 +149,7 @@ func AncestorContracts(ctx context.Context, tx sql.Tx, fcid types.FileContractID ) SELECT c.fcid, c.host_id, c.host_key, c.v2, - c.archival_reason, c.proof_height, c.renewed_from, c.renewed_to, c.revision_height, c.revision_number, c.size, c.start_height, c.state, c.window_start, c.window_end, + c.archival_reason, c.proof_height, c.renewed_from, c.renewed_to, c.revision_height, c.revision_number, c.size, c.start_height, c.state, c.usability, c.window_start, c.window_end, c.contract_price, c.initial_renter_funds, c.delete_spending, c.fund_account_spending, c.sector_roots_spending, c.upload_spending, "", COALESCE(h.net_address, ""), COALESCE(h.settings->>'$.siamuxport', "") @@ -1916,7 +1916,7 @@ func QueryContracts(ctx context.Context, tx sql.Tx, whereExprs []string, whereAr rows, err := tx.Query(ctx, fmt.Sprintf(` SELECT c.fcid, c.host_id, c.host_key, c.v2, - c.archival_reason, c.proof_height, c.renewed_from, c.renewed_to, c.revision_height, c.revision_number, c.size, c.start_height, c.state, c.window_start, c.window_end, + c.archival_reason, c.proof_height, c.renewed_from, c.renewed_to, c.revision_height, c.revision_number, c.size, c.start_height, c.state, c.usability, c.window_start, c.window_end, c.contract_price, c.initial_renter_funds, c.delete_spending, c.fund_account_spending, c.sector_roots_spending, c.upload_spending, COALESCE(cs.name, ""), COALESCE(h.net_address, ""), COALESCE(h.settings->>'$.siamuxport', "") AS siamux_port @@ -2165,7 +2165,12 @@ func UpdateContract(ctx context.Context, tx sql.Tx, fcid types.FileContractID, c var state ContractState if err := state.LoadString(c.State); err != nil { return err - } else if c.ID == (types.FileContractID{}) { + } + var usability ContractUsability + if err := usability.LoadString(c.Usability); err != nil { + return err + } + if c.ID == (types.FileContractID{}) { return errors.New("contract id is required") } else if c.HostKey == (types.PublicKey{}) { return errors.New("host key is required") @@ -2175,12 +2180,12 @@ func UpdateContract(ctx context.Context, tx sql.Tx, fcid types.FileContractID, c _, err := tx.Exec(ctx, ` UPDATE contracts SET created_at = ?, fcid = ?, - proof_height = ?, renewed_from = ?, revision_height = ?, revision_number = ?, size = ?, start_height = ?, state = ?, window_start = ?, window_end = ?, + proof_height = ?, renewed_from = ?, revision_height = ?, revision_number = ?, size = ?, start_height = ?, state = ?, usability = ?, window_start = ?, window_end = ?, contract_price = ?, initial_renter_funds = ?, delete_spending = ?, fund_account_spending = ?, sector_roots_spending = ?, upload_spending = ? WHERE fcid = ?`, time.Now(), FileContractID(c.ID), - 0, FileContractID(c.RenewedFrom), 0, fmt.Sprint(c.RevisionNumber), c.Size, c.StartHeight, state, c.WindowStart, c.WindowEnd, + 0, FileContractID(c.RenewedFrom), 0, fmt.Sprint(c.RevisionNumber), c.Size, c.StartHeight, state, usability, c.WindowStart, c.WindowEnd, Currency(c.ContractPrice), Currency(c.InitialRenterFunds), ZeroCurrency, ZeroCurrency, ZeroCurrency, ZeroCurrency, FileContractID(c.RenewedFrom), diff --git a/stores/sql/mysql/main.go b/stores/sql/mysql/main.go index b5dec9646..7e7d5e068 100644 --- a/stores/sql/mysql/main.go +++ b/stores/sql/mysql/main.go @@ -733,7 +733,12 @@ func (tx *MainDatabaseTx) PutContract(ctx context.Context, c api.ContractMetadat var state ssql.ContractState if err := state.LoadString(c.State); err != nil { return err - } else if c.ID == (types.FileContractID{}) { + } + var usability ssql.ContractUsability + if err := usability.LoadString(c.Usability); err != nil { + return err + } + if c.ID == (types.FileContractID{}) { return errors.New("contract id is required") } else if c.HostKey == (types.PublicKey{}) { return errors.New("host key is required") @@ -750,17 +755,17 @@ func (tx *MainDatabaseTx) PutContract(ctx context.Context, c api.ContractMetadat _, err = tx.Exec(ctx, ` INSERT INTO contracts ( created_at, fcid, host_id, host_key, v2, - archival_reason, proof_height, renewed_from, renewed_to, revision_height, revision_number, size, start_height, state, window_start, window_end, + archival_reason, proof_height, renewed_from, renewed_to, revision_height, revision_number, size, start_height, state, usability, window_start, window_end, contract_price, initial_renter_funds, delete_spending, fund_account_spending, sector_roots_spending, upload_spending -) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) +) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ON DUPLICATE KEY UPDATE created_at = VALUES(created_at), fcid = VALUES(fcid), host_id = VALUES(host_id), host_key = VALUES(host_key), v2 = VALUES(v2), - archival_reason = VALUES(archival_reason), proof_height = VALUES(proof_height), renewed_from = VALUES(renewed_from), renewed_to = VALUES(renewed_to), revision_height = VALUES(revision_height), revision_number = VALUES(revision_number), size = VALUES(size), start_height = VALUES(start_height), state = VALUES(state), window_start = VALUES(window_start), window_end = VALUES(window_end), + archival_reason = VALUES(archival_reason), proof_height = VALUES(proof_height), renewed_from = VALUES(renewed_from), renewed_to = VALUES(renewed_to), revision_height = VALUES(revision_height), revision_number = VALUES(revision_number), size = VALUES(size), start_height = VALUES(start_height), state = VALUES(state), usability = VALUES(usability), window_start = VALUES(window_start), window_end = VALUES(window_end), contract_price = VALUES(contract_price), initial_renter_funds = VALUES(initial_renter_funds), delete_spending = VALUES(delete_spending), fund_account_spending = VALUES(fund_account_spending), sector_roots_spending = VALUES(sector_roots_spending), upload_spending = VALUES(upload_spending)`, time.Now(), ssql.FileContractID(c.ID), hostID, ssql.PublicKey(c.HostKey), c.V2, - ssql.NullableString(c.ArchivalReason), c.ProofHeight, ssql.FileContractID(c.RenewedFrom), ssql.FileContractID(c.RenewedTo), c.RevisionHeight, c.RevisionNumber, c.Size, c.StartHeight, state, c.WindowStart, c.WindowEnd, + ssql.NullableString(c.ArchivalReason), c.ProofHeight, ssql.FileContractID(c.RenewedFrom), ssql.FileContractID(c.RenewedTo), c.RevisionHeight, c.RevisionNumber, c.Size, c.StartHeight, state, usability, c.WindowStart, c.WindowEnd, ssql.Currency(c.ContractPrice), ssql.Currency(c.InitialRenterFunds), ssql.Currency(c.Spending.Deletions), ssql.Currency(c.Spending.FundAccount), ssql.Currency(c.Spending.SectorRoots), ssql.Currency(c.Spending.Uploads), ) diff --git a/stores/sql/mysql/migrations/main/migration_00027_contract_usability.sql b/stores/sql/mysql/migrations/main/migration_00027_contract_usability.sql new file mode 100644 index 000000000..b32377335 --- /dev/null +++ b/stores/sql/mysql/migrations/main/migration_00027_contract_usability.sql @@ -0,0 +1,4 @@ +ALTER TABLE contracts ADD COLUMN usability tinyint unsigned; +CREATE INDEX `idx_contracts_usability` ON contracts (`usability`); +UPDATE contracts SET usability = CASE WHEN archival_reason IS NULL THEN 2 ELSE 1 END; +ALTER TABLE contracts MODIFY COLUMN usability tinyint unsigned NOT NULL; \ No newline at end of file diff --git a/stores/sql/mysql/migrations/main/schema.sql b/stores/sql/mysql/migrations/main/schema.sql index f540138ce..5230e0ba1 100644 --- a/stores/sql/mysql/migrations/main/schema.sql +++ b/stores/sql/mysql/migrations/main/schema.sql @@ -88,6 +88,7 @@ CREATE TABLE `contracts` ( `size` bigint unsigned DEFAULT NULL, `start_height` bigint unsigned NOT NULL, `state` tinyint unsigned NOT NULL DEFAULT '0', + `usability` tinyint unsigned NOT NULL, `window_start` bigint unsigned NOT NULL DEFAULT '0', `window_end` bigint unsigned NOT NULL DEFAULT '0', @@ -110,6 +111,7 @@ CREATE TABLE `contracts` ( KEY `idx_contracts_revision_height` (`revision_height`), KEY `idx_contracts_start_height` (`start_height`), KEY `idx_contracts_state` (`state`), + KEY `idx_contracts_usability` (`usability`), KEY `idx_contracts_window_start` (`window_start`), KEY `idx_contracts_window_end` (`window_end`), CONSTRAINT `fk_contracts_host` FOREIGN KEY (`host_id`) REFERENCES `hosts` (`id`) diff --git a/stores/sql/rows.go b/stores/sql/rows.go index 2f95eaac8..a3c7f535c 100644 --- a/stores/sql/rows.go +++ b/stores/sql/rows.go @@ -26,6 +26,7 @@ type ContractRow struct { Size uint64 StartHeight uint64 State ContractState + Usability ContractUsability WindowStart uint64 WindowEnd uint64 @@ -48,7 +49,7 @@ type ContractRow struct { func (r *ContractRow) Scan(s Scanner) error { return s.Scan( &r.FCID, &r.HostID, &r.HostKey, &r.V2, - &r.ArchivalReason, &r.ProofHeight, &r.RenewedFrom, &r.RenewedTo, &r.RevisionHeight, &r.RevisionNumber, &r.Size, &r.StartHeight, &r.State, &r.WindowStart, &r.WindowEnd, + &r.ArchivalReason, &r.ProofHeight, &r.RenewedFrom, &r.RenewedTo, &r.RevisionHeight, &r.RevisionNumber, &r.Size, &r.StartHeight, &r.State, &r.Usability, &r.WindowStart, &r.WindowEnd, &r.ContractPrice, &r.InitialRenterFunds, &r.DeleteSpending, &r.FundAccountSpending, &r.SectorRootsSpending, &r.UploadSpending, &r.ContractSet, &r.NetAddress, &r.SiamuxPort, @@ -97,6 +98,7 @@ func (r *ContractRow) ContractMetadata() api.ContractMetadata { Spending: spending, StartHeight: r.StartHeight, State: r.State.String(), + Usability: r.Usability.String(), WindowStart: r.WindowStart, WindowEnd: r.WindowEnd, } diff --git a/stores/sql/sqlite/main.go b/stores/sql/sqlite/main.go index 44215e18b..3bf55f0ed 100644 --- a/stores/sql/sqlite/main.go +++ b/stores/sql/sqlite/main.go @@ -743,7 +743,12 @@ func (tx *MainDatabaseTx) PutContract(ctx context.Context, c api.ContractMetadat var state ssql.ContractState if err := state.LoadString(c.State); err != nil { return err - } else if c.ID == (types.FileContractID{}) { + } + var usability ssql.ContractUsability + if err := usability.LoadString(c.Usability); err != nil { + return err + } + if c.ID == (types.FileContractID{}) { return errors.New("contract id is required") } else if c.HostKey == (types.PublicKey{}) { return errors.New("host key is required") @@ -760,17 +765,17 @@ func (tx *MainDatabaseTx) PutContract(ctx context.Context, c api.ContractMetadat _, err = tx.Exec(ctx, ` INSERT INTO contracts ( created_at, fcid, host_id, host_key, v2, - archival_reason, proof_height, renewed_from, renewed_to, revision_height, revision_number, size, start_height, state, window_start, window_end, + archival_reason, proof_height, renewed_from, renewed_to, revision_height, revision_number, size, start_height, state, usability, window_start, window_end, contract_price, initial_renter_funds, delete_spending, fund_account_spending, sector_roots_spending, upload_spending -) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) +) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ON CONFLICT(fcid) DO UPDATE SET fcid = EXCLUDED.fcid, host_id = EXCLUDED.host_id, host_key = EXCLUDED.host_key, v2 = EXCLUDED.v2, - archival_reason = EXCLUDED.archival_reason, proof_height = EXCLUDED.proof_height, renewed_from = EXCLUDED.renewed_from, renewed_to = EXCLUDED.renewed_to, revision_height = EXCLUDED.revision_height, revision_number = EXCLUDED.revision_number, size = EXCLUDED.size, start_height = EXCLUDED.start_height, state = EXCLUDED.state, window_start = EXCLUDED.window_start, window_end = EXCLUDED.window_end, + archival_reason = EXCLUDED.archival_reason, proof_height = EXCLUDED.proof_height, renewed_from = EXCLUDED.renewed_from, renewed_to = EXCLUDED.renewed_to, revision_height = EXCLUDED.revision_height, revision_number = EXCLUDED.revision_number, size = EXCLUDED.size, start_height = EXCLUDED.start_height, state = EXCLUDED.state, usability = EXCLUDED.usability, window_start = EXCLUDED.window_start, window_end = EXCLUDED.window_end, contract_price = EXCLUDED.contract_price, initial_renter_funds = EXCLUDED.initial_renter_funds, delete_spending = EXCLUDED.delete_spending, fund_account_spending = EXCLUDED.fund_account_spending, sector_roots_spending = EXCLUDED.sector_roots_spending, upload_spending = EXCLUDED.upload_spending`, time.Now(), ssql.FileContractID(c.ID), hostID, ssql.PublicKey(c.HostKey), c.V2, - ssql.NullableString(c.ArchivalReason), c.ProofHeight, ssql.FileContractID(c.RenewedFrom), ssql.FileContractID(c.RenewedTo), c.RevisionHeight, c.RevisionNumber, c.Size, c.StartHeight, state, c.WindowStart, c.WindowEnd, + ssql.NullableString(c.ArchivalReason), c.ProofHeight, ssql.FileContractID(c.RenewedFrom), ssql.FileContractID(c.RenewedTo), c.RevisionHeight, c.RevisionNumber, c.Size, c.StartHeight, state, usability, c.WindowStart, c.WindowEnd, ssql.Currency(c.ContractPrice), ssql.Currency(c.InitialRenterFunds), ssql.Currency(c.Spending.Deletions), ssql.Currency(c.Spending.FundAccount), ssql.Currency(c.Spending.SectorRoots), ssql.Currency(c.Spending.Uploads), ) diff --git a/stores/sql/sqlite/migrations/main/migration_00027_contract_usability.sql b/stores/sql/sqlite/migrations/main/migration_00027_contract_usability.sql new file mode 100644 index 000000000..35d01cbe8 --- /dev/null +++ b/stores/sql/sqlite/migrations/main/migration_00027_contract_usability.sql @@ -0,0 +1,115 @@ +-- create a temporary table that adds the usability column +DROP TABLE IF EXISTS contracts_temp; +CREATE TABLE contracts_temp ( + `id` integer PRIMARY KEY AUTOINCREMENT, + `created_at` datetime, + `fcid` blob NOT NULL UNIQUE, + `host_id` integer, + `host_key` blob NOT NULL, + + `v2` INTEGER NOT NULL, + `archival_reason` text DEFAULT NULL, + `proof_height` integer DEFAULT 0, + `renewed_from` blob, + `renewed_to` blob, + `revision_height` integer DEFAULT 0, + `revision_number` text NOT NULL DEFAULT "0", + `size` integer, + `start_height` integer NOT NULL, + `state` integer NOT NULL DEFAULT 0, + `usability` integer NOT NULL, + `window_start` integer NOT NULL DEFAULT 0, + `window_end` integer NOT NULL DEFAULT 0, + + `contract_price` text, + `initial_renter_funds` text, + + `delete_spending` text, + `fund_account_spending` text, + `sector_roots_spending` text, + `upload_spending` text, + + CONSTRAINT `fk_contracts_host` FOREIGN KEY (`host_id`) REFERENCES `hosts`(`id`) +); + +DROP INDEX IF EXISTS `idx_contracts_archival_reason`; +DROP INDEX IF EXISTS `idx_contracts_fcid`; +DROP INDEX IF EXISTS `idx_contracts_host_id`; +DROP INDEX IF EXISTS `idx_contracts_host_key`; +DROP INDEX IF EXISTS `idx_contracts_proof_height`; +DROP INDEX IF EXISTS `idx_contracts_renewed_from`; +DROP INDEX IF EXISTS `idx_contracts_renewed_to`; +DROP INDEX IF EXISTS `idx_contracts_revision_height`; +DROP INDEX IF EXISTS `idx_contracts_start_height`; +DROP INDEX IF EXISTS `idx_contracts_state`; +DROP INDEX IF EXISTS `idx_contracts_window_end`; +DROP INDEX IF EXISTS `idx_contracts_window_start`; + +CREATE INDEX `idx_contracts_archival_reason` ON `contracts_temp`(`archival_reason`); +CREATE INDEX `idx_contracts_fcid` ON `contracts_temp`(`fcid`); +CREATE INDEX `idx_contracts_host_id` ON `contracts_temp`(`host_id`); +CREATE INDEX `idx_contracts_host_key` ON `contracts_temp`(`host_key`); +CREATE INDEX `idx_contracts_proof_height` ON `contracts_temp`(`proof_height`); +CREATE INDEX `idx_contracts_renewed_from` ON `contracts_temp`(`renewed_from`); +CREATE INDEX `idx_contracts_renewed_to` ON `contracts_temp`(`renewed_to`); +CREATE INDEX `idx_contracts_revision_height` ON `contracts_temp`(`revision_height`); +CREATE INDEX `idx_contracts_start_height` ON `contracts_temp`(`start_height`); +CREATE INDEX `idx_contracts_state` ON `contracts_temp`(`state`); +CREATE INDEX `idx_contracts_usability` ON `contracts_temp`(`usability`); +CREATE INDEX `idx_contracts_window_end` ON `contracts_temp`(`window_end`); +CREATE INDEX `idx_contracts_window_start` ON `contracts_temp`(`window_start`); + +INSERT INTO contracts_temp ( + id, + created_at, + fcid, + host_id, + host_key, + v2, + archival_reason, + proof_height, + renewed_from, + renewed_to, + revision_height, + revision_number, + size, + start_height, + state, + usability, + window_start, + window_end, + contract_price, + initial_renter_funds, + delete_spending, + fund_account_spending, + sector_roots_spending, + upload_spending +) SELECT + c.id, + c.created_at, + c.fcid, + c.host_id, + c.host_key, + c.v2, + c.archival_reason, + c.proof_height, + c.renewed_from, + c.renewed_to, + c.revision_height, + c.revision_number, + c.size, + c.start_height, + c.state, + CASE WHEN archival_reason IS NULL THEN 2 ELSE 1 END, + c.window_start, + c.window_end, + c.contract_price, + c.initial_renter_funds, + c.delete_spending, + c.fund_account_spending, + c.sector_roots_spending, + c.upload_spending +FROM contracts c; + +DROP TABLE `contracts`; +ALTER TABLE contracts_temp RENAME TO contracts; \ No newline at end of file diff --git a/stores/sql/sqlite/migrations/main/schema.sql b/stores/sql/sqlite/migrations/main/schema.sql index 04939856a..bcafefb0a 100644 --- a/stores/sql/sqlite/migrations/main/schema.sql +++ b/stores/sql/sqlite/migrations/main/schema.sql @@ -8,7 +8,7 @@ CREATE INDEX `idx_hosts_public_key` ON `hosts`(`public_key`); CREATE INDEX `idx_hosts_net_address` ON `hosts`(`net_address`); -- dbContract -CREATE TABLE contracts (`id` integer PRIMARY KEY AUTOINCREMENT, `created_at` datetime, `fcid` blob NOT NULL UNIQUE, `host_id` integer, `host_key` blob NOT NULL,`v2` INTEGER NOT NULL, `archival_reason` text DEFAULT NULL, `proof_height` integer DEFAULT 0, `renewed_from` blob, `renewed_to` blob, `revision_height` integer DEFAULT 0, `revision_number` text NOT NULL DEFAULT "0", `size` integer, `start_height` integer NOT NULL, `state` integer NOT NULL DEFAULT 0, `window_start` integer NOT NULL DEFAULT 0, `window_end` integer NOT NULL DEFAULT 0, `contract_price` text, `initial_renter_funds` text, `delete_spending` text, `fund_account_spending` text, `sector_roots_spending` text, `upload_spending` text, CONSTRAINT `fk_contracts_host` FOREIGN KEY (`host_id`) REFERENCES `hosts`(`id`)); +CREATE TABLE contracts (`id` integer PRIMARY KEY AUTOINCREMENT, `created_at` datetime, `fcid` blob NOT NULL UNIQUE, `host_id` integer, `host_key` blob NOT NULL,`v2` INTEGER NOT NULL, `archival_reason` text DEFAULT NULL, `proof_height` integer DEFAULT 0, `renewed_from` blob, `renewed_to` blob, `revision_height` integer DEFAULT 0, `revision_number` text NOT NULL DEFAULT "0", `size` integer, `start_height` integer NOT NULL, `state` integer NOT NULL DEFAULT 0, `usability` integer NOT NULL, `window_start` integer NOT NULL DEFAULT 0, `window_end` integer NOT NULL DEFAULT 0, `contract_price` text, `initial_renter_funds` text, `delete_spending` text, `fund_account_spending` text, `sector_roots_spending` text, `upload_spending` text, CONSTRAINT `fk_contracts_host` FOREIGN KEY (`host_id`) REFERENCES `hosts`(`id`)); CREATE INDEX `idx_contracts_archival_reason` ON `contracts`(`archival_reason`); CREATE INDEX `idx_contracts_fcid` ON `contracts`(`fcid`); CREATE INDEX `idx_contracts_host_id` ON `contracts`(`host_id`); @@ -19,6 +19,7 @@ CREATE INDEX `idx_contracts_renewed_to` ON `contracts`(`renewed_to`); CREATE INDEX `idx_contracts_revision_height` ON `contracts`(`revision_height`); CREATE INDEX `idx_contracts_start_height` ON `contracts`(`start_height`); CREATE INDEX `idx_contracts_state` ON `contracts`(`state`); +CREATE INDEX `idx_contracts_usability` ON `contracts`(`usability`); CREATE INDEX `idx_contracts_window_end` ON `contracts`(`window_end`); CREATE INDEX `idx_contracts_window_start` ON `contracts`(`window_start`);