From ce55cfd789e3cadf4a4a59f946a608a63fac9129 Mon Sep 17 00:00:00 2001 From: Nate Maninger Date: Fri, 30 Aug 2024 10:19:19 -0700 Subject: [PATCH] explorer, sqlite: add id to transaction type --- explorer/types.go | 1 + persist/sqlite/addresses.go | 2 +- persist/sqlite/encoding.go | 2 -- persist/sqlite/init.sql | 16 +++++++++------- persist/sqlite/transactions.go | 31 ++++++++++++++++++++++--------- 5 files changed, 33 insertions(+), 19 deletions(-) diff --git a/explorer/types.go b/explorer/types.go index c78f6d96..2fa0b683 100644 --- a/explorer/types.go +++ b/explorer/types.go @@ -96,6 +96,7 @@ type FileContractRevision struct { // A Transaction is a transaction that uses the wrapped types above. type Transaction struct { + ID types.TransactionID `json:"id"` SiacoinInputs []types.SiacoinInput `json:"siacoinInputs,omitempty"` SiacoinOutputs []SiacoinOutput `json:"siacoinOutputs,omitempty"` SiafundInputs []types.SiafundInput `json:"siafundInputs,omitempty"` diff --git a/persist/sqlite/addresses.go b/persist/sqlite/addresses.go index 4e2c82ea..5c001d22 100644 --- a/persist/sqlite/addresses.go +++ b/persist/sqlite/addresses.go @@ -24,7 +24,7 @@ func scanEvent(tx *txn, s scanner) (ev explorer.Event, eventID int64, err error) if err != nil { return explorer.Event{}, 0, fmt.Errorf("failed to fetch transaction ID: %w", err) } - txns, err := getTransactions(tx, []int64{txnID}) + txns, err := getTransactions(tx, map[int64]types.TransactionID{txnID: types.TransactionID(ev.ID)}) if err != nil || len(txns) == 0 { return explorer.Event{}, 0, fmt.Errorf("failed to fetch transaction: %w", err) } diff --git a/persist/sqlite/encoding.go b/persist/sqlite/encoding.go index 5b91473c..876bd163 100644 --- a/persist/sqlite/encoding.go +++ b/persist/sqlite/encoding.go @@ -85,8 +85,6 @@ func (d *decodable) Scan(src any) error { return fmt.Errorf("cannot scan %T to %T", src, d.v) } return nil - case nil: - return nil default: return fmt.Errorf("cannot scan %T to %T", src, d.v) } diff --git a/persist/sqlite/init.sql b/persist/sqlite/init.sql index e5212020..57f6d5f8 100644 --- a/persist/sqlite/init.sql +++ b/persist/sqlite/init.sql @@ -146,6 +146,7 @@ CREATE TABLE block_transactions ( ); CREATE INDEX block_transactions_block_id_index ON block_transactions(block_id); +CREATE INDEX block_transactions_transaction_id_index ON block_transactions(transaction_id); CREATE TABLE transaction_arbitrary_data ( transaction_id INTEGER REFERENCES transactions(id) ON DELETE CASCADE NOT NULL, @@ -188,11 +189,12 @@ CREATE TABLE transaction_storage_proofs ( ); CREATE INDEX transaction_storage_proofs_transaction_id_index ON transaction_storage_proofs(transaction_id); +CREATE INDEX transaction_storage_proofs_parent_id_index ON transaction_storage_proofs(parent_id); CREATE TABLE transaction_siacoin_inputs ( transaction_id INTEGER REFERENCES transactions(id) ON DELETE CASCADE NOT NULL, transaction_order INTEGER NOT NULL, - parent_id BLOB NOT NULL, + parent_id BLOB NOT NULL, -- TODO: change this to a reference to the siacoin_element and join for queries unlock_conditions BLOB NOT NULL, UNIQUE(transaction_id, transaction_order) ); @@ -211,7 +213,7 @@ CREATE INDEX transaction_siacoin_outputs_transaction_id_index ON transaction_sia CREATE TABLE transaction_siafund_inputs ( transaction_id INTEGER REFERENCES transactions(id) ON DELETE CASCADE NOT NULL, transaction_order INTEGER NOT NULL, - parent_id BLOB NOT NULL, + parent_id BLOB NOT NULL, -- TODO: change this to a reference to the siacoin_element and join for queries unlock_conditions BLOB NOT NULL, claim_address BLOB NOT NULL, UNIQUE(transaction_id, transaction_order) @@ -222,7 +224,7 @@ CREATE INDEX transaction_siafund_inputs_transaction_id_index ON transaction_siaf CREATE TABLE transaction_siafund_outputs ( transaction_id INTEGER REFERENCES transactions(id) ON DELETE CASCADE NOT NULL, transaction_order INTEGER NOT NULL, - output_id INTEGER REFERENCES siafund_elements(id) ON DELETE CASCADE NOT NULL, + output_id INTEGER REFERENCES siafund_elements(id) ON DELETE CASCADE NOT NULL, -- add an index to all foreign keys UNIQUE(transaction_id, transaction_order) ); @@ -231,7 +233,7 @@ CREATE INDEX transaction_siafund_outputs_transaction_id_index ON transaction_sia CREATE TABLE transaction_file_contracts ( transaction_id INTEGER REFERENCES transactions(id) ON DELETE CASCADE NOT NULL, transaction_order INTEGER NOT NULL, - contract_id INTEGER REFERENCES file_contract_elements(id) ON DELETE CASCADE NOT NULL, + contract_id INTEGER REFERENCES file_contract_elements(id) ON DELETE CASCADE NOT NULL, -- add an index to all foreign keys UNIQUE(transaction_id, transaction_order) ); @@ -240,7 +242,7 @@ CREATE INDEX transaction_file_contracts_transaction_id_index ON transaction_file CREATE TABLE transaction_file_contract_revisions ( transaction_id INTEGER REFERENCES transactions(id) ON DELETE CASCADE NOT NULL, transaction_order INTEGER NOT NULL, - contract_id INTEGER REFERENCES file_contract_elements(id) ON DELETE CASCADE NOT NULL, + contract_id INTEGER REFERENCES file_contract_elements(id) ON DELETE CASCADE NOT NULL, -- add an index to all foreign keys parent_id BLOB NOT NULL, unlock_conditions BLOB NOT NULL, UNIQUE(transaction_id, transaction_order) @@ -261,13 +263,13 @@ CREATE TABLE events ( maturity_height INTEGER NOT NULL, date_created INTEGER NOT NULL, event_type TEXT NOT NULL, - block_id BLOB NOT NULL REFERENCES blocks(id) ON DELETE CASCADE, + block_id BLOB NOT NULL REFERENCES blocks(id) ON DELETE CASCADE, -- add an index to all foreign keys height INTEGER NOT NULL ); CREATE INDEX events_block_id_height_index ON events(block_id, height); CREATE TABLE event_addresses ( - event_id INTEGER NOT NULL REFERENCES events(id) ON DELETE CASCADE, + event_id INTEGER NOT NULL REFERENCES events(id) ON DELETE CASCADE, address_id INTEGER NOT NULL REFERENCES address_balance(id), PRIMARY KEY (event_id, address_id) ); diff --git a/persist/sqlite/transactions.go b/persist/sqlite/transactions.go index d77904de..64ee9ac8 100644 --- a/persist/sqlite/transactions.go +++ b/persist/sqlite/transactions.go @@ -363,19 +363,24 @@ ORDER BY transaction_order ASC` // blockTransactionIDs returns the database ID for each transaction in the // block. -func blockTransactionIDs(tx *txn, blockID types.BlockID) (dbIDs []int64, err error) { - rows, err := tx.Query(`SELECT transaction_id FROM block_transactions WHERE block_id = ? ORDER BY block_order`, encode(blockID)) +func blockTransactionIDs(tx *txn, blockID types.BlockID) (idMap map[int64]types.TransactionID, err error) { + rows, err := tx.Query(`SELECT bt.transaction_id, t.transaction_id +FROM block_transactions bt +INNER JOIN transactions t ON (t.id = bt.transaction_id) +WHERE block_id = ? ORDER BY block_order ASC`, encode(blockID)) if err != nil { return nil, err } defer rows.Close() + idMap = make(map[int64]types.TransactionID) for rows.Next() { var dbID int64 - if err := rows.Scan(&dbID); err != nil { + var txnID types.TransactionID + if err := rows.Scan(&dbID, decode(&txnID)); err != nil { return nil, fmt.Errorf("failed to scan block transaction: %w", err) } - dbIDs = append(dbIDs, dbID) + idMap[dbID] = txnID } return } @@ -409,7 +414,7 @@ ORDER BY mp.block_order ASC` } // transactionDatabaseIDs returns the database ID for each transaction. -func transactionDatabaseIDs(tx *txn, txnIDs []types.TransactionID) (dbIDs []int64, err error) { +func transactionDatabaseIDs(tx *txn, txnIDs []types.TransactionID) (dbIDs map[int64]types.TransactionID, err error) { encodedIDs := func(ids []types.TransactionID) []any { result := make([]any, len(ids)) for i, id := range ids { @@ -418,24 +423,31 @@ func transactionDatabaseIDs(tx *txn, txnIDs []types.TransactionID) (dbIDs []int6 return result } - query := `SELECT id FROM transactions WHERE transaction_id IN (` + queryPlaceHolders(len(txnIDs)) + `)` + query := `SELECT id, transaction_id FROM transactions WHERE transaction_id IN (` + queryPlaceHolders(len(txnIDs)) + `)` rows, err := tx.Query(query, encodedIDs(txnIDs)...) if err != nil { return nil, err } defer rows.Close() + dbIDs = make(map[int64]types.TransactionID) for rows.Next() { var dbID int64 - if err := rows.Scan(&dbID); err != nil { + var txnID types.TransactionID + if err := rows.Scan(&dbID, decode(&txnID)); err != nil { return nil, fmt.Errorf("failed to scan transaction: %w", err) } - dbIDs = append(dbIDs, dbID) + dbIDs[dbID] = txnID } return } -func getTransactions(tx *txn, dbIDs []int64) ([]explorer.Transaction, error) { +func getTransactions(tx *txn, idMap map[int64]types.TransactionID) ([]explorer.Transaction, error) { + dbIDs := make([]int64, 0, len(idMap)) + for dbID := range idMap { + dbIDs = append(dbIDs, dbID) + } + txnArbitraryData, err := transactionArbitraryData(tx, dbIDs) if err != nil { return nil, fmt.Errorf("getTransactions: failed to get arbitrary data: %w", err) @@ -489,6 +501,7 @@ func getTransactions(tx *txn, dbIDs []int64) ([]explorer.Transaction, error) { var results []explorer.Transaction for _, dbID := range dbIDs { txn := explorer.Transaction{ + ID: idMap[dbID], SiacoinInputs: txnSiacoinInputs[dbID], SiacoinOutputs: txnSiacoinOutputs[dbID], SiafundInputs: txnSiafundInputs[dbID],