Skip to content

Commit

Permalink
Merge pull request #43 from SiaFoundation/new-reorg-test
Browse files Browse the repository at this point in the history
Add test for reverting file contracts and revisions
  • Loading branch information
ChrisSchinnerl authored Jun 17, 2024
2 parents 90b6137 + f05cea8 commit dc0275b
Show file tree
Hide file tree
Showing 3 changed files with 332 additions and 42 deletions.
69 changes: 47 additions & 22 deletions persist/sqlite/consensus.go
Original file line number Diff line number Diff line change
Expand Up @@ -730,23 +730,23 @@ func deleteBlock(tx *txn, bid types.BlockID) error {
return err
}

func addFileContractElements(tx *txn, b types.Block, fces []explorer.FileContractUpdate) (map[explorer.DBFileContract]int64, error) {
stmt, err := tx.Prepare(`INSERT INTO file_contract_elements(block_id, contract_id, leaf_index, resolved, valid, filesize, file_merkle_root, window_start, window_end, payout, unlock_hash, revision_number)
VALUES (?, ?, ?, FALSE, TRUE, ?, ?, ?, ?, ?, ?, ?)
func updateFileContractElements(tx *txn, revert bool, b types.Block, fces []explorer.FileContractUpdate) (map[explorer.DBFileContract]int64, error) {
stmt, err := tx.Prepare(`INSERT INTO file_contract_elements(contract_id, leaf_index, resolved, valid, filesize, file_merkle_root, window_start, window_end, payout, unlock_hash, revision_number)
VALUES (?, ?, FALSE, FALSE, ?, ?, ?, ?, ?, ?, ?)
ON CONFLICT (contract_id, revision_number)
DO UPDATE SET resolved = ?, valid = ?, leaf_index = ?
RETURNING id;`)
if err != nil {
return nil, fmt.Errorf("addFileContractElements: failed to prepare file_contract_elements statement: %w", err)
return nil, fmt.Errorf("updateFileContractElements: failed to prepare file_contract_elements statement: %w", err)
}
defer stmt.Close()

revisionStmt, err := tx.Prepare(`INSERT INTO last_contract_revision(contract_id, contract_element_id, ed25519_renter_key, ed25519_host_key)
VALUES (?, ?, ?, ?)
revisionStmt, err := tx.Prepare(`INSERT INTO last_contract_revision(contract_id, block_id, contract_element_id, ed25519_renter_key, ed25519_host_key)
VALUES (?, ?, ?, ?, ?)
ON CONFLICT (contract_id)
DO UPDATE SET contract_element_id = ?, ed25519_renter_key = COALESCE(?, ed25519_renter_key), ed25519_host_key = COALESCE(?, ed25519_host_key)`)
if err != nil {
return nil, fmt.Errorf("addFileContractElements: failed to prepare last_contract_revision statement: %w", err)
return nil, fmt.Errorf("updateFileContractElements: failed to prepare last_contract_revision statement: %w", err)
}
defer revisionStmt.Close()

Expand Down Expand Up @@ -785,7 +785,7 @@ func addFileContractElements(tx *txn, b types.Block, fces []explorer.FileContrac
addFC := func(fcID types.FileContractID, leafIndex uint64, fc types.FileContract, resolved, valid, lastRevision bool) error {
var dbID int64
dbFC := explorer.DBFileContract{ID: fcID, RevisionNumber: fc.RevisionNumber}
err := stmt.QueryRow(encode(b.ID()), encode(fcID), encode(leafIndex), fc.Filesize, encode(fc.FileMerkleRoot), fc.WindowStart, fc.WindowEnd, encode(fc.Payout), encode(fc.UnlockHash), encode(fc.RevisionNumber), resolved, valid, encode(leafIndex)).Scan(&dbID)
err := stmt.QueryRow(encode(fcID), encode(leafIndex), fc.Filesize, encode(fc.FileMerkleRoot), fc.WindowStart, fc.WindowEnd, encode(fc.Payout), encode(fc.UnlockHash), encode(fc.RevisionNumber), resolved, valid, encode(leafIndex)).Scan(&dbID)
if err != nil {
return fmt.Errorf("failed to execute file_contract_elements statement: %w", err)
}
Expand All @@ -799,7 +799,7 @@ func addFileContractElements(tx *txn, b types.Block, fces []explorer.FileContrac
hostKey = encode(keys[1]).([]byte)
}

if _, err := revisionStmt.Exec(encode(fcID), dbID, renterKey, hostKey, dbID, renterKey, hostKey); err != nil {
if _, err := revisionStmt.Exec(encode(fcID), encode(b.ID()), dbID, renterKey, hostKey, dbID, renterKey, hostKey); err != nil {
return fmt.Errorf("failed to update last revision number: %w", err)
}
}
Expand All @@ -808,11 +808,31 @@ func addFileContractElements(tx *txn, b types.Block, fces []explorer.FileContrac
return nil
}

var updateErr error
for _, update := range fces {
fce := &update.FileContractElement
if update.Revision != nil {
fce = update.Revision
var fce *types.FileContractElement

if revert {
// Reverting
if update.Revision != nil {
// Contract revision reverted.
// We are reverting the revision, so get the contract before
// the revision.
fce = &update.FileContractElement
} else {
// Contract formation reverted.
// The contract update has no revision, therefore it refers
// to the original contract formation.
continue
}
} else {
// Applying
fce = &update.FileContractElement
if update.Revision != nil {
// Contract is revised.
// We want last_contract_revision to refer to the latest
// revision, so use the revision FCE if there is one.
fce = update.Revision
}
}

if err := addFC(
Expand All @@ -823,9 +843,14 @@ func addFileContractElements(tx *txn, b types.Block, fces []explorer.FileContrac
update.Valid,
true,
); err != nil {
return nil, fmt.Errorf("addFileContractElements: %w", err)
return nil, fmt.Errorf("updateFileContractElements: %w", err)
}
}

if revert {
return fcDBIds, nil
}

for _, txn := range b.Transactions {
for j, fc := range txn.FileContracts {
fcID := txn.FileContractID(j)
Expand All @@ -834,8 +859,8 @@ func addFileContractElements(tx *txn, b types.Block, fces []explorer.FileContrac
continue
}

if err := addFC(fcID, 0, fc, false, true, false); err != nil {
return nil, fmt.Errorf("addFileContractElements: %w", err)
if err := addFC(fcID, 0, fc, false, false, false); err != nil {
return nil, fmt.Errorf("updateFileContractElements: %w", err)
}
}
for _, fcr := range txn.FileContractRevisions {
Expand All @@ -845,13 +870,13 @@ func addFileContractElements(tx *txn, b types.Block, fces []explorer.FileContrac
continue
}

if err := addFC(fcr.ParentID, 0, fc, false, true, false); err != nil {
return nil, fmt.Errorf("addFileContractElements: %w", err)
if err := addFC(fcr.ParentID, 0, fc, false, false, false); err != nil {
return nil, fmt.Errorf("updateFileContractElements: %w", err)
}
}
}

return fcDBIds, updateErr
return fcDBIds, nil
}

func addMetrics(tx *txn, height uint64, difficulty consensus.Work, b types.Block, fces []explorer.FileContractUpdate, events []explorer.Event) error {
Expand Down Expand Up @@ -976,9 +1001,9 @@ func (ut *updateTx) ApplyIndex(state explorer.UpdateState) error {
return fmt.Errorf("ApplyIndex: failed to update balances: %w", err)
}

fcDBIds, err := addFileContractElements(ut.tx, state.Block, state.FileContractElements)
fcDBIds, err := updateFileContractElements(ut.tx, false, state.Block, state.FileContractElements)
if err != nil {
return fmt.Errorf("v: failed to add file contracts: %w", err)
return fmt.Errorf("ApplyIndex: failed to add file contracts: %w", err)
}

if err := addMinerPayouts(ut.tx, state.Block.ID(), state.Block.MinerPayouts, scDBIds); err != nil {
Expand Down Expand Up @@ -1015,7 +1040,7 @@ func (ut *updateTx) RevertIndex(state explorer.UpdateState) error {
return fmt.Errorf("RevertIndex: failed to update siafund output state: %w", err)
} else if err := updateBalances(ut.tx, state.Index.Height, state.SpentSiacoinElements, state.NewSiacoinElements, state.SpentSiafundElements, state.NewSiafundElements); err != nil {
return fmt.Errorf("RevertIndex: failed to update balances: %w", err)
} else if _, err := addFileContractElements(ut.tx, state.Block, state.FileContractElements); err != nil {
} else if _, err := updateFileContractElements(ut.tx, true, state.Block, state.FileContractElements); err != nil {
return fmt.Errorf("RevertIndex: failed to update file contract state: %w", err)
} else if err := deleteBlock(ut.tx, state.Block.ID()); err != nil {
return fmt.Errorf("RevertIndex: failed to delete block: %w", err)
Expand Down
Loading

0 comments on commit dc0275b

Please sign in to comment.