lbcd/claimtrie/node/normalizing_manager.go
2022-05-26 22:04:33 -07:00

118 lines
3.2 KiB
Go

package node
import (
"bytes"
"github.com/lbryio/lbcd/claimtrie/change"
"github.com/lbryio/lbcd/claimtrie/normalization"
"github.com/lbryio/lbcd/claimtrie/param"
)
type NormalizingManager struct { // implements Manager
Manager
normalizedAt int32
}
func NewNormalizingManager(baseManager Manager) Manager {
log.Info(normalization.NormalizeTitle)
return &NormalizingManager{
Manager: baseManager,
normalizedAt: -1,
}
}
func (nm *NormalizingManager) AppendChange(chg change.Change) {
chg.Name = normalization.NormalizeIfNecessary(chg.Name, chg.Height)
nm.Manager.AppendChange(chg)
}
func (nm *NormalizingManager) IncrementHeightTo(height int32, temporary bool) ([][]byte, error) {
nm.addNormalizationForkChangesIfNecessary(height)
return nm.Manager.IncrementHeightTo(height, temporary)
}
func (nm *NormalizingManager) DecrementHeightTo(affectedNames [][]byte, height int32) ([][]byte, error) {
if nm.normalizedAt > height {
nm.normalizedAt = -1
nm.ClearCache()
}
return nm.Manager.DecrementHeightTo(affectedNames, height)
}
func (nm *NormalizingManager) addNormalizationForkChangesIfNecessary(height int32) {
if nm.Manager.Height()+1 != height {
// initialization phase
if height >= param.ActiveParams.NormalizedNameForkHeight {
nm.normalizedAt = param.ActiveParams.NormalizedNameForkHeight // eh, we don't really know that it happened there
}
}
if nm.normalizedAt >= 0 || height != param.ActiveParams.NormalizedNameForkHeight {
return
}
nm.normalizedAt = height
log.Info("Generating necessary changes for the normalization fork...")
// the original code had an unfortunate bug where many unnecessary takeovers
// were triggered at the normalization fork
predicate := func(name []byte) bool {
norm := normalization.Normalize(name)
eq := bytes.Equal(name, norm)
if eq {
return true
}
clone := make([]byte, len(name))
copy(clone, name) // iteration name buffer is reused on future loops
// by loading changes for norm here, you can determine if there will be a conflict
n, err := nm.Manager.NodeAt(nm.Manager.Height(), clone)
if err != nil || n == nil {
return true
}
for _, c := range n.Claims {
nm.Manager.AppendChange(change.Change{
Type: change.AddClaim,
Name: norm,
Height: c.AcceptedAt,
OutPoint: c.OutPoint,
ClaimID: c.ClaimID,
Amount: c.Amount,
ActiveHeight: c.ActiveAt, // necessary to match the old hash
VisibleHeight: height, // necessary to match the old hash; it would have been much better without
})
nm.Manager.AppendChange(change.Change{
Type: change.SpendClaim,
Name: clone,
Height: height,
OutPoint: c.OutPoint,
})
}
for _, c := range n.Supports {
nm.Manager.AppendChange(change.Change{
Type: change.AddSupport,
Name: norm,
Height: c.AcceptedAt,
OutPoint: c.OutPoint,
ClaimID: c.ClaimID,
Amount: c.Amount,
ActiveHeight: c.ActiveAt,
VisibleHeight: height,
})
nm.Manager.AppendChange(change.Change{
Type: change.SpendSupport,
Name: clone,
Height: height,
OutPoint: c.OutPoint,
})
}
return true
}
nm.Manager.ClearCache()
nm.Manager.IterateNames(predicate)
}