Skip to content

Commit

Permalink
only add outputs that mature in future to balance when they mature
Browse files Browse the repository at this point in the history
  • Loading branch information
chris124567 committed Mar 4, 2024
1 parent a849283 commit 1a34073
Showing 1 changed file with 86 additions and 1 deletion.
87 changes: 86 additions & 1 deletion persist/sqlite/consensus.go
Original file line number Diff line number Diff line change
Expand Up @@ -319,7 +319,8 @@ func (s *Store) updateBalances(dbTxn txn, update consensusUpdate) error {
if underflow {
return
}
} else {
} else if sce.MaturityHeight == 0 {
// Outputs that mature later are handled in updateMaturedBalances
// log.Println("Gain:", sce.SiacoinOutput.Address, sce.SiacoinOutput.Value)
bal.sc = bal.sc.Add(sce.SiacoinOutput.Value)
}
Expand Down Expand Up @@ -358,6 +359,86 @@ func (s *Store) updateBalances(dbTxn txn, update consensusUpdate) error {
return nil
}

func (s *Store) updateMaturedBalances(dbTxn txn, update consensusUpdate, height uint64) error {
// Prevent double counting - outputs with a maturity height of 0 are
// handled in updateBalances
if height == 0 {
return nil
}

_, isApply := update.(*chain.ApplyUpdate)
if !isApply {
height += 1
}

rows, err := dbTxn.Query(`SELECT address, value
FROM siacoin_elements
WHERE maturity_height = ?`, height)
if err != nil {
return fmt.Errorf("updateMaturedBalances: failed to query siacoin_elements: %w", err)
}
defer rows.Close()

var addressList []any
var scos []types.SiacoinOutput
for rows.Next() {
var sco types.SiacoinOutput
if err := rows.Scan(dbDecode(&sco.Address), dbDecode(&sco.Value)); err != nil {
return fmt.Errorf("updateMaturedBalances: failed to scan maturing outputs: %w", err)
}
scos = append(scos, sco)
addressList = append(addressList, dbEncode(sco.Address))
}

balanceRows, err := dbTxn.Query(`SELECT address, siacoin_balance
FROM address_balance
WHERE address IN (`+queryPlaceHolders(len(addressList))+`)`, addressList...)
if err != nil {
return fmt.Errorf("updateMaturedBalances: failed to query address_balance: %w", err)
}
defer balanceRows.Close()

addresses := make(map[types.Address]types.Currency)
for balanceRows.Next() {
var address types.Address
var sc types.Currency
if err := balanceRows.Scan(dbDecode(&address), dbDecode(&sc)); err != nil {
return fmt.Errorf("updateMaturedBalances: failed to scan balance: %w", err)
}
addresses[address] = sc
}

// If the update is an apply update then we add the amounts.
// If we are reverting then we subtract them.
for _, sco := range scos {
bal := addresses[sco.Address]
if isApply {
bal = bal.Add(sco.Value)
} else {
bal = bal.Sub(sco.Value)
}
addresses[sco.Address] = bal
}

stmt, err := dbTxn.Prepare(`INSERT INTO address_balance(address, siacoin_balance, siafund_balance)
VALUES (?, ?, ?)
ON CONFLICT(address)
DO UPDATE set siacoin_balance = ?`)
if err != nil {
return fmt.Errorf("updateMaturedBalances: failed to prepare statement: %w", err)
}
defer stmt.Close()

initialSF := dbEncode(uint64(0))
for addr, bal := range addresses {
if _, err := stmt.Exec(dbEncode(addr), dbEncode(bal), initialSF, dbEncode(bal)); err != nil {
return fmt.Errorf("updateMaturedBalances: failed to exec statement: %w", err)
}
}

return nil
}

func (s *Store) addSiacoinElements(dbTxn txn, bid types.BlockID, update consensusUpdate) (map[types.SiacoinOutputID]int64, error) {
sources := make(map[types.SiacoinOutputID]explorer.Source)
if applyUpdate, ok := update.(*chain.ApplyUpdate); ok {
Expand Down Expand Up @@ -512,6 +593,8 @@ func (s *Store) applyUpdates() error {
}
if err := s.updateBalances(dbTxn, update); err != nil {
return fmt.Errorf("applyUpdates: failed to update balances: %w", err)
} else if err := s.updateMaturedBalances(dbTxn, update, update.State.Index.Height); err != nil {
return fmt.Errorf("applyUpdates: failed to update matured balances: %w", err)
}

fcDBIds, err := s.addFileContractElements(dbTxn, update.Block.ID(), update)
Expand Down Expand Up @@ -546,6 +629,8 @@ func (s *Store) revertUpdate(cru *chain.RevertUpdate) error {
return fmt.Errorf("revertUpdate: failed to update siafund output state: %w", err)
} else if err := s.updateBalances(dbTxn, cru); err != nil {
return fmt.Errorf("revertUpdate: failed to update balances: %w", err)
} else if err := s.updateMaturedBalances(dbTxn, cru, cru.State.Index.Height); err != nil {
return fmt.Errorf("revertUpdate: failed to update matured balances: %w", err)
} else if _, err := s.addFileContractElements(dbTxn, cru.Block.ID(), cru); err != nil {
return fmt.Errorf("revertUpdate: failed to update file contract state: %w", err)
}
Expand Down

0 comments on commit 1a34073

Please sign in to comment.