Skip to content

Commit

Permalink
[PSL-1207] implement recovery flows for cascade multi-vol registratio…
Browse files Browse the repository at this point in the history
…n/activation
  • Loading branch information
j-rafique committed Jul 5, 2024
1 parent 9f6e7d4 commit fd164bf
Show file tree
Hide file tree
Showing 32 changed files with 60,780 additions and 56,354 deletions.
10 changes: 6 additions & 4 deletions common/storage/ticketstore/activation_attempts.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package ticketstore

import (
"github.com/pastelnetwork/gonode/common/types"
"time"
)

type ActivationAttemptsQueries interface {
Expand All @@ -15,14 +16,14 @@ type ActivationAttemptsQueries interface {
func (s *TicketStore) InsertActivationAttempt(attempt types.ActivationAttempt) (int64, error) {
const insertQuery = `
INSERT INTO activation_attempts (
file_id, activation_attempt_at, is_successful, error_message
) VALUES (?, ?, ?, ?)
file_id, activation_attempt_at, is_successful, error_message, created_at, updated_at
) VALUES (?, ?, ?, ?, ?, ?)
RETURNING id;`

var id int64
err := s.db.QueryRow(insertQuery,
attempt.FileID, attempt.ActivationAttemptAt,
attempt.IsSuccessful, attempt.ErrorMessage).Scan(&id)
attempt.IsSuccessful, attempt.ErrorMessage, time.Now().UTC(), time.Now().UTC()).Scan(&id)
if err != nil {
return 0, err
}
Expand All @@ -34,7 +35,7 @@ func (s *TicketStore) InsertActivationAttempt(attempt types.ActivationAttempt) (
func (s *TicketStore) UpdateActivationAttempt(attempt types.ActivationAttempt) (int64, error) {
const updateQuery = `
UPDATE activation_attempts
SET activation_attempt_at = ?, is_successful = ?, error_message = ?
SET activation_attempt_at = ?, is_successful = ?, error_message = ?, updated_at = ?
WHERE id = ? AND file_id = ?
RETURNING id`

Expand All @@ -43,6 +44,7 @@ func (s *TicketStore) UpdateActivationAttempt(attempt types.ActivationAttempt) (
attempt.ActivationAttemptAt,
attempt.IsSuccessful,
attempt.ErrorMessage,
time.Now().UTC(),
attempt.ID,
attempt.FileID).Scan(&id)
if err != nil {
Expand Down
52 changes: 48 additions & 4 deletions common/storage/ticketstore/files.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@ package ticketstore

import (
"github.com/pastelnetwork/gonode/common/types"
"time"
)

type FilesQueries interface {
UpsertFile(file types.File) error
GetFileByID(fileID string) (*types.File, error)
GetFilesByBaseFileID(baseFileID string) ([]*types.File, error)
GetFileByTaskID(taskID string) (*types.File, error)
GetFilesByBaseFileIDAndConcludedCheck(baseFileID string, isConcluded bool) ([]*types.File, error)
}

// UpsertFile inserts a new file into the files table
Expand All @@ -20,8 +22,8 @@ func (s *TicketStore) UpsertFile(file types.File) error {
req_amount, is_concluded, cascade_metadata_ticket_id, uuid_key,
hash_of_original_big_file, name_of_original_big_file_with_ext,
size_of_original_big_file, data_type_of_original_big_file,
start_block, done_block
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
start_block, done_block, created_at, updated_at
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
ON CONFLICT(file_id)
DO UPDATE SET
upload_timestamp = COALESCE(excluded.upload_timestamp, files.upload_timestamp),
Expand All @@ -42,15 +44,16 @@ func (s *TicketStore) UpsertFile(file types.File) error {
size_of_original_big_file = COALESCE(excluded.size_of_original_big_file, files.size_of_original_big_file),
data_type_of_original_big_file = COALESCE(excluded.data_type_of_original_big_file, files.data_type_of_original_big_file),
start_block = COALESCE(excluded.start_block, files.start_block),
done_block = COALESCE(excluded.done_block, files.done_block);`
done_block = COALESCE(excluded.done_block, files.done_block),
txid = COALESCE(excluded.txid, files.txid);`

_, err := s.db.Exec(upsertQuery,
file.FileID, file.UploadTimestamp, file.Path, file.FileIndex, file.BaseFileID, file.TaskID,
file.RegTxid, file.ActivationTxid, file.ReqBurnTxnAmount, file.BurnTxnID,
file.ReqAmount, file.IsConcluded, file.CascadeMetadataTicketID, file.UUIDKey,
file.HashOfOriginalBigFile, file.NameOfOriginalBigFileWithExt,
file.SizeOfOriginalBigFile, file.DataTypeOfOriginalBigFile,
file.StartBlock, file.DoneBlock)
file.StartBlock, file.DoneBlock, time.Now().UTC(), time.Now().UTC())
if err != nil {
return err
}
Expand Down Expand Up @@ -156,3 +159,44 @@ func (s *TicketStore) GetFilesByBaseFileID(baseFileID string) ([]*types.File, er

return files, nil
}

// GetFilesByBaseFileIDAndConcludedCheck retrieves un-concluded files by base_file_id and is_concluded check from the files table.
func (s *TicketStore) GetFilesByBaseFileIDAndConcludedCheck(baseFileID string, isConcluded bool) ([]*types.File, error) {
const selectQuery = `
SELECT file_id, upload_timestamp, path, file_index, base_file_id, task_id,
reg_txid, activation_txid, req_burn_txn_amount, burn_txn_id,
req_amount, is_concluded, cascade_metadata_ticket_id, uuid_key,
hash_of_original_big_file, name_of_original_big_file_with_ext,
size_of_original_big_file, data_type_of_original_big_file,
start_block, done_block
FROM files
WHERE base_file_id = ? AND is_concluded = ?;`

rows, err := s.db.Query(selectQuery, baseFileID, isConcluded)
if err != nil {
return nil, err
}
defer rows.Close()

var files []*types.File
for rows.Next() {
var file types.File
err := rows.Scan(
&file.FileID, &file.UploadTimestamp, &file.Path, &file.FileIndex, &file.BaseFileID, &file.TaskID,
&file.RegTxid, &file.ActivationTxid, &file.ReqBurnTxnAmount, &file.BurnTxnID,
&file.ReqAmount, &file.IsConcluded, &file.CascadeMetadataTicketID, &file.UUIDKey,
&file.HashOfOriginalBigFile, &file.NameOfOriginalBigFileWithExt,
&file.SizeOfOriginalBigFile, &file.DataTypeOfOriginalBigFile,
&file.StartBlock, &file.DoneBlock)
if err != nil {
return nil, err
}
files = append(files, &file)
}

if err = rows.Err(); err != nil {
return nil, err
}

return files, nil
}
1 change: 1 addition & 0 deletions common/storage/ticketstore/local.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,5 @@ type TicketStorageInterface interface {
FilesQueries
ActivationAttemptsQueries
RegistrationAttemptsQueries
MultiVolCascadeTicketMapQueries
}
44 changes: 44 additions & 0 deletions common/storage/ticketstore/multi_vol_cascade_ticket_txid_map.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package ticketstore

import (
"time"

"github.com/pastelnetwork/gonode/common/types"
)

type MultiVolCascadeTicketMapQueries interface {
InsertMultiVolCascadeTicketTxIDMap(m types.MultiVolCascadeTicketTxIDMap) error
GetMultiVolCascadeTicketTxIDMap(baseFileID string) (*types.MultiVolCascadeTicketTxIDMap, error)
}

func (s *TicketStore) InsertMultiVolCascadeTicketTxIDMap(m types.MultiVolCascadeTicketTxIDMap) error {
insertSQL := `
INSERT INTO multi_vol_cascade_tickets_txid_map (base_file_id, multi_vol_cascade_ticket_txid, created_at, updated_at)
VALUES (?, ?, ?, ?)`
stmt, err := s.db.Prepare(insertSQL)
if err != nil {
return err
}
defer stmt.Close()

_, err = stmt.Exec(m.BaseFileID, m.MultiVolCascadeTicketTxid, time.Now().UTC(), time.Now().UTC())
if err != nil {
return err
}
return nil
}

func (s *TicketStore) GetMultiVolCascadeTicketTxIDMap(baseFileID string) (*types.MultiVolCascadeTicketTxIDMap, error) {
selectSQL := `
SELECT id, base_file_id, multi_vol_cascade_ticket_txid
FROM multi_vol_cascade_tickets_txid_map
WHERE base_file_id = ?`
row := s.db.QueryRow(selectSQL, baseFileID)

var ticket types.MultiVolCascadeTicketTxIDMap
err := row.Scan(&ticket.ID, &ticket.BaseFileID, &ticket.MultiVolCascadeTicketTxid)
if err != nil {
return nil, err
}
return &ticket, nil
}
12 changes: 7 additions & 5 deletions common/storage/ticketstore/registration_attempts.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package ticketstore

import (
"github.com/pastelnetwork/gonode/common/types"
"time"
)

type RegistrationAttemptsQueries interface {
Expand All @@ -15,14 +16,14 @@ type RegistrationAttemptsQueries interface {
func (s *TicketStore) InsertRegistrationAttempt(attempt types.RegistrationAttempt) (int64, error) {
const insertQuery = `
INSERT INTO registration_attempts (
file_id, reg_started_at, processor_sns, finished_at, is_successful, error_message
) VALUES (?, ?, ?, ?, ?, ?)
file_id, reg_started_at, processor_sns, finished_at, is_successful, error_message, created_at, updated_at
) VALUES (?, ?, ?, ?, ?, ?, ?, ?)
RETURNING id;`

var id int64
err := s.db.QueryRow(insertQuery,
attempt.FileID, attempt.RegStartedAt, attempt.ProcessorSNS,
attempt.FinishedAt, attempt.IsSuccessful, attempt.ErrorMessage).Scan(&id)
attempt.FinishedAt, attempt.IsSuccessful, attempt.ErrorMessage, time.Now().UTC(), time.Now().UTC()).Scan(&id)
if err != nil {
return 0, err
}
Expand All @@ -38,14 +39,15 @@ func (s *TicketStore) UpdateRegistrationAttempt(attempt types.RegistrationAttemp
processor_sns = ?,
finished_at = ?,
is_successful = ?,
error_message = ?
error_message = ?,
updated_at = ?
WHERE id = ? AND file_id = ?
RETURNING id;`

var id int64
err := s.db.QueryRow(updateQuery,
attempt.RegStartedAt, attempt.ProcessorSNS, attempt.FinishedAt,
attempt.IsSuccessful, attempt.ErrorMessage,
attempt.IsSuccessful, attempt.ErrorMessage, time.Now().UTC(),
attempt.ID, attempt.FileID).Scan(&id)
if err != nil {
return 0, err
Expand Down
24 changes: 21 additions & 3 deletions common/storage/ticketstore/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@ CREATE TABLE IF NOT EXISTS files (
size_of_original_big_file FLOAT,
data_type_of_original_big_file TEXT,
start_block INTEGER,
done_block INTEGER
done_block INTEGER,
created_at DATETIME NOT NULL,
updated_at DATETIME NOT NULL
);
`

Expand All @@ -43,7 +45,9 @@ CREATE TABLE IF NOT EXISTS registration_attempts (
processor_sns TEXT,
finished_at DATETIME,
is_successful BOOLEAN,
error_message TEXT
error_message TEXT,
created_at DATETIME NOT NULL,
updated_at DATETIME NOT NULL
);
`

Expand All @@ -53,7 +57,19 @@ CREATE TABLE IF NOT EXISTS activation_attempts (
file_id TEXT NOT NULL,
activation_attempt_at DATETIME,
is_successful BOOLEAN,
error_message TEXT
error_message TEXT,
created_at DATETIME NOT NULL,
updated_at DATETIME NOT NULL
);
`

const createMultiVolCascadeTicketTxIDMap string = `
CREATE TABLE IF NOT EXISTS multi_vol_cascade_tickets_txid_map (
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
base_file_id TEXT NOT NULL,
multi_vol_cascade_ticket_txid TEXT NOT NULL,
created_at DATETIME NOT NULL,
updated_at DATETIME NOT NULL
);
`

Expand Down Expand Up @@ -94,6 +110,8 @@ func OpenTicketingDb() (TicketStorageInterface, error) {
return nil, fmt.Errorf("cannot create table(s): %w", err)
}

_, _ = db.Exec(createMultiVolCascadeTicketTxIDMap)

pragmas := []string{
"PRAGMA synchronous=NORMAL;",
"PRAGMA cache_size=-262144;",
Expand Down
6 changes: 6 additions & 0 deletions common/types/ticket.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,9 @@ func (fs Files) GetBase() *File {

return nil
}

type MultiVolCascadeTicketTxIDMap struct {
ID int64
MultiVolCascadeTicketTxid string
BaseFileID string
}
78 changes: 78 additions & 0 deletions walletnode/api/design/cascade.go
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,31 @@ var _ = Service("cascade", func() {
Response(StatusCreated)
})
})

Method("restore", func() {
Description("Restore the files cascade registration")
Meta("swagger:summary", "Restore the file details for registration, activation and multi-volume pastel")

Security(APIKeyAuth)

Payload(func() {
Extend(RestoreFilePayload)
})
Result(RestoreFileResult)

HTTP(func() {
POST("/restore/{base_file_id}")
Params(func() {
Param("base_file_id", String)
})

// Define error HTTP statuses.
Response("UnAuthorized", StatusUnauthorized)
Response("BadRequest", StatusBadRequest)
Response("InternalServerError", StatusInternalServerError)
Response(StatusCreated)
})
})
})

// AssetUploadPayload represents a payload for uploading asset
Expand Down Expand Up @@ -341,6 +366,45 @@ var FileRegistrationDetailPayload = Type("FileRegistrationDetailPayload", func()
Required("base_file_id")
})

// RestoreFilePayload - Payload for restore file details.
var RestoreFilePayload = Type("RestoreFilePayload", func() {
Description("Restore file details")
Attribute("base_file_id", String, func() {
Description("Base file ID")
MaxLength(8)
Example("VK7mpAqZ")
})
Attribute("app_pastelId", String, func() {
Meta("struct:field:name", "AppPastelID")
Description("App PastelID")
MinLength(86)
MaxLength(86)
Pattern(`^[a-zA-Z0-9]+$`)
Example("jXYJud3rmrR1Sk2scvR47N4E4J5Vv48uCC6se2nzHrBRdjaKj3ybPoi1Y2VVoRqi1GnQrYKjSxQAC7NBtvtEdS")
})
APIKey("api_key", "key", String, func() {
Description("Passphrase of the owner's PastelID")
Example("Basic abcdef12345")
})
Attribute("make_publicly_accessible", Boolean, func() {
Meta("struct:field:name", "MakePubliclyAccessible")
Description("To make it publicly accessible")
Example(false)
Default(false)

})
Attribute("spendable_address", String, func() {
Meta("struct:field:name", "SpendableAddress")
Description("Address to use for registration fee ")
MinLength(35)
MaxLength(35)
Pattern(`^[a-zA-Z0-9]+$`)
Example("PtiqRXn2VQwBjp1K8QXR2uW2w2oZ3Ns7N6j")
})

Required("base_file_id", "app_pastelId", "key")
})

// FileRegistrationDetailResult is registration detail result.
var FileRegistrationDetailResult = ResultType("application/vnd.cascade.registration-detail", func() {
TypeName("Registration")
Expand All @@ -350,6 +414,20 @@ var FileRegistrationDetailResult = ResultType("application/vnd.cascade.registrat
Required("files")
})

// RestoreFileResult is return type for restore file details.
var RestoreFileResult = ResultType("application/vnd.cascade.restore-files", func() {
TypeName("RestoreFile")
Attribute("total_volumes", Int, "Total volumes of selected file")
Attribute("registered_volumes", Int, "Total registered volumes")
Attribute("volumes_with_pending_registration", Int, "Total volumes with pending registration")
Attribute("volumes_registration_in_progress", Int, "Total volumes with in-progress registration")
Attribute("activated_volumes", Int, "Total volumes that are activated")
Attribute("volumes_activated_in_recovery_flow", Int, "Total volumes that are activated in restore process")

Required("total_volumes", "registered_volumes", "volumes_with_pending_registration",
"volumes_registration_in_progress", "activated_volumes", "volumes_activated_in_recovery_flow")
})

var File = Type("File", func() {
Attribute("file_id", String, "File ID")
Attribute("upload_timestamp", String, "Upload Timestamp in datetime format", func() {
Expand Down
Loading

0 comments on commit fd164bf

Please sign in to comment.