From 9073e2937fa61e3fbf2d2ab6c4f3faa067df2d2b Mon Sep 17 00:00:00 2001 From: lukechampine Date: Tue, 25 Jun 2024 23:33:56 -0400 Subject: [PATCH] all: Update for core changes --- chain/db.go | 43 ++++++++++++++++++++++++++++--------------- chain/manager.go | 32 ++++++++++++++++---------------- wallet/update.go | 37 ++++++++----------------------------- 3 files changed, 52 insertions(+), 60 deletions(-) diff --git a/chain/db.go b/chain/db.go index 55035ac..5353993 100644 --- a/chain/db.go +++ b/chain/db.go @@ -331,6 +331,9 @@ func (db *DBStore) treeKey(row, col uint64) []byte { } func (db *DBStore) getElementProof(leafIndex, numLeaves uint64) (proof []types.Hash256) { + if leafIndex >= numLeaves { + panic(fmt.Sprintf("leafIndex %v exceeds accumulator size %v", leafIndex, numLeaves)) // should never happen + } // The size of the proof is the mergeHeight of leafIndex and numLeaves. To // see why, imagine a tree large enough to contain both leafIndex and // numLeaves within the same subtree; the height at which the paths to those @@ -348,7 +351,9 @@ func (db *DBStore) getElementProof(leafIndex, numLeaves uint64) (proof []types.H func (db *DBStore) getSiacoinElement(id types.SiacoinOutputID, numLeaves uint64) (sce types.SiacoinElement, ok bool) { ok = db.bucket(bSiacoinElements).get(id[:], &sce) - sce.MerkleProof = db.getElementProof(sce.LeafIndex, numLeaves) + if ok { + sce.MerkleProof = db.getElementProof(sce.LeafIndex, numLeaves) + } return } @@ -363,7 +368,9 @@ func (db *DBStore) deleteSiacoinElement(id types.SiacoinOutputID) { func (db *DBStore) getSiafundElement(id types.SiafundOutputID, numLeaves uint64) (sfe types.SiafundElement, ok bool) { ok = db.bucket(bSiafundElements).get(id[:], &sfe) - sfe.MerkleProof = db.getElementProof(sfe.LeafIndex, numLeaves) + if ok { + sfe.MerkleProof = db.getElementProof(sfe.LeafIndex, numLeaves) + } return } @@ -378,7 +385,9 @@ func (db *DBStore) deleteSiafundElement(id types.SiafundOutputID) { func (db *DBStore) getFileContractElement(id types.FileContractID, numLeaves uint64) (fce types.FileContractElement, ok bool) { ok = db.bucket(bFileContractElements).get(id[:], &fce) - fce.MerkleProof = db.getElementProof(fce.LeafIndex, numLeaves) + if ok { + fce.MerkleProof = db.getElementProof(fce.LeafIndex, numLeaves) + } return } @@ -428,16 +437,16 @@ func (db *DBStore) applyElements(cau consensus.ApplyUpdate) { db.bucket(bTree).put(db.treeKey(row, col), h) }) - cau.ForEachSiacoinElement(func(sce types.SiacoinElement, spent bool) { - if sce.LeafIndex == types.EphemeralLeafIndex { - return + cau.ForEachSiacoinElement(func(sce types.SiacoinElement, created, spent bool) { + if created && spent { + return // ephemeral } else if spent { db.deleteSiacoinElement(types.SiacoinOutputID(sce.ID)) } else { db.putSiacoinElement(sce) } }) - cau.ForEachSiafundElement(func(sfe types.SiafundElement, spent bool) { + cau.ForEachSiafundElement(func(sfe types.SiafundElement, created, spent bool) { if sfe.LeafIndex == types.EphemeralLeafIndex { return } else if spent { @@ -446,8 +455,10 @@ func (db *DBStore) applyElements(cau consensus.ApplyUpdate) { db.putSiafundElement(sfe) } }) - cau.ForEachFileContractElement(func(fce types.FileContractElement, rev *types.FileContractElement, resolved, valid bool) { - if resolved { + cau.ForEachFileContractElement(func(fce types.FileContractElement, created bool, rev *types.FileContractElement, resolved, valid bool) { + if created && resolved { + return + } else if resolved { db.deleteFileContractElement(types.FileContractID(fce.ID)) db.deleteFileContractExpiration(types.FileContractID(fce.ID), fce.FileContract.WindowEnd) } else if rev != nil { @@ -464,8 +475,10 @@ func (db *DBStore) applyElements(cau consensus.ApplyUpdate) { } func (db *DBStore) revertElements(cru consensus.RevertUpdate) { - cru.ForEachFileContractElement(func(fce types.FileContractElement, rev *types.FileContractElement, resolved, valid bool) { - if resolved { + cru.ForEachFileContractElement(func(fce types.FileContractElement, created bool, rev *types.FileContractElement, resolved, valid bool) { + if created && resolved { + return + } else if resolved { // contract no longer resolved; restore it db.putFileContractElement(fce) db.putFileContractExpiration(types.FileContractID(fce.ID), fce.FileContract.WindowEnd) @@ -482,8 +495,8 @@ func (db *DBStore) revertElements(cru consensus.RevertUpdate) { db.deleteFileContractExpiration(types.FileContractID(fce.ID), fce.FileContract.WindowEnd) } }) - cru.ForEachSiafundElement(func(sfe types.SiafundElement, spent bool) { - if sfe.LeafIndex == types.EphemeralLeafIndex { + cru.ForEachSiafundElement(func(sfe types.SiafundElement, created, spent bool) { + if created && spent { return } else if spent { // output no longer spent; restore it @@ -493,8 +506,8 @@ func (db *DBStore) revertElements(cru consensus.RevertUpdate) { db.deleteSiafundElement(types.SiafundOutputID(sfe.ID)) } }) - cru.ForEachSiacoinElement(func(sce types.SiacoinElement, spent bool) { - if sce.LeafIndex == types.EphemeralLeafIndex { + cru.ForEachSiacoinElement(func(sce types.SiacoinElement, created, spent bool) { + if created && spent { return } else if spent { // output no longer spent; restore it diff --git a/chain/manager.go b/chain/manager.go index f89a1c6..c7f4559 100644 --- a/chain/manager.go +++ b/chain/manager.go @@ -645,23 +645,23 @@ func (m *Manager) revertPoolUpdate(cru consensus.RevertUpdate, cs consensus.Stat return } else if uncreated == nil { uncreated = make(map[types.Hash256]bool) - cru.ForEachSiacoinElement(func(sce types.SiacoinElement, spent bool) { - if !spent { + cru.ForEachSiacoinElement(func(sce types.SiacoinElement, created, spent bool) { + if created { uncreated[sce.ID] = true } }) - cru.ForEachSiafundElement(func(sfe types.SiafundElement, spent bool) { - if !spent { + cru.ForEachSiafundElement(func(sfe types.SiafundElement, created, spent bool) { + if created { uncreated[sfe.ID] = true } }) - cru.ForEachFileContractElement(func(fce types.FileContractElement, rev *types.FileContractElement, resolved, valid bool) { - if !resolved { + cru.ForEachFileContractElement(func(fce types.FileContractElement, created bool, rev *types.FileContractElement, resolved, valid bool) { + if created { uncreated[fce.ID] = true } }) - cru.ForEachV2FileContractElement(func(fce types.V2FileContractElement, rev *types.V2FileContractElement, res types.V2FileContractResolutionType) { - if res != nil { + cru.ForEachV2FileContractElement(func(fce types.V2FileContractElement, created bool, rev *types.V2FileContractElement, res types.V2FileContractResolutionType) { + if created { uncreated[fce.ID] = true } }) @@ -702,23 +702,23 @@ func (m *Manager) applyPoolUpdate(cau consensus.ApplyUpdate, cs consensus.State) return } else if newElements == nil { newElements = make(map[types.Hash256]types.StateElement) - cau.ForEachSiacoinElement(func(sce types.SiacoinElement, spent bool) { - if !spent { + cau.ForEachSiacoinElement(func(sce types.SiacoinElement, created, spent bool) { + if created { newElements[sce.ID] = sce.StateElement } }) - cau.ForEachSiafundElement(func(sfe types.SiafundElement, spent bool) { - if !spent { + cau.ForEachSiafundElement(func(sfe types.SiafundElement, created, spent bool) { + if created { newElements[sfe.ID] = sfe.StateElement } }) - cau.ForEachFileContractElement(func(fce types.FileContractElement, rev *types.FileContractElement, resolved, valid bool) { - if !resolved { + cau.ForEachFileContractElement(func(fce types.FileContractElement, created bool, rev *types.FileContractElement, resolved, valid bool) { + if created { newElements[fce.ID] = fce.StateElement } }) - cau.ForEachV2FileContractElement(func(fce types.V2FileContractElement, rev *types.V2FileContractElement, res types.V2FileContractResolutionType) { - if res != nil { + cau.ForEachV2FileContractElement(func(fce types.V2FileContractElement, created bool, rev *types.V2FileContractElement, res types.V2FileContractResolutionType) { + if created { newElements[fce.ID] = fce.StateElement } }) diff --git a/wallet/update.go b/wallet/update.go index 18e59dd..f4d39cf 100644 --- a/wallet/update.go +++ b/wallet/update.go @@ -55,7 +55,7 @@ func appliedEvents(cau chain.ApplyUpdate, walletAddress types.Address) (events [ siacoinElements := make(map[types.SiacoinOutputID]types.SiacoinElement) // cache the value of siacoin elements to use when calculating v1 outflow - cau.ForEachSiacoinElement(func(se types.SiacoinElement, spent bool) { + cau.ForEachSiacoinElement(func(se types.SiacoinElement, created, spent bool) { siacoinElements[types.SiacoinOutputID(se.ID)] = se }) @@ -187,7 +187,8 @@ func appliedEvents(cau chain.ApplyUpdate, walletAddress types.Address) (events [ addEvent(types.Hash256(txn.ID()), EventTypeV2Transaction, EventV2Transaction(txn)) } - cau.ForEachFileContractElement(func(fce types.FileContractElement, rev *types.FileContractElement, resolved bool, valid bool) { + // add the file contract outputs + cau.ForEachFileContractElement(func(fce types.FileContractElement, created bool, rev *types.FileContractElement, resolved bool, valid bool) { if !resolved { return } @@ -221,7 +222,7 @@ func appliedEvents(cau chain.ApplyUpdate, walletAddress types.Address) (events [ } }) - cau.ForEachV2FileContractElement(func(fce types.V2FileContractElement, rev *types.V2FileContractElement, res types.V2FileContractResolutionType) { + cau.ForEachV2FileContractElement(func(fce types.V2FileContractElement, created bool, rev *types.V2FileContractElement, res types.V2FileContractResolutionType) { if res == nil { return } @@ -287,31 +288,10 @@ func applyChainState(tx UpdateTx, address types.Address, cau chain.ApplyUpdate) return fmt.Errorf("failed to get state elements: %w", err) } - // determine which siacoin and siafund elements are ephemeral - // - // note: I thought we could use LeafIndex == EphemeralLeafIndex, but - // it seems to be set before the subscriber is called. - created := make(map[types.Hash256]bool) - ephemeral := make(map[types.Hash256]bool) - for _, txn := range cau.Block.Transactions { - for i := range txn.SiacoinOutputs { - created[types.Hash256(txn.SiacoinOutputID(i))] = true - } - for _, input := range txn.SiacoinInputs { - ephemeral[types.Hash256(input.ParentID)] = created[types.Hash256(input.ParentID)] - } - for i := range txn.SiafundOutputs { - created[types.Hash256(txn.SiafundOutputID(i))] = true - } - for _, input := range txn.SiafundInputs { - ephemeral[types.Hash256(input.ParentID)] = created[types.Hash256(input.ParentID)] - } - } - var createdUTXOs, spentUTXOs []types.SiacoinElement utxoValues := make(map[types.SiacoinOutputID]types.Currency) - cau.ForEachSiacoinElement(func(se types.SiacoinElement, spent bool) { + cau.ForEachSiacoinElement(func(se types.SiacoinElement, created, spent bool) { if se.SiacoinOutput.Address != address { return } @@ -320,7 +300,7 @@ func applyChainState(tx UpdateTx, address types.Address, cau chain.ApplyUpdate) utxoValues[types.SiacoinOutputID(se.ID)] = se.SiacoinOutput.Value // ignore ephemeral elements - if ephemeral[se.ID] { + if created && spent { return } @@ -346,11 +326,10 @@ func applyChainState(tx UpdateTx, address types.Address, cau chain.ApplyUpdate) // revertChainUpdate atomically reverts a chain update from a wallet func revertChainUpdate(tx UpdateTx, revertedIndex types.ChainIndex, address types.Address, cru chain.RevertUpdate) error { var removedUTXOs, unspentUTXOs []types.SiacoinElement - cru.ForEachSiacoinElement(func(se types.SiacoinElement, spent bool) { - if se.SiacoinOutput.Address != address { + cru.ForEachSiacoinElement(func(se types.SiacoinElement, created, spent bool) { + if se.SiacoinOutput.Address != address || (created && spent) { return } - if spent { unspentUTXOs = append(unspentUTXOs, se) } else {