refactored EffectiveAmount for performance

This commit is contained in:
Brannon King 2021-07-10 15:35:52 -04:00
parent f829fb6206
commit a0469820a2
6 changed files with 103 additions and 43 deletions

View file

@ -23,6 +23,8 @@ import (
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/wire"
"runtime"
"sort"
)
// ClaimTrie implements a Merkle Trie supporting linear history of commits.
@ -110,18 +112,6 @@ func New(cfg config.Config) (*ClaimTrie, error) {
return nil, fmt.Errorf("load blocks: %w", err)
}
if previousHeight > 0 {
hash, err := blockRepo.Get(previousHeight)
if err != nil {
return nil, fmt.Errorf("get hash: %w", err)
}
_, err = nodeManager.IncrementHeightTo(previousHeight)
if err != nil {
return nil, fmt.Errorf("node manager init: %w", err)
}
trie.SetRoot(hash, nil) // keep this after IncrementHeightTo
}
ct := &ClaimTrie{
blockRepo: blockRepo,
temporalRepo: temporalRepo,
@ -149,6 +139,25 @@ func New(cfg config.Config) (*ClaimTrie, error) {
}
ct.cleanups = cleanups
if previousHeight > 0 {
hash, err := blockRepo.Get(previousHeight)
if err != nil {
ct.Close() // TODO: the cleanups aren't run when we exit with an err above here (but should be)
return nil, fmt.Errorf("get hash: %w", err)
}
_, err = nodeManager.IncrementHeightTo(previousHeight)
if err != nil {
ct.Close()
return nil, fmt.Errorf("node manager init: %w", err)
}
trie.SetRoot(hash, nil) // keep this after IncrementHeightTo
if !ct.MerkleHash().IsEqual(hash) {
ct.Close()
return nil, fmt.Errorf("unable to restore the claim hash to %s at height %d", hash.String(), previousHeight)
}
}
return ct, nil
}

View file

@ -41,8 +41,8 @@ func showClaim(c *node.Claim, n *node.Node) {
mark = "*"
}
fmt.Printf("%s C ID: %s, TXO: %s\n %5d/%-5d, Status: %9s, Amount: %15d, Effective Amount: %15d\n",
mark, c.ClaimID, c.OutPoint, c.AcceptedAt, c.ActiveAt, status[c.Status], c.Amount, c.EffectiveAmount(n.Supports))
fmt.Printf("%s C ID: %s, TXO: %s\n %5d/%-5d, Status: %9s, Amount: %15d, Support Amount: %15d\n",
mark, c.ClaimID, c.OutPoint, c.AcceptedAt, c.ActiveAt, status[c.Status], c.Amount, n.SupportSums[c.ClaimID])
}
func showSupport(c *node.Claim) {

View file

@ -101,23 +101,6 @@ func (c *Claim) setStatus(status Status) *Claim {
return c
}
func (c *Claim) EffectiveAmount(supports ClaimList) int64 {
if c.Status != Activated {
return 0
}
amt := c.Amount
for _, s := range supports {
if s.Status == Activated && s.ClaimID == c.ClaimID { // TODO: this comparison is hit a lot; byte comparison instead of hex would be faster
amt += s.Amount
}
}
return amt
}
func (c *Claim) ExpireAt() int32 {
if c.AcceptedAt+param.OriginalClaimExpirationTime > param.ExtendedClaimExpirationForkHeight {

View file

@ -16,6 +16,7 @@ var (
out1 = NewOutPointFromString("0000000000000000000000000000000000000000000000000000000000000000:1")
out2 = NewOutPointFromString("0000000000000000000000000000000000000000000000000000000000000000:2")
out3 = NewOutPointFromString("0100000000000000000000000000000000000000000000000000000000000000:1")
out4 = NewOutPointFromString("0100000000000000000000000000000000000000000000000000000000000000:2")
name1 = []byte("name1")
name2 = []byte("name2")
)
@ -51,6 +52,7 @@ func TestSimpleAddClaim(t *testing.T) {
m, err := NewBaseManager(repo)
r.NoError(err)
defer m.Close()
_, err = m.IncrementHeightTo(10)
r.NoError(err)
@ -90,6 +92,58 @@ func TestSimpleAddClaim(t *testing.T) {
r.Nil(n2)
}
func TestSupportAmounts(t *testing.T) {
r := require.New(t)
param.SetNetwork(wire.TestNet, "")
repo, err := noderepo.NewPebble(t.TempDir())
r.NoError(err)
m, err := NewBaseManager(repo)
r.NoError(err)
defer m.Close()
_, err = m.IncrementHeightTo(10)
r.NoError(err)
chg := change.New(change.AddClaim).SetName(name1).SetOutPoint(out1.String()).SetHeight(11).SetAmount(3)
chg.ClaimID = NewClaimID(*out1).String()
err = m.AppendChange(chg)
r.NoError(err)
chg = change.New(change.AddClaim).SetName(name1).SetOutPoint(out2.String()).SetHeight(11).SetAmount(4)
chg.ClaimID = NewClaimID(*out2).String()
err = m.AppendChange(chg)
r.NoError(err)
_, err = m.IncrementHeightTo(11)
r.NoError(err)
chg = change.New(change.AddSupport).SetName(name1).SetOutPoint(out3.String()).SetHeight(12).SetAmount(2)
chg.ClaimID = NewClaimID(*out1).String()
err = m.AppendChange(chg)
r.NoError(err)
chg = change.New(change.AddSupport).SetName(name1).SetOutPoint(out4.String()).SetHeight(12).SetAmount(2)
chg.ClaimID = NewClaimID(*out2).String()
err = m.AppendChange(chg)
r.NoError(err)
chg = change.New(change.SpendSupport).SetName(name1).SetOutPoint(out4.String()).SetHeight(12).SetAmount(2)
chg.ClaimID = NewClaimID(*out2).String()
err = m.AppendChange(chg)
r.NoError(err)
_, err = m.IncrementHeightTo(20)
r.NoError(err)
n1, err := m.Node(name1)
r.NoError(err)
r.Equal(2, len(n1.Claims))
r.Equal(int64(5), n1.BestClaim.Amount+n1.SupportSums[n1.BestClaim.ClaimID])
}
func TestNodeSort(t *testing.T) {
r := require.New(t)

View file

@ -17,11 +17,12 @@ type Node struct {
TakenOverAt int32 // The height at when the current BestClaim took over.
Claims ClaimList // List of all Claims.
Supports ClaimList // List of all Supports, including orphaned ones.
SupportSums map[string]int64
}
// New returns a new node.
func New() *Node {
return &Node{}
return &Node{SupportSums: map[string]int64{}}
}
func (n *Node) ApplyChange(chg change.Change, delay int32) error {
@ -94,6 +95,12 @@ func (n *Node) ApplyChange(chg change.Change, delay int32) error {
case change.SpendSupport:
s := n.Supports.find(byOut(*out))
if s != nil {
if s.Status == Activated {
n.SupportSums[s.ClaimID] -= s.Amount
}
// TODO: we could do without this Deactivated flag if we set expiration instead
// That would eliminate the above Sum update.
// We would also need to track the update situation, though, but that could be done locally.
s.setStatus(Deactivated)
} else {
fmt.Printf("Spending support but missing existing support with TXO %s\n "+
@ -151,12 +158,15 @@ func (n *Node) updateTakeoverHeight(height int32, name []byte, refindBest bool)
func (n *Node) handleExpiredAndActivated(height int32) int {
changes := 0
update := func(items ClaimList) ClaimList {
update := func(items ClaimList, sums map[string]int64) ClaimList {
for i := 0; i < len(items); i++ {
c := items[i]
if c.Status == Accepted && c.ActiveAt <= height && c.VisibleAt <= height {
c.setStatus(Activated)
changes++
if sums != nil {
sums[c.ClaimID] += c.Amount
}
}
if c.ExpireAt() <= height || c.Status == Deactivated {
if i < len(items)-1 {
@ -165,12 +175,15 @@ func (n *Node) handleExpiredAndActivated(height int32) int {
}
items = items[:len(items)-1]
changes++
if sums != nil && c.Status != Deactivated {
sums[c.ClaimID] -= c.Amount
}
}
}
return items
}
n.Claims = update(n.Claims)
n.Supports = update(n.Supports)
n.Claims = update(n.Claims, nil)
n.Supports = update(n.Supports, n.SupportSums)
return changes
}
@ -234,9 +247,9 @@ func (n Node) findBestClaim() *Claim {
continue
}
candidateAmount := candidate.EffectiveAmount(n.Supports)
if bestAmount <= 0 { // trying to reduce calls to EffectiveAmount
bestAmount = best.EffectiveAmount(n.Supports)
candidateAmount := candidate.Amount + n.SupportSums[candidate.ClaimID]
if bestAmount <= 0 {
bestAmount = best.Amount + n.SupportSums[best.ClaimID]
}
switch {
@ -263,7 +276,7 @@ func (n *Node) activateAllClaims(height int32) int {
count := 0
for _, c := range n.Claims {
if c.Status == Accepted && c.ActiveAt > height && c.VisibleAt <= height {
c.setActiveAt(height) // don't necessary need to change this number
c.setActiveAt(height) // don't necessarily need to change this number?
c.setStatus(Activated)
count++
}
@ -271,9 +284,10 @@ func (n *Node) activateAllClaims(height int32) int {
for _, s := range n.Supports {
if s.Status == Accepted && s.ActiveAt > height && s.VisibleAt <= height {
s.setActiveAt(height) // don't necessary need to change this number
s.setActiveAt(height) // don't necessarily need to change this number?
s.setStatus(Activated)
count++
n.SupportSums[s.ClaimID] += s.Amount
}
}
return count
@ -283,8 +297,8 @@ func (n *Node) SortClaims() {
// purposefully sorting by descent
sort.Slice(n.Claims, func(j, i int) bool {
iAmount := n.Claims[i].EffectiveAmount(n.Supports)
jAmount := n.Claims[j].EffectiveAmount(n.Supports)
iAmount := n.Claims[i].Amount + n.SupportSums[n.Claims[i].ClaimID]
jAmount := n.Claims[j].Amount + n.SupportSums[n.Claims[j].ClaimID]
switch {
case iAmount < jAmount:
return true

View file

@ -15,7 +15,7 @@ type Pebble struct {
func NewPebble(path string) (*Pebble, error) {
db, err := pebble.Open(path, &pebble.Options{Cache: pebble.NewCache(128 << 20), BytesPerSync: 16 << 20})
db, err := pebble.Open(path, &pebble.Options{Cache: pebble.NewCache(256 << 20), BytesPerSync: 16 << 20})
if err != nil {
return nil, fmt.Errorf("pebble open %s, %w", path, err)
}