optimize collectSpentChildren, add tests for it
This commit is contained in:
parent
88dbf2267c
commit
e8b2910b36
5 changed files with 150 additions and 11 deletions
|
@ -354,6 +354,7 @@ func (ct *ClaimTrie) Close() {
|
||||||
node.LogOnce("On cleanup: " + err.Error())
|
node.LogOnce("On cleanup: " + err.Error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ct.cleanups = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ct *ClaimTrie) forwardNodeChange(chg change.Change) error {
|
func (ct *ClaimTrie) forwardNodeChange(chg change.Change) error {
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
package claimtrie
|
package claimtrie
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"math/rand"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/btcsuite/btcd/claimtrie/change"
|
"github.com/btcsuite/btcd/claimtrie/change"
|
||||||
"github.com/btcsuite/btcd/claimtrie/config"
|
"github.com/btcsuite/btcd/claimtrie/config"
|
||||||
|
@ -252,3 +254,94 @@ func TestRebuild(t *testing.T) {
|
||||||
r.NotNil(m2)
|
r.NotNil(m2)
|
||||||
r.Equal(*m, *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
|
||||||
|
}
|
||||||
|
|
|
@ -145,7 +145,7 @@ func (rt *RamTrie) merkleHashAllClaims(v *collapsedVertex) *chainhash.Hash {
|
||||||
if v.claimHash != nil {
|
if v.claimHash != nil {
|
||||||
claimHash = v.claimHash
|
claimHash = v.claimHash
|
||||||
} else if len(childHashes) == 0 {
|
} else if len(childHashes) == 0 {
|
||||||
return v.merkleHash
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
childHash := NoChildrenHash
|
childHash := NoChildrenHash
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
package node
|
package node
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"container/list"
|
"container/list"
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
@ -199,22 +199,44 @@ func collectChildNames(changes []change.Change) {
|
||||||
// For each non-spend 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
|
// 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 {
|
for i := range changes {
|
||||||
t := changes[i].Type
|
t := changes[i].Type
|
||||||
if t == change.SpendClaim || t == change.SpendSupport {
|
if t == change.SpendClaim || t == change.SpendSupport {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
a := changes[i].Name
|
a := string(changes[i].Name)
|
||||||
sc := map[string]bool{}
|
sc := map[string]bool{}
|
||||||
for j := 0; j < i; j++ {
|
idx := sort.Search(len(spends), func(i int) bool {
|
||||||
t = changes[j].Type
|
return spends[i].name >= a
|
||||||
if t != change.SpendClaim {
|
})
|
||||||
continue
|
for idx < len(spends) {
|
||||||
}
|
b := spends[idx].name
|
||||||
b := changes[j].Name
|
if len(b) >= len(a) && spends[idx].order < i && a == b[:len(a)] {
|
||||||
if len(b) >= len(a) && bytes.Equal(a, b[:len(a)]) {
|
sc[b] = true
|
||||||
sc[string(b)] = true
|
} else {
|
||||||
|
break
|
||||||
}
|
}
|
||||||
|
idx++
|
||||||
}
|
}
|
||||||
changes[i].SpentChildren = sc
|
changes[i].SpentChildren = sc
|
||||||
}
|
}
|
||||||
|
|
|
@ -226,3 +226,26 @@ func TestHasChildren(t *testing.T) {
|
||||||
r.NoError(err)
|
r.NoError(err)
|
||||||
r.True(m.hasChildren([]byte("a"), 4, nil, 2))
|
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"])
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue