Skip to content

Commit

Permalink
use explorer types for events
Browse files Browse the repository at this point in the history
  • Loading branch information
chris124567 committed Dec 16, 2024
1 parent 7bee799 commit 134f5ba
Show file tree
Hide file tree
Showing 6 changed files with 202 additions and 226 deletions.
174 changes: 119 additions & 55 deletions explorer/events.go
Original file line number Diff line number Diff line change
@@ -1,48 +1,74 @@
package explorer

import (
"time"

"go.sia.tech/core/consensus"
"go.sia.tech/core/types"
"go.sia.tech/coreutils/wallet"
)

// event types indicate the source of an event. Events can
// either be created by sending Siacoins between addresses or they can be
// created by consensus (e.g. a miner payout, a siafund claim, or a contract).
const (
EventTypeMinerPayout = wallet.EventTypeMinerPayout
EventTypeFoundationSubsidy = wallet.EventTypeFoundationSubsidy
EventTypeSiafundClaim = wallet.EventTypeSiafundClaim

EventTypeV1Transaction = wallet.EventTypeV1Transaction
EventTypeV1ContractResolution = wallet.EventTypeV1ContractResolution

EventTypeV2Transaction = wallet.EventTypeV2Transaction
EventTypeV2ContractResolution = wallet.EventTypeV2ContractResolution
)

type (
// An EventPayout represents a miner payout, siafund claim, or foundation
// subsidy.
EventPayout = wallet.EventPayout
EventPayout struct {
SiacoinElement SiacoinOutput `json:"siacoinElement"`
}

// An EventV1Transaction pairs a v1 transaction with its spent siacoin and
// siafund elements.
EventV1Transaction = wallet.EventV1Transaction
EventV1Transaction struct {
Transaction Transaction `json:"transaction"`
// v1 siacoin inputs do not describe the value of the spent utxo
SpentSiacoinElements []SiacoinOutput `json:"spentSiacoinElements,omitempty"`
// v1 siafund inputs do not describe the value of the spent utxo
SpentSiafundElements []SiacoinOutput `json:"spentSiafundElements,omitempty"`
}

// An EventV1ContractResolution represents a file contract payout from a v1
// contract.
EventV1ContractResolution = wallet.EventV1ContractResolution
// EventV2Transaction is a transaction event that includes the transaction
EventV2Transaction = wallet.EventV2Transaction
EventV1ContractResolution struct {
Parent ExtendedFileContract `json:"parent"`
SiacoinElement SiacoinOutput `json:"siacoinElement"`
Missed bool `json:"missed"`
}

// An EventV2ContractResolution represents a file contract payout from a v2
// contract.
EventV2ContractResolution = wallet.EventV2ContractResolution
EventV2ContractResolution struct {
Resolution V2FileContractResolution `json:"resolution"`
SiacoinElement SiacoinOutput `json:"siacoinElement"`
Missed bool `json:"missed"`
}

// EventData is the data associated with an event.
EventData = wallet.EventData
// An Event is a record of a consensus event that affects the wallet.
Event = wallet.Event
// EventV2Transaction is a transaction event that includes the transaction
EventV2Transaction V2Transaction

// EventData contains the data associated with an event.
EventData interface {
isEvent() bool
}

// An Event is a transaction or other event that affects the wallet including
// miner payouts, siafund claims, and file contract payouts.
Event struct {
ID types.Hash256 `json:"id"`
Index types.ChainIndex `json:"index"`
Confirmations uint64 `json:"confirmations"`
Type string `json:"type"`
Data EventData `json:"data"`
MaturityHeight uint64 `json:"maturityHeight"`
Timestamp time.Time `json:"timestamp"`
Relevant []types.Address `json:"relevant,omitempty"`
}
)

func (EventPayout) isEvent() bool { return true }
func (EventV1Transaction) isEvent() bool { return true }
func (EventV1ContractResolution) isEvent() bool { return true }
func (EventV2Transaction) isEvent() bool { return true }
func (EventV2ContractResolution) isEvent() bool { return true }

// A ChainUpdate is a set of changes to the consensus state.
type ChainUpdate interface {
ForEachSiacoinElement(func(sce types.SiacoinElement, created, spent bool))
Expand Down Expand Up @@ -91,9 +117,9 @@ func AppliedEvents(cs consensus.State, b types.Block, cu ChainUpdate) (events []
for _, txn := range b.Transactions {
addresses := make(map[types.Address]struct{})
e := EventV1Transaction{
Transaction: txn,
SpentSiacoinElements: make([]types.SiacoinElement, 0, len(txn.SiacoinInputs)),
SpentSiafundElements: make([]types.SiafundElement, 0, len(txn.SiafundInputs)),
// Transaction: txn,
// SpentSiacoinElements: make([]types.SiacoinElement, 0, len(txn.SiacoinInputs)),
// SpentSiafundElements: make([]types.SiafundElement, 0, len(txn.SiafundInputs)),
}

for _, sci := range txn.SiacoinInputs {
Expand All @@ -102,7 +128,7 @@ func AppliedEvents(cs consensus.State, b types.Block, cu ChainUpdate) (events []
continue
}

e.SpentSiacoinElements = append(e.SpentSiacoinElements, sce)
// e.SpentSiacoinElements = append(e.SpentSiacoinElements, sce)
addresses[sce.SiacoinOutput.Address] = struct{}{}
}
for _, sco := range txn.SiacoinOutputs {
Expand All @@ -115,13 +141,13 @@ func AppliedEvents(cs consensus.State, b types.Block, cu ChainUpdate) (events []
continue
}

e.SpentSiafundElements = append(e.SpentSiafundElements, sfe)
// e.SpentSiafundElements = append(e.SpentSiafundElements, sfe)
addresses[sfe.SiafundOutput.Address] = struct{}{}

sce, ok := sces[sfi.ParentID.ClaimOutputID()]
if ok {
addEvent(types.Hash256(sce.ID), sce.MaturityHeight, EventTypeSiafundClaim, EventPayout{
SiacoinElement: sce,
addEvent(types.Hash256(sce.ID), sce.MaturityHeight, wallet.EventTypeSiafundClaim, EventPayout{
SiacoinElement: SiacoinOutput{SiacoinElement: sce},
}, []types.Address{sfi.ClaimAddress})
}
}
Expand All @@ -148,7 +174,7 @@ func AppliedEvents(cs consensus.State, b types.Block, cu ChainUpdate) (events []
relevant = append(relevant, addr)
}

addEvent(types.Hash256(txn.ID()), cs.Index.Height, EventTypeV1Transaction, e, relevant) // transaction maturity height is the current block height
addEvent(types.Hash256(txn.ID()), cs.Index.Height, wallet.EventTypeV1Transaction, e, relevant) // transaction maturity height is the current block height
}

// handle v2 transactions
Expand All @@ -165,21 +191,22 @@ func AppliedEvents(cs consensus.State, b types.Block, cu ChainUpdate) (events []

sce, ok := sces[types.SiafundOutputID(sfi.Parent.ID).V2ClaimOutputID()]
if ok {
addEvent(types.Hash256(sce.ID), sce.MaturityHeight, EventTypeSiafundClaim, EventPayout{
SiacoinElement: sce,
addEvent(types.Hash256(sce.ID), sce.MaturityHeight, wallet.EventTypeSiafundClaim, EventPayout{
SiacoinElement: SiacoinOutput{SiacoinElement: sce},
}, []types.Address{sfi.ClaimAddress})
}
}
for _, sco := range txn.SiafundOutputs {
addresses[sco.Address] = struct{}{}
}

ev := EventV2Transaction(txn)
// ev := EventV2Transaction(txn)
var ev EventV2Transaction
relevant := make([]types.Address, 0, len(addresses))
for addr := range addresses {
relevant = append(relevant, addr)
}
addEvent(types.Hash256(txn.ID()), cs.Index.Height, EventTypeV2Transaction, ev, relevant) // transaction maturity height is the current block height
addEvent(types.Hash256(txn.ID()), cs.Index.Height, wallet.EventTypeV2Transaction, ev, relevant) // transaction maturity height is the current block height
}

// handle contracts
Expand All @@ -190,23 +217,45 @@ func AppliedEvents(cs consensus.State, b types.Block, cu ChainUpdate) (events []

fce.StateElement.MerkleProof = nil

var mpos, vpos []ContractSiacoinOutput
for _, mpo := range fce.FileContract.MissedProofOutputs {
mpos = append(mpos, ContractSiacoinOutput{SiacoinOutput: mpo})
}
for _, vpo := range fce.FileContract.ValidProofOutputs {
vpos = append(vpos, ContractSiacoinOutput{SiacoinOutput: vpo})
}
efc := ExtendedFileContract{
ID: fce.ID,
Filesize: fce.FileContract.Filesize,
FileMerkleRoot: fce.FileContract.FileMerkleRoot,
WindowStart: fce.FileContract.WindowStart,
WindowEnd: fce.FileContract.WindowEnd,
Payout: fce.FileContract.Payout,
ValidProofOutputs: vpos,
MissedProofOutputs: mpos,
UnlockHash: fce.FileContract.UnlockHash,
RevisionNumber: fce.FileContract.RevisionNumber,
}

if valid {
for i := range fce.FileContract.ValidProofOutputs {
address := fce.FileContract.ValidProofOutputs[i].Address
element := sces[types.FileContractID(fce.ID).ValidOutputID(i)]
addEvent(types.Hash256(element.ID), element.MaturityHeight, EventTypeV1ContractResolution, EventV1ContractResolution{
Parent: fce,
SiacoinElement: element,

addEvent(types.Hash256(element.ID), element.MaturityHeight, wallet.EventTypeV1ContractResolution, EventV1ContractResolution{
Parent: efc,
SiacoinElement: SiacoinOutput{SiacoinElement: element},
Missed: false,
}, []types.Address{address})
}
} else {
for i := range fce.FileContract.MissedProofOutputs {
address := fce.FileContract.MissedProofOutputs[i].Address
element := sces[types.FileContractID(fce.ID).MissedOutputID(i)]
addEvent(types.Hash256(element.ID), element.MaturityHeight, EventTypeV1ContractResolution, EventV1ContractResolution{
Parent: fce,
SiacoinElement: element,

addEvent(types.Hash256(element.ID), element.MaturityHeight, wallet.EventTypeV1ContractResolution, EventV1ContractResolution{
Parent: efc,
SiacoinElement: SiacoinOutput{SiacoinElement: element},
Missed: true,
}, []types.Address{address})
}
Expand All @@ -225,26 +274,41 @@ func AppliedEvents(cs consensus.State, b types.Block, cu ChainUpdate) (events []
missed = true
}

var typ string
switch res.(type) {
case *types.V2FileContractRenewal:
typ = "renewal"
case *types.V2StorageProof:
typ = "storageProof"
case *types.V2FileContractExpiration:
typ = "expiration"
default:
panic("unknown resolution type")
}

efc := V2FileContract{V2FileContractElement: fce}
{
element := sces[types.FileContractID(fce.ID).V2HostOutputID()]
addEvent(types.Hash256(element.ID), element.MaturityHeight, EventTypeV2ContractResolution, EventV2ContractResolution{
Resolution: types.V2FileContractResolution{
Parent: fce,
addEvent(types.Hash256(element.ID), element.MaturityHeight, wallet.EventTypeV2ContractResolution, EventV2ContractResolution{
Resolution: V2FileContractResolution{
Parent: efc,
Type: typ,
Resolution: res,
},
SiacoinElement: element,
SiacoinElement: SiacoinOutput{SiacoinElement: element},
Missed: missed,
}, []types.Address{fce.V2FileContract.HostOutput.Address})
}

{
element := sces[types.FileContractID(fce.ID).V2RenterOutputID()]
addEvent(types.Hash256(element.ID), element.MaturityHeight, EventTypeV2ContractResolution, EventV2ContractResolution{
Resolution: types.V2FileContractResolution{
Parent: fce,
addEvent(types.Hash256(element.ID), element.MaturityHeight, wallet.EventTypeV2ContractResolution, EventV2ContractResolution{
Resolution: V2FileContractResolution{
Parent: efc,
Type: typ,
Resolution: res,
},
SiacoinElement: element,
SiacoinElement: SiacoinOutput{SiacoinElement: element},
Missed: missed,
}, []types.Address{fce.V2FileContract.RenterOutput.Address})
}
Expand All @@ -253,16 +317,16 @@ func AppliedEvents(cs consensus.State, b types.Block, cu ChainUpdate) (events []
// handle block rewards
for i := range b.MinerPayouts {
element := sces[cs.Index.ID.MinerOutputID(i)]
addEvent(types.Hash256(element.ID), element.MaturityHeight, EventTypeMinerPayout, EventPayout{
SiacoinElement: element,
addEvent(types.Hash256(element.ID), element.MaturityHeight, wallet.EventTypeMinerPayout, EventPayout{
SiacoinElement: SiacoinOutput{SiacoinElement: element},
}, []types.Address{b.MinerPayouts[i].Address})
}

// handle foundation subsidy
element, ok := sces[cs.Index.ID.FoundationOutputID()]
if ok {
addEvent(types.Hash256(element.ID), element.MaturityHeight, EventTypeFoundationSubsidy, EventPayout{
SiacoinElement: element,
addEvent(types.Hash256(element.ID), element.MaturityHeight, wallet.EventTypeFoundationSubsidy, EventPayout{
SiacoinElement: SiacoinOutput{SiacoinElement: element},
}, []types.Address{element.SiacoinOutput.Address})
}

Expand Down
2 changes: 1 addition & 1 deletion internal/testutil/check.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import (
func Equal[T any](t *testing.T, desc string, expect, got T) {
t.Helper()

if !cmp.Equal(expect, got, cmpopts.EquateEmpty(), cmpopts.IgnoreUnexported(consensus.Work{}), cmpopts.IgnoreTypes(types.StateElement{}, "MerkleProof")) {
if !cmp.Equal(expect, got, cmpopts.EquateEmpty(), cmpopts.IgnoreUnexported(consensus.Work{}), cmpopts.IgnoreFields(types.StateElement{}, "MerkleProof")) {
t.Fatalf("%s expected != got, diff: %s", desc, cmp.Diff(expect, got))
}
}
Expand Down
19 changes: 11 additions & 8 deletions persist/sqlite/consensus.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@ import (
"database/sql"
"errors"
"fmt"
"log"
"reflect"
"time"

"go.sia.tech/core/types"
"go.sia.tech/coreutils/chain"
"go.sia.tech/coreutils/wallet"
"go.sia.tech/explored/explorer"
)

Expand Down Expand Up @@ -620,7 +620,7 @@ func addSiafundElements(tx *txn, index types.ChainIndex, spentElements, newEleme
return sfDBIds, nil
}

func addEvents(tx *txn, bid types.BlockID, scDBIds map[types.SiacoinOutputID]int64, sfDBIds map[types.SiafundOutputID]int64, fcDBIds map[explorer.DBFileContract]int64, v2FcDBIds map[explorer.DBFileContract]int64, txnDBIds map[types.TransactionID]txnDBId, v2TxnDBIds map[types.TransactionID]txnDBId, events []wallet.Event) error {
func addEvents(tx *txn, bid types.BlockID, scDBIds map[types.SiacoinOutputID]int64, sfDBIds map[types.SiafundOutputID]int64, fcDBIds map[explorer.DBFileContract]int64, v2FcDBIds map[explorer.DBFileContract]int64, txnDBIds map[types.TransactionID]txnDBId, v2TxnDBIds map[types.TransactionID]txnDBId, events []explorer.Event) error {
if len(events) == 0 {
return nil
}
Expand Down Expand Up @@ -703,21 +703,24 @@ func addEvents(tx *txn, bid types.BlockID, scDBIds map[types.SiacoinOutputID]int
}

switch v := event.Data.(type) {
case wallet.EventV1Transaction:
case explorer.EventV1Transaction:
dbID := txnDBIds[types.TransactionID(event.ID)].id
if _, err = v1TransactionEventStmt.Exec(eventID, dbID); err != nil {
return fmt.Errorf("failed to insert transaction event: %w", err)
}
case wallet.EventV2Transaction:
case explorer.EventV2Transaction:
dbID := v2TxnDBIds[types.TransactionID(event.ID)].id
if _, err = v2TransactionEventStmt.Exec(eventID, dbID); err != nil {
return fmt.Errorf("failed to insert transaction event: %w", err)
}
case wallet.EventPayout:
case explorer.EventPayout:
_, err = payoutEventStmt.Exec(eventID, scDBIds[types.SiacoinOutputID(event.ID)])
case wallet.EventV1ContractResolution:
_, err = v1ContractResolutionEventStmt.Exec(eventID, scDBIds[v.SiacoinElement.ID], fcDBIds[explorer.DBFileContract{ID: v.Parent.ID, RevisionNumber: v.Parent.FileContract.RevisionNumber}], v.Missed)
case wallet.EventV2ContractResolution:
case explorer.EventV1ContractResolution:
ddd := explorer.DBFileContract{ID: v.Parent.ID, RevisionNumber: v.Parent.RevisionNumber}
log.Printf("scDBIDs[%+v] = %v, fcDBIds[%+v] = %d", v.SiacoinElement.ID, scDBIds[v.SiacoinElement.ID], ddd, fcDBIds[ddd])

_, err = v1ContractResolutionEventStmt.Exec(eventID, scDBIds[v.SiacoinElement.ID], fcDBIds[explorer.DBFileContract{ID: v.Parent.ID, RevisionNumber: v.Parent.RevisionNumber}], v.Missed)
case explorer.EventV2ContractResolution:
_, err = v2ContractResolutionEventStmt.Exec(eventID, scDBIds[v.SiacoinElement.ID], v2FcDBIds[explorer.DBFileContract{ID: v.Resolution.Parent.ID, RevisionNumber: v.Resolution.Parent.V2FileContract.RevisionNumber}], v.Missed)
default:
return fmt.Errorf("unknown event type: %T", reflect.TypeOf(event.Data))
Expand Down
Loading

0 comments on commit 134f5ba

Please sign in to comment.