optimize collectSpentChildren, add tests for it

This commit is contained in:
Brannon King 2021-07-28 14:40:21 -04:00 committed by Roy Lee
parent 88dbf2267c
commit e8b2910b36
5 changed files with 150 additions and 11 deletions

View file

@ -354,6 +354,7 @@ func (ct *ClaimTrie) Close() {
node.LogOnce("On cleanup: " + err.Error())
}
}
ct.cleanups = nil
}
func (ct *ClaimTrie) forwardNodeChange(chg change.Change) error {

View file

@ -1,7 +1,9 @@
package claimtrie
import (
"math/rand"
"testing"
"time"
"github.com/btcsuite/btcd/claimtrie/change"
"github.com/btcsuite/btcd/claimtrie/config"
@ -252,3 +254,94 @@ func TestRebuild(t *testing.T) {
r.NotNil(m2)
r.Equal(*m, *m2)
}
func BenchmarkClaimTrie_AppendBlock(b *testing.B) {
rand.Seed(42)
names := make([][]byte, 0, b.N)
for i := 0; i < b.N; i++ {
names = append(names, randomName())
}
param.SetNetwork(wire.TestNet)
param.OriginalClaimExpirationTime = 1000000
param.ExtendedClaimExpirationTime = 1000000
cfg.DataDir = b.TempDir()
r := require.New(b)
ct, err := New(cfg)
r.NoError(err)
defer ct.Close()
h1 := chainhash.Hash{100, 200}
start := time.Now()
b.ResetTimer()
c := 0
for i := 0; i < b.N; i++ {
op := wire.OutPoint{Hash: h1, Index: uint32(i)}
id := change.NewClaimID(op)
err = ct.AddClaim(names[i], op, id, 500)
r.NoError(err)
if c++; (c & 0xff) == 0xff {
err = ct.AppendBlock()
r.NoError(err)
}
}
for i := 0; i < b.N; i++ {
op := wire.OutPoint{Hash: h1, Index: uint32(i)}
id := change.NewClaimID(op)
op.Hash[0] = 1
err = ct.UpdateClaim(names[i], op, 400, id)
r.NoError(err)
if c++; (c & 0xff) == 0xff {
err = ct.AppendBlock()
r.NoError(err)
}
}
for i := 0; i < b.N; i++ {
op := wire.OutPoint{Hash: h1, Index: uint32(i)}
id := change.NewClaimID(op)
op.Hash[0] = 2
err = ct.UpdateClaim(names[i], op, 300, id)
r.NoError(err)
if c++; (c & 0xff) == 0xff {
err = ct.AppendBlock()
r.NoError(err)
}
}
for i := 0; i < b.N; i++ {
op := wire.OutPoint{Hash: h1, Index: uint32(i)}
id := change.NewClaimID(op)
op.Hash[0] = 3
err = ct.SpendClaim(names[i], op, id)
r.NoError(err)
if c++; (c & 0xff) == 0xff {
err = ct.AppendBlock()
r.NoError(err)
}
}
err = ct.AppendBlock()
r.NoError(err)
b.StopTimer()
ht := ct.height
h1 = *ct.MerkleHash()
ct.Close()
b.Logf("Running AppendBlock bench with %d names in %f sec. Height: %d, Hash: %s",
b.N, time.Since(start).Seconds(), ht, h1.String())
}
func randomName() []byte {
name := make([]byte, rand.Intn(30)+10)
rand.Read(name)
for i := range name {
name[i] %= 56
name[i] += 65
}
return name
}

View file

@ -145,7 +145,7 @@ func (rt *RamTrie) merkleHashAllClaims(v *collapsedVertex) *chainhash.Hash {
if v.claimHash != nil {
claimHash = v.claimHash
} else if len(childHashes) == 0 {
return v.merkleHash
return nil
}
childHash := NoChildrenHash

View file

@ -1,11 +1,11 @@
package node
import (
"bytes"
"container/list"
"crypto/sha256"
"encoding/binary"
"fmt"
"sort"
"strconv"
"github.com/pkg/errors"
@ -199,22 +199,44 @@ func collectChildNames(changes []change.Change) {
// For each non-spend change
// Loop through all the spends before you and add them to your child list if they are your child
type pair struct {
name string
order int
}
spends := make([]pair, 0, len(changes))
for i := range changes {
t := changes[i].Type
if t != change.SpendClaim {
continue
}
spends = append(spends, pair{string(changes[i].Name), i})
}
sort.Slice(spends, func(i, j int) bool {
if spends[i].name == spends[j].name {
return spends[i].order < spends[j].order
}
return spends[i].name < spends[j].name
})
for i := range changes {
t := changes[i].Type
if t == change.SpendClaim || t == change.SpendSupport {
continue
}
a := changes[i].Name
a := string(changes[i].Name)
sc := map[string]bool{}
for j := 0; j < i; j++ {
t = changes[j].Type
if t != change.SpendClaim {
continue
}
b := changes[j].Name
if len(b) >= len(a) && bytes.Equal(a, b[:len(a)]) {
sc[string(b)] = true
idx := sort.Search(len(spends), func(i int) bool {
return spends[i].name >= a
})
for idx < len(spends) {
b := spends[idx].name
if len(b) >= len(a) && spends[idx].order < i && a == b[:len(a)] {
sc[b] = true
} else {
break
}
idx++
}
changes[i].SpentChildren = sc
}

View file

@ -226,3 +226,26 @@ func TestHasChildren(t *testing.T) {
r.NoError(err)
r.True(m.hasChildren([]byte("a"), 4, nil, 2))
}
func TestCollectChildren(t *testing.T) {
r := require.New(t)
c1 := change.Change{Name: []byte("ba"), Type: change.SpendClaim}
c2 := change.Change{Name: []byte("ba"), Type: change.UpdateClaim}
c3 := change.Change{Name: []byte("ac"), Type: change.SpendClaim}
c4 := change.Change{Name: []byte("ac"), Type: change.UpdateClaim}
c5 := change.Change{Name: []byte("a"), Type: change.SpendClaim}
c6 := change.Change{Name: []byte("a"), Type: change.UpdateClaim}
c := []change.Change{c1, c2, c3, c4, c5, c6}
collectChildNames(c)
r.Empty(c[0].SpentChildren)
r.Empty(c[2].SpentChildren)
r.Empty(c[4].SpentChildren)
r.Len(c[1].SpentChildren, 1)
r.Len(c[3].SpentChildren, 1)
r.Len(c[5].SpentChildren, 2)
r.True(c[5].SpentChildren["ac"])
}