Skip to content

Commit

Permalink
all: Update for core changes
Browse files Browse the repository at this point in the history
  • Loading branch information
lukechampine committed Jun 27, 2024
1 parent 3285d53 commit 4f37341
Show file tree
Hide file tree
Showing 5 changed files with 69 additions and 76 deletions.
45 changes: 29 additions & 16 deletions chain/db.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
}

Expand All @@ -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
}

Expand All @@ -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
}

Expand Down Expand Up @@ -428,26 +437,28 @@ 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) {
if sfe.LeafIndex == types.EphemeralLeafIndex {
cau.ForEachSiafundElement(func(sfe types.SiafundElement, created, spent bool) {
if created && spent {
return
} else if spent {
db.deleteSiafundElement(types.SiafundOutputID(sfe.ID))
} else {
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 {
Expand All @@ -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)
Expand All @@ -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
Expand All @@ -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
Expand Down
49 changes: 26 additions & 23 deletions chain/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -614,7 +614,7 @@ func updateTxnProofs(txn *types.V2Transaction, updateElementProof func(*types.St
valid = true
updateProof := func(e *types.StateElement) {
valid = valid && e.LeafIndex < numLeaves
if !valid || e.LeafIndex == types.EphemeralLeafIndex {
if !valid || e.LeafIndex == types.UnassignedLeafIndex {
return
}
updateElementProof(e)
Expand All @@ -638,36 +638,37 @@ func updateTxnProofs(txn *types.V2Transaction, updateElementProof func(*types.St
}

func (m *Manager) revertPoolUpdate(cru consensus.RevertUpdate, cs consensus.State) {
// restore ephemeral elements, if necessary
// applying a block can make ephemeral elements in the txpool non-ephemeral;
// here, we undo that
var uncreated map[types.Hash256]bool
replaceEphemeral := func(e *types.StateElement) {
if e.LeafIndex != types.EphemeralLeafIndex {
if e.LeafIndex == types.UnassignedLeafIndex {
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
}
})
}
if uncreated[e.ID] {
*e = types.StateElement{ID: e.ID, LeafIndex: types.EphemeralLeafIndex}
*e = types.StateElement{ID: e.ID, LeafIndex: types.UnassignedLeafIndex}
}
}
for _, txn := range m.txpool.v2txns {
Expand Down Expand Up @@ -695,35 +696,37 @@ func (m *Manager) revertPoolUpdate(cru consensus.RevertUpdate, cs consensus.Stat
}

func (m *Manager) applyPoolUpdate(cau consensus.ApplyUpdate, cs consensus.State) {
// replace ephemeral elements, if necessary
// applying a block can make ephemeral elements in the txpool non-ephemeral
var newElements map[types.Hash256]types.StateElement
replaceEphemeral := func(e *types.StateElement) {
if e.LeafIndex != types.EphemeralLeafIndex {
if e.LeafIndex != types.UnassignedLeafIndex {
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
}
})
}
*e = newElements[e.ID]
if se, ok := newElements[e.ID]; ok {
*e = se
}
}
for _, txn := range m.txpool.v2txns {
for i := range txn.SiacoinInputs {
Expand Down
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ module go.sia.tech/coreutils
go 1.21.8

require (
go.etcd.io/bbolt v1.3.10
go.sia.tech/core v0.2.9
go.etcd.io/bbolt v1.3.9
go.sia.tech/core v0.3.0
go.uber.org/zap v1.27.0
golang.org/x/crypto v0.24.0
lukechampine.com/frand v1.4.2
Expand Down
10 changes: 4 additions & 6 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,10 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
go.etcd.io/bbolt v1.3.10 h1:+BqfJTcCzTItrop8mq/lbzL8wSGtj94UO/3U31shqG0=
go.etcd.io/bbolt v1.3.10/go.mod h1:bK3UQLPJZly7IlNmV7uVHJDxfe5aK9Ll93e/74Y9oEQ=
go.sia.tech/core v0.2.8 h1:NQZw8gz9XWlkw9zr7HrLIA3xQnoatp8lYzyONS0IXJg=
go.sia.tech/core v0.2.8/go.mod h1:BMgT/reXtgv6XbDgUYTCPY7wSMbspDRDs7KMi1vL6Iw=
go.sia.tech/core v0.2.9 h1:UnO+wXQ3w2dMaU3ULA95fLYspllxaYPSfVW08fFIxQU=
go.sia.tech/core v0.2.9/go.mod h1:BMgT/reXtgv6XbDgUYTCPY7wSMbspDRDs7KMi1vL6Iw=
go.etcd.io/bbolt v1.3.9 h1:8x7aARPEXiXbHmtUwAIv7eV2fQFHrLLavdiJ3uzJXoI=
go.etcd.io/bbolt v1.3.9/go.mod h1:zaO32+Ti0PK1ivdPtgMESzuzL2VPoIG1PCQNvOdo/dE=
go.sia.tech/core v0.3.0 h1:PDfAQh9z8PYD+oeVS7rS9SEnTMOZzwwFfAH45yktmko=
go.sia.tech/core v0.3.0/go.mod h1:BMgT/reXtgv6XbDgUYTCPY7wSMbspDRDs7KMi1vL6Iw=
go.sia.tech/mux v1.2.0 h1:ofa1Us9mdymBbGMY2XH/lSpY8itFsKIo/Aq8zwe+GHU=
go.sia.tech/mux v1.2.0/go.mod h1:Yyo6wZelOYTyvrHmJZ6aQfRoer3o4xyKQ4NmQLJrBSo=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
Expand Down
37 changes: 8 additions & 29 deletions wallet/update.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
})

Expand Down Expand Up @@ -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
}
Expand Down Expand Up @@ -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
}
Expand Down Expand Up @@ -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
}
Expand All @@ -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
}

Expand All @@ -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 {
Expand Down

0 comments on commit 4f37341

Please sign in to comment.