diff --git a/explorer/types.go b/explorer/types.go index 2fa0b683..46246aaa 100644 --- a/explorer/types.go +++ b/explorer/types.go @@ -62,6 +62,20 @@ func (d Source) MarshalJSON() ([]byte, error) { } } +// A SiacoinInput is a types.SiacoinInput with information about the parent +// value. +type SiacoinInput struct { + Value types.Currency + types.SiacoinInput +} + +// A SiafundInput is a types.SiafundInput with information about the parent +// value. +type SiafundInput struct { + Value uint64 + types.SiafundInput +} + // A SiacoinOutput is a types.SiacoinElement with added fields for the source // and when it was spent. type SiacoinOutput struct { @@ -97,9 +111,9 @@ 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"` + SiacoinInputs []SiacoinInput `json:"siacoinInputs,omitempty"` SiacoinOutputs []SiacoinOutput `json:"siacoinOutputs,omitempty"` - SiafundInputs []types.SiafundInput `json:"siafundInputs,omitempty"` + SiafundInputs []SiafundInput `json:"siafundInputs,omitempty"` SiafundOutputs []SiafundOutput `json:"siafundOutputs,omitempty"` FileContracts []FileContract `json:"fileContracts,omitempty"` FileContractRevisions []FileContractRevision `json:"fileContractRevisions,omitempty"` diff --git a/persist/sqlite/consensus_test.go b/persist/sqlite/consensus_test.go index 0bc7c3e1..6677d248 100644 --- a/persist/sqlite/consensus_test.go +++ b/persist/sqlite/consensus_test.go @@ -423,6 +423,9 @@ func TestSendTransactions(t *testing.T) { expectSci := expectTxn.SiacoinInputs[i] gotSci := gotTxn.SiacoinInputs[i] + if gotSci.Value == types.ZeroCurrency { + t.Fatal("invalid value") + } check(t, "parent ID", expectSci.ParentID, gotSci.ParentID) check(t, "unlock conditions", expectSci.UnlockConditions, gotSci.UnlockConditions) } @@ -438,6 +441,9 @@ func TestSendTransactions(t *testing.T) { expectSfi := expectTxn.SiafundInputs[i] gotSfi := gotTxn.SiafundInputs[i] + if gotSfi.Value == 0 { + t.Fatal("invalid value") + } check(t, "parent ID", expectSfi.ParentID, gotSfi.ParentID) check(t, "claim address", expectSfi.ClaimAddress, gotSfi.ClaimAddress) check(t, "unlock conditions", expectSfi.UnlockConditions, gotSfi.UnlockConditions) @@ -1627,6 +1633,9 @@ func TestRevertSendTransactions(t *testing.T) { expectSci := expectTxn.SiacoinInputs[i] gotSci := gotTxn.SiacoinInputs[i] + if gotSci.Value == types.ZeroCurrency { + t.Fatal("invalid value") + } check(t, "parent ID", expectSci.ParentID, gotSci.ParentID) check(t, "unlock conditions", expectSci.UnlockConditions, gotSci.UnlockConditions) } @@ -1642,6 +1651,9 @@ func TestRevertSendTransactions(t *testing.T) { expectSfi := expectTxn.SiafundInputs[i] gotSfi := gotTxn.SiafundInputs[i] + if gotSfi.Value == 0 { + t.Fatal("invalid value") + } check(t, "parent ID", expectSfi.ParentID, gotSfi.ParentID) check(t, "claim address", expectSfi.ClaimAddress, gotSfi.ClaimAddress) check(t, "unlock conditions", expectSfi.UnlockConditions, gotSfi.UnlockConditions) diff --git a/persist/sqlite/transactions.go b/persist/sqlite/transactions.go index 41d04a80..3c25cc32 100644 --- a/persist/sqlite/transactions.go +++ b/persist/sqlite/transactions.go @@ -110,22 +110,23 @@ ORDER BY ts.transaction_order ASC` } // transactionSiacoinInputs returns the siacoin inputs for each transaction. -func transactionSiacoinInputs(tx *txn, txnIDs []int64) (map[int64][]types.SiacoinInput, error) { - query := `SELECT transaction_id, parent_id, unlock_conditions -FROM transaction_siacoin_inputs -WHERE transaction_id IN (` + queryPlaceHolders(len(txnIDs)) + `) -ORDER BY transaction_order ASC` +func transactionSiacoinInputs(tx *txn, txnIDs []int64) (map[int64][]explorer.SiacoinInput, error) { + query := `SELECT ts.transaction_id, ts.parent_id, ts.unlock_conditions, sc.value +FROM siacoin_elements sc +INNER JOIN transaction_siacoin_inputs ts ON (ts.parent_id = sc.output_id) +WHERE ts.transaction_id IN (` + queryPlaceHolders(len(txnIDs)) + `) +ORDER BY ts.transaction_order ASC` rows, err := tx.Query(query, queryArgs(txnIDs)...) if err != nil { return nil, err } defer rows.Close() - result := make(map[int64][]types.SiacoinInput) + result := make(map[int64][]explorer.SiacoinInput) for rows.Next() { var txnID int64 - var sci types.SiacoinInput - if err := rows.Scan(&txnID, decode(&sci.ParentID), decode(&sci.UnlockConditions)); err != nil { + var sci explorer.SiacoinInput + if err := rows.Scan(&txnID, decode(&sci.ParentID), decode(&sci.UnlockConditions), decode(&sci.Value)); err != nil { return nil, fmt.Errorf("failed to scan siacoin input: %w", err) } result[txnID] = append(result[txnID], sci) @@ -134,22 +135,23 @@ ORDER BY transaction_order ASC` } // transactionSiafundInputs returns the siafund inputs for each transaction. -func transactionSiafundInputs(tx *txn, txnIDs []int64) (map[int64][]types.SiafundInput, error) { - query := `SELECT transaction_id, parent_id, unlock_conditions, claim_address -FROM transaction_siafund_inputs -WHERE transaction_id IN (` + queryPlaceHolders(len(txnIDs)) + `) -ORDER BY transaction_order ASC` +func transactionSiafundInputs(tx *txn, txnIDs []int64) (map[int64][]explorer.SiafundInput, error) { + query := `SELECT ts.transaction_id, ts.parent_id, ts.unlock_conditions, ts.claim_address, sf.value +FROM siafund_elements sf +INNER JOIN transaction_siafund_inputs ts ON (ts.parent_id = sf.output_id) +WHERE ts.transaction_id IN (` + queryPlaceHolders(len(txnIDs)) + `) +ORDER BY ts.transaction_order ASC` rows, err := tx.Query(query, queryArgs(txnIDs)...) if err != nil { return nil, err } defer rows.Close() - result := make(map[int64][]types.SiafundInput) + result := make(map[int64][]explorer.SiafundInput) for rows.Next() { var txnID int64 - var sfi types.SiafundInput - if err := rows.Scan(&txnID, decode(&sfi.ParentID), decode(&sfi.UnlockConditions), decode(&sfi.ClaimAddress)); err != nil { + var sfi explorer.SiafundInput + if err := rows.Scan(&txnID, decode(&sfi.ParentID), decode(&sfi.UnlockConditions), decode(&sfi.ClaimAddress), decode(&sfi.Value)); err != nil { return nil, fmt.Errorf("failed to scan siafund input: %w", err) } result[txnID] = append(result[txnID], sfi)