2019-02-14 21:55:21 +00:00
// Copyright (C) 2019 Storj Labs, Inc.
// See LICENSE for copying information.
package satellitedb
import (
2019-12-05 20:42:12 +00:00
"fmt"
"github.com/lib/pq"
2019-02-14 21:55:21 +00:00
"github.com/zeebo/errs"
2019-12-05 20:42:12 +00:00
"storj.io/storj/private/dbutil"
2019-11-14 19:46:15 +00:00
"storj.io/storj/private/dbutil/pgutil"
"storj.io/storj/private/migrate"
2019-02-14 21:55:21 +00:00
)
2019-07-23 18:58:43 +01:00
var (
// ErrMigrate is for tracking migration errors
ErrMigrate = errs . Class ( "migrate" )
2019-11-19 20:52:57 +00:00
// ErrMigrateMinVersion is for migration min version errors
ErrMigrateMinVersion = errs . Class ( "migrate min version" )
2019-07-23 18:58:43 +01:00
)
2019-02-14 21:55:21 +00:00
// CreateTables is a method for creating all tables for database
func ( db * DB ) CreateTables ( ) error {
2019-12-05 20:42:12 +00:00
// First handle the idiosyncrasies of postgres and cockroach migrations. Postgres
// will need to create any schemas specified in the search path, and cockroach
// will need to create the database it was told to connect to. These things should
// not really be here, and instead should be assumed to exist.
// This is tracked in jira ticket #3338.
switch db . implementation {
case dbutil . Postgres :
2019-05-14 16:13:18 +01:00
schema , err := pgutil . ParseSchemaFromConnstr ( db . source )
if err != nil {
return errs . New ( "error parsing schema: %+v" , err )
}
2019-11-22 19:59:46 +00:00
2019-05-14 16:13:18 +01:00
if schema != "" {
2019-12-04 03:36:21 +00:00
err = pgutil . CreateSchema ( db . db , schema )
2019-05-14 16:13:18 +01:00
if err != nil {
return errs . New ( "error creating schema: %+v" , err )
}
}
2019-12-05 20:42:12 +00:00
case dbutil . Cockroach :
var dbName string
if err := db . db . QueryRow ( ` SELECT current_database(); ` ) . Scan ( & dbName ) ; err != nil {
return errs . New ( "error querying current database: %+v" , err )
}
_ , err := db . db . Exec ( fmt . Sprintf ( ` CREATE DATABASE IF NOT EXISTS %s; ` ,
pq . QuoteIdentifier ( dbName ) ) )
if err != nil {
return errs . Wrap ( err )
}
}
switch db . implementation {
case dbutil . Postgres , dbutil . Cockroach :
2019-02-14 21:55:21 +00:00
migration := db . PostgresMigration ( )
2019-11-22 19:59:46 +00:00
// since we merged migration steps 0-69, the current db version should never be
// less than 69 unless the migration hasn't run yet
const minDBVersion = 69
2019-11-19 20:52:57 +00:00
dbVersion , err := migration . CurrentVersion ( db . log , db . db )
if err != nil {
return errs . New ( "error current version: %+v" , err )
}
if dbVersion > - 1 && dbVersion < minDBVersion {
return ErrMigrateMinVersion . New ( "current database version is %d, it shouldn't be less than the min version %d" ,
dbVersion , minDBVersion ,
)
}
2019-09-10 20:42:23 +01:00
return migration . Run ( db . log . Named ( "migrate" ) )
2019-12-05 20:42:12 +00:00
2019-02-14 21:55:21 +00:00
default :
return migrate . Create ( "database" , db . db )
}
}
2019-11-19 20:52:57 +00:00
// CheckVersion confirms the database is at the desired version
2019-11-02 20:09:07 +00:00
func ( db * DB ) CheckVersion ( ) error {
2019-12-05 20:42:12 +00:00
switch db . implementation {
case dbutil . Postgres , dbutil . Cockroach :
2019-11-02 20:09:07 +00:00
migration := db . PostgresMigration ( )
return migration . ValidateVersions ( db . log )
2019-12-05 20:42:12 +00:00
2019-11-02 20:09:07 +00:00
default :
return nil
}
}
2019-02-14 21:55:21 +00:00
// PostgresMigration returns steps needed for migrating postgres database.
func ( db * DB ) PostgresMigration ( ) * migrate . Migration {
return & migrate . Migration {
Table : "versions" ,
Steps : [ ] * migrate . Step {
{
2019-09-10 20:42:23 +01:00
DB : db . db ,
2019-02-14 21:55:21 +00:00
Description : "Initial setup" ,
2019-11-22 19:59:46 +00:00
Version : 69 ,
2019-02-14 21:55:21 +00:00
Action : migrate . SQL {
2019-11-19 20:52:57 +00:00
` CREATE TABLE accounting_rollups (
2019-02-14 21:55:21 +00:00
id bigserial NOT NULL ,
node_id bytea NOT NULL ,
start_time timestamp with time zone NOT NULL ,
put_total bigint NOT NULL ,
get_total bigint NOT NULL ,
get_audit_total bigint NOT NULL ,
get_repair_total bigint NOT NULL ,
put_repair_total bigint NOT NULL ,
at_rest_total double precision NOT NULL ,
PRIMARY KEY ( id )
2019-11-19 20:52:57 +00:00
) ; ` ,
` CREATE TABLE accounting_timestamps (
2019-02-14 21:55:21 +00:00
name text NOT NULL ,
value timestamp with time zone NOT NULL ,
PRIMARY KEY ( name )
2019-11-19 20:52:57 +00:00
) ; ` ,
` CREATE TABLE bucket_bandwidth_rollups (
bucket_name bytea NOT NULL ,
interval_start timestamp NOT NULL ,
interval_seconds integer NOT NULL ,
action integer NOT NULL ,
inline bigint NOT NULL ,
allocated bigint NOT NULL ,
settled bigint NOT NULL ,
project_id bytea NOT NULL ,
CONSTRAINT bucket_bandwidth_rollups_pk PRIMARY KEY ( bucket_name , project_id , interval_start , action )
) ; ` ,
` CREATE INDEX bucket_name_project_id_interval_start_interval_seconds ON bucket_bandwidth_rollups ( bucket_name, project_id, interval_start, interval_seconds ); ` ,
` CREATE TABLE bucket_storage_tallies (
bucket_name bytea NOT NULL ,
interval_start timestamp NOT NULL ,
inline bigint NOT NULL ,
remote bigint NOT NULL ,
remote_segments_count integer NOT NULL ,
inline_segments_count integer NOT NULL ,
object_count integer NOT NULL ,
metadata_size bigint NOT NULL ,
project_id bytea NOT NULL ,
CONSTRAINT bucket_storage_tallies_pk PRIMARY KEY ( bucket_name , project_id , interval_start )
) ; ` ,
` CREATE TABLE injuredsegments (
2019-02-14 21:55:21 +00:00
data bytea NOT NULL ,
2019-11-19 20:52:57 +00:00
attempted timestamp ,
path bytea NOT NULL ,
CONSTRAINT injuredsegments_pk PRIMARY KEY ( path )
) ; ` ,
` CREATE INDEX injuredsegments_attempted_index ON injuredsegments ( attempted ); ` ,
` CREATE TABLE irreparabledbs (
2019-02-14 21:55:21 +00:00
segmentpath bytea NOT NULL ,
segmentdetail bytea NOT NULL ,
pieces_lost_count bigint NOT NULL ,
seg_damaged_unix_sec bigint NOT NULL ,
repair_attempt_count bigint NOT NULL ,
PRIMARY KEY ( segmentpath )
2019-11-19 20:52:57 +00:00
) ; ` ,
` CREATE TABLE nodes (
2019-02-14 21:55:21 +00:00
id bytea NOT NULL ,
2019-11-19 20:52:57 +00:00
audit_success_count bigint NOT NULL DEFAULT 0 ,
total_audit_count bigint NOT NULL DEFAULT 0 ,
2019-02-14 21:55:21 +00:00
uptime_success_count bigint NOT NULL ,
total_uptime_count bigint NOT NULL ,
2019-11-19 20:52:57 +00:00
created_at timestamp with time zone NOT NULL DEFAULT current_timestamp ,
updated_at timestamp with time zone NOT NULL DEFAULT current_timestamp ,
wallet text NOT NULL ,
email text NOT NULL ,
address text NOT NULL DEFAULT ' ' ,
protocol INTEGER NOT NULL DEFAULT 0 ,
type INTEGER NOT NULL DEFAULT 0 ,
free_bandwidth BIGINT NOT NULL DEFAULT - 1 ,
free_disk BIGINT NOT NULL DEFAULT - 1 ,
latency_90 BIGINT NOT NULL DEFAULT 0 ,
last_contact_success TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT ' epoch ' ,
last_contact_failure TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT ' epoch ' ,
major bigint NOT NULL DEFAULT 0 ,
minor bigint NOT NULL DEFAULT 0 ,
patch bigint NOT NULL DEFAULT 0 ,
hash TEXT NOT NULL DEFAULT ' ' ,
timestamp TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT ' 0001 - 01 - 01 00 : 00 : 00 + 00 ' ,
release bool NOT NULL DEFAULT FALSE ,
contained bool NOT NULL DEFAULT FALSE ,
last_net text NOT NULL ,
disqualified timestamp with time zone ,
audit_reputation_alpha double precision NOT NULL DEFAULT 1 ,
audit_reputation_beta double precision NOT NULL DEFAULT 0 ,
uptime_reputation_alpha double precision NOT NULL DEFAULT 1 ,
uptime_reputation_beta double precision NOT NULL DEFAULT 0 ,
piece_count bigint NOT NULL DEFAULT 0 ,
exit_loop_completed_at TIMESTAMP ,
exit_initiated_at TIMESTAMP ,
exit_finished_at TIMESTAMP ,
exit_success boolean NOT NULL DEFAULT FALSE ,
2019-02-14 21:55:21 +00:00
PRIMARY KEY ( id )
2019-11-19 20:52:57 +00:00
) ; ` ,
` CREATE INDEX node_last_ip ON nodes ( last_net ); ` ,
` CREATE TABLE offers (
id serial NOT NULL ,
2019-02-14 21:55:21 +00:00
name text NOT NULL ,
description text NOT NULL ,
2019-11-19 20:52:57 +00:00
type integer NOT NULL ,
award_credit_duration_days integer ,
invitee_credit_duration_days integer ,
redeemable_cap integer ,
expires_at timestamp with time zone NOT NULL ,
2019-02-14 21:55:21 +00:00
created_at timestamp with time zone NOT NULL ,
status integer NOT NULL ,
2019-11-19 20:52:57 +00:00
award_credit_in_cents integer NOT NULL DEFAULT 0 ,
invitee_credit_in_cents integer NOT NULL DEFAULT 0 ,
2019-02-14 21:55:21 +00:00
PRIMARY KEY ( id )
2019-11-19 20:52:57 +00:00
) ; ` ,
2019-02-14 21:55:21 +00:00
2019-11-19 20:52:57 +00:00
` CREATE TABLE peer_identities (
node_id bytea NOT NULL ,
leaf_serial_number bytea NOT NULL ,
chain bytea NOT NULL ,
updated_at timestamp with time zone NOT NULL ,
PRIMARY KEY ( node_id )
) ; ` ,
2019-02-14 21:55:21 +00:00
2019-11-19 20:52:57 +00:00
` CREATE TABLE pending_audits (
node_id bytea NOT NULL ,
piece_id bytea NOT NULL ,
stripe_index bigint NOT NULL ,
share_size bigint NOT NULL ,
expected_share_hash bytea NOT NULL ,
reverify_count bigint NOT NULL ,
path bytea NOT NULL ,
PRIMARY KEY ( node_id )
) ; ` ,
2019-02-14 21:55:21 +00:00
2019-11-19 20:52:57 +00:00
` CREATE TABLE projects (
2019-02-14 21:55:21 +00:00
id bytea NOT NULL ,
2019-11-19 20:52:57 +00:00
name text NOT NULL ,
description text NOT NULL ,
created_at timestamp with time zone NOT NULL ,
usage_limit bigint NOT NULL DEFAULT 0 ,
partner_id bytea ,
owner_id bytea NOT NULL ,
2019-02-14 21:55:21 +00:00
PRIMARY KEY ( id )
2019-11-19 20:52:57 +00:00
) ; ` ,
2019-02-14 21:55:21 +00:00
2019-11-19 20:52:57 +00:00
` CREATE TABLE registration_tokens (
secret bytea NOT NULL ,
owner_id bytea UNIQUE ,
project_limit integer NOT NULL ,
created_at timestamp with time zone NOT NULL ,
PRIMARY KEY ( secret )
) ; ` ,
2019-02-14 21:55:21 +00:00
2019-11-19 20:52:57 +00:00
` CREATE TABLE reset_password_tokens (
secret bytea NOT NULL ,
owner_id bytea NOT NULL UNIQUE ,
created_at timestamp with time zone NOT NULL ,
PRIMARY KEY ( secret )
) ; ` ,
2019-02-14 21:55:21 +00:00
2019-03-22 18:54:22 +00:00
` CREATE TABLE serial_numbers (
id serial NOT NULL ,
serial_number bytea NOT NULL ,
bucket_id bytea NOT NULL ,
expires_at timestamp NOT NULL ,
2019-03-26 10:34:30 +00:00
PRIMARY KEY ( id )
2019-11-19 20:52:57 +00:00
) ; ` ,
` CREATE INDEX serial_numbers_expires_at_index ON serial_numbers ( expires_at ); ` ,
2019-03-26 10:34:30 +00:00
` CREATE UNIQUE INDEX serial_number_index ON serial_numbers ( serial_number ) ` ,
2019-11-19 20:52:57 +00:00
2019-03-22 18:54:22 +00:00
` CREATE TABLE storagenode_bandwidth_rollups (
storagenode_id bytea NOT NULL ,
interval_start timestamp NOT NULL ,
interval_seconds integer NOT NULL ,
action integer NOT NULL ,
allocated bigint NOT NULL ,
settled bigint NOT NULL ,
2019-03-26 10:34:30 +00:00
PRIMARY KEY ( storagenode_id , interval_start , action )
2019-05-13 16:53:52 +01:00
) ; ` ,
2019-11-19 20:52:57 +00:00
` CREATE INDEX storagenode_id_interval_start_interval_seconds_index ON storagenode_bandwidth_rollups ( storagenode_id, interval_start, interval_seconds ); ` ,
2019-05-16 15:11:15 +01:00
2019-11-19 20:52:57 +00:00
` CREATE TABLE accounting_raws (
id bigserial NOT NULL ,
2019-05-16 15:11:15 +01:00
node_id bytea NOT NULL ,
2019-11-19 20:52:57 +00:00
interval_end_time timestamp with time zone NOT NULL ,
data_total double precision NOT NULL ,
PRIMARY KEY ( id )
) ` ,
` ALTER TABLE accounting_raws RENAME TO storagenode_storage_tallies ` ,
` CREATE TABLE users (
id bytea NOT NULL ,
full_name text NOT NULL ,
short_name text ,
email text NOT NULL ,
password_hash bytea NOT NULL ,
status integer NOT NULL ,
2019-06-13 14:52:33 +01:00
created_at timestamp with time zone NOT NULL ,
2019-11-19 20:52:57 +00:00
partner_id bytea ,
normalized_email text NOT NULL ,
2019-06-13 14:52:33 +01:00
PRIMARY KEY ( id )
) ; ` ,
2019-11-19 20:52:57 +00:00
` CREATE TABLE value_attributions (
bucket_name bytea NOT NULL ,
partner_id bytea NOT NULL ,
last_updated timestamp NOT NULL ,
project_id bytea NOT NULL ,
PRIMARY KEY ( project_id , bucket_name )
) ; ` ,
` CREATE TABLE api_keys (
id bytea NOT NULL ,
project_id bytea NOT NULL REFERENCES projects ( id ) ON DELETE CASCADE ,
head bytea NOT NULL UNIQUE ,
name text NOT NULL ,
secret bytea NOT NULL ,
created_at timestamp with time zone NOT NULL ,
partner_id bytea ,
PRIMARY KEY ( id ) ,
UNIQUE ( name , project_id )
) ; ` ,
2019-07-03 23:03:56 +01:00
` CREATE TABLE bucket_metainfos (
2019-07-01 21:45:21 +01:00
id bytea NOT NULL ,
project_id bytea NOT NULL REFERENCES projects ( id ) ,
name bytea NOT NULL ,
path_cipher integer NOT NULL ,
2019-07-03 23:03:56 +01:00
created_at timestamp with time zone NOT NULL ,
2019-07-01 21:45:21 +01:00
default_segment_size integer NOT NULL ,
default_encryption_cipher_suite integer NOT NULL ,
default_encryption_block_size integer NOT NULL ,
default_redundancy_algorithm integer NOT NULL ,
default_redundancy_share_size integer NOT NULL ,
default_redundancy_required_shares integer NOT NULL ,
default_redundancy_repair_shares integer NOT NULL ,
default_redundancy_optimal_shares integer NOT NULL ,
default_redundancy_total_shares integer NOT NULL ,
2019-11-19 20:52:57 +00:00
partner_id bytea ,
2019-07-01 21:45:21 +01:00
PRIMARY KEY ( id ) ,
UNIQUE ( name , project_id )
) ; ` ,
2019-11-19 20:52:57 +00:00
` CREATE TABLE project_invoice_stamps (
project_id bytea NOT NULL REFERENCES projects ( id ) ON DELETE CASCADE ,
invoice_id bytea NOT NULL UNIQUE ,
start_date timestamp with time zone NOT NULL ,
end_date timestamp with time zone NOT NULL ,
created_at timestamp with time zone NOT NULL ,
PRIMARY KEY ( project_id , start_date , end_date )
) ; ` ,
` CREATE TABLE project_members (
member_id bytea NOT NULL REFERENCES users ( id ) ON DELETE CASCADE ,
2019-07-10 21:29:26 +01:00
project_id bytea NOT NULL REFERENCES projects ( id ) ON DELETE CASCADE ,
created_at timestamp with time zone NOT NULL ,
2019-11-19 20:52:57 +00:00
PRIMARY KEY ( member_id , project_id )
) ; ` ,
` CREATE TABLE used_serials (
serial_number_id integer NOT NULL REFERENCES serial_numbers ( id ) ON DELETE CASCADE ,
storage_node_id bytea NOT NULL ,
PRIMARY KEY ( serial_number_id , storage_node_id )
) ; ` ,
` CREATE TABLE user_credits (
id serial NOT NULL ,
user_id bytea NOT NULL REFERENCES users ( id ) ON DELETE CASCADE ,
offer_id integer NOT NULL REFERENCES offers ( id ) ,
referred_by bytea REFERENCES users ( id ) ON DELETE SET NULL ,
credits_earned_in_cents integer NOT NULL ,
credits_used_in_cents integer NOT NULL ,
expires_at timestamp with time zone NOT NULL ,
created_at timestamp with time zone NOT NULL ,
type text NOT NULL ,
2019-07-10 21:29:26 +01:00
PRIMARY KEY ( id )
) ; ` ,
2019-11-19 20:52:57 +00:00
` CREATE UNIQUE INDEX credits_earned_user_id_offer_id ON user_credits (id, offer_id); ` ,
2019-07-12 15:19:38 +01:00
` INSERT INTO offers (
name ,
description ,
award_credit_in_cents ,
invitee_credit_in_cents ,
expires_at ,
created_at ,
status ,
2019-11-19 20:52:57 +00:00
type ,
award_credit_duration_days ,
invitee_credit_duration_days
)
2019-07-12 15:19:38 +01:00
VALUES (
' Default referral offer ' ,
' Is active when no other active referral offer ' ,
300 ,
600 ,
' 2119 - 03 - 14 0 8 : 28 : 24.636949 + 00 ' ,
' 2019 - 07 - 14 0 8 : 28 : 24.636949 + 00 ' ,
1 ,
2019-11-19 20:52:57 +00:00
2 ,
365 ,
14
2019-07-12 15:19:38 +01:00
) ,
(
' Default free credit offer ' ,
' Is active when no active free credit offer ' ,
0 ,
2019-11-19 20:52:57 +00:00
300 ,
2019-07-12 15:19:38 +01:00
' 2119 - 03 - 14 0 8 : 28 : 24.636949 + 00 ' ,
' 2019 - 07 - 14 0 8 : 28 : 24.636949 + 00 ' ,
1 ,
2019-11-19 20:52:57 +00:00
1 ,
NULL ,
14
2019-07-12 15:19:38 +01:00
) ON CONFLICT DO NOTHING ; ` ,
2019-08-07 13:28:13 +01:00
2019-09-13 17:57:32 +01:00
` CREATE TABLE graceful_exit_progress (
node_id bytea NOT NULL ,
bytes_transferred bigint NOT NULL ,
2019-11-19 20:52:57 +00:00
updated_at timestamp NOT NULL ,
pieces_transferred bigint NOT NULL DEFAULT 0 ,
pieces_failed bigint NOT NULL DEFAULT 0 ,
2019-09-13 17:57:32 +01:00
PRIMARY KEY ( node_id )
) ; ` ,
2019-11-19 20:52:57 +00:00
2019-09-13 17:57:32 +01:00
` CREATE TABLE graceful_exit_transfer_queue (
node_id bytea NOT NULL ,
path bytea NOT NULL ,
piece_num integer NOT NULL ,
durability_ratio double precision NOT NULL ,
2019-11-19 20:52:57 +00:00
queued_at timestamp NOT NULL ,
requested_at timestamp ,
last_failed_at timestamp ,
2019-09-13 17:57:32 +01:00
last_failed_code integer ,
failed_count integer ,
2019-11-19 20:52:57 +00:00
finished_at timestamp ,
2019-11-22 19:59:46 +00:00
root_piece_id bytea ,
order_limit_send_count integer NOT NULL DEFAULT 0 ,
2019-11-19 20:52:57 +00:00
PRIMARY KEY ( node_id , path , piece_num )
2019-09-13 17:57:32 +01:00
) ; ` ,
2019-11-19 20:52:57 +00:00
2019-10-10 18:12:23 +01:00
` CREATE TABLE stripe_customers (
user_id bytea NOT NULL ,
2019-11-19 20:52:57 +00:00
customer_id text NOT NULL UNIQUE ,
2019-10-10 18:12:23 +01:00
created_at timestamp with time zone NOT NULL ,
2019-11-19 20:52:57 +00:00
PRIMARY KEY ( user_id )
2019-10-10 18:12:23 +01:00
) ; ` ,
2019-11-19 20:52:57 +00:00
2019-11-05 13:16:02 +00:00
` CREATE TABLE stripecoinpayments_invoice_project_records (
id bytea NOT NULL ,
project_id bytea NOT NULL ,
storage double precision NOT NULL ,
egress bigint NOT NULL ,
objects bigint NOT NULL ,
period_start timestamp with time zone NOT NULL ,
period_end timestamp with time zone NOT NULL ,
state integer NOT NULL ,
created_at timestamp with time zone NOT NULL ,
PRIMARY KEY ( id ) ,
UNIQUE ( project_id , period_start , period_end )
) ; ` ,
2019-11-15 14:59:39 +00:00
` CREATE TABLE stripecoinpayments_tx_conversion_rates (
tx_id text NOT NULL ,
rate bytea NOT NULL ,
created_at timestamp with time zone NOT NULL ,
PRIMARY KEY ( tx_id )
) ; ` ,
2019-11-22 19:59:46 +00:00
2019-11-15 14:59:39 +00:00
` CREATE TABLE coinpayments_transactions (
id text NOT NULL ,
user_id bytea NOT NULL ,
address text NOT NULL ,
amount bytea NOT NULL ,
received bytea NOT NULL ,
status integer NOT NULL ,
key text NOT NULL ,
timeout integer NOT NULL ,
created_at timestamp with time zone NOT NULL ,
PRIMARY KEY ( id )
) ; ` ,
2019-11-22 19:59:46 +00:00
` CREATE TABLE stripecoinpayments_apply_balance_intents (
tx_id text NOT NULL REFERENCES coinpayments_transactions ( id ) ON DELETE CASCADE ,
state integer NOT NULL ,
created_at timestamp with time zone NOT NULL ,
PRIMARY KEY ( tx_id )
) ; ` ,
2019-11-15 14:59:39 +00:00
} ,
} ,
2019-11-26 17:58:51 +00:00
{
DB : db . db ,
Description : "Add coupons and coupon_usage tables" ,
2019-12-10 16:12:49 +00:00
Version : 70 ,
2019-11-26 17:58:51 +00:00
Action : migrate . SQL {
` CREATE TABLE coupons (
id bytea NOT NULL ,
project_id bytea NOT NULL ,
user_id bytea NOT NULL ,
amount bigint NOT NULL ,
description text NOT NULL ,
status integer NOT NULL ,
duration bigint NOT NULL ,
created_at timestamp with time zone NOT NULL ,
PRIMARY KEY ( id ) ,
UNIQUE ( project_id )
) ; ` ,
` CREATE TABLE coupon_usages (
id bytea NOT NULL ,
coupon_id bytea NOT NULL ,
amount bigint NOT NULL ,
interval_end timestamp with time zone NOT NULL ,
PRIMARY KEY ( id )
) ; ` ,
} ,
} ,
2019-12-09 17:04:00 +00:00
{
DB : db . db ,
Description : "Reset node reputations to re-enable disqualification" ,
2019-12-10 16:12:49 +00:00
Version : 71 ,
2019-12-09 17:04:00 +00:00
Action : migrate . SQL {
` UPDATE nodes SET audit_reputation_beta = 0; ` ,
} ,
} ,
2019-02-14 21:55:21 +00:00
} ,
}
}