Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

all: Update for core changes #65

Merged
merged 1 commit into from
Jun 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ go 1.21.8

require (
go.etcd.io/bbolt v1.3.10
go.sia.tech/core v0.2.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
6 changes: 2 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,8 @@ github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKs
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.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