diff --git a/claim/claim.go b/claim/claim.go index ca617bf..2e2bfc0 100644 --- a/claim/claim.go +++ b/claim/claim.go @@ -47,7 +47,8 @@ func (c *Claim) expireAt() Height { return c.Accepted + paramOriginalClaimExpirationTime } -func isActiveAt(c *Claim, ht Height) bool { +// IsActiveAt ... +func IsActiveAt(c *Claim, ht Height) bool { return c != nil && c.ActiveAt <= ht && c.expireAt() > ht } diff --git a/claim/list.go b/claim/list.go index c9f1728..e7ee437 100644 --- a/claim/list.go +++ b/claim/list.go @@ -1,22 +1,22 @@ package claim -type list []*Claim +type List []*Claim -type comparator func(c *Claim) bool +type Comparator func(c *Claim) bool -func byOP(op OutPoint) comparator { +func ByOP(op OutPoint) Comparator { return func(c *Claim) bool { return c.OutPoint == op } } -func byID(id ID) comparator { +func ByID(id ID) Comparator { return func(c *Claim) bool { return c.ID == id } } -func remove(l list, cmp comparator) (list, *Claim) { +func Remove(l List, cmp Comparator) (List, *Claim) { last := len(l) - 1 for i, v := range l { if !cmp(v) { @@ -30,7 +30,7 @@ func remove(l list, cmp comparator) (list, *Claim) { return l, nil } -func find(cmp comparator, lists ...list) *Claim { +func Find(cmp Comparator, lists ...List) *Claim { for _, l := range lists { for _, v := range l { if cmp(v) { diff --git a/claim/node.go b/claim/node.go index 6c3114a..d37b718 100644 --- a/claim/node.go +++ b/claim/node.go @@ -16,11 +16,11 @@ type Node struct { best *Claim tookover Height - claims list - supports list + claims List + supports List // refer to updateClaim. - removed list + removed List } // NewNode returns a new Node. @@ -28,6 +28,11 @@ func NewNode(name string) *Node { return &Node{name: name} } +// Name returns the Name where the Node blongs. +func (n *Node) Name() string { + return n.name +} + // Height returns the current height. func (n *Node) Height() Height { return n.height @@ -38,15 +43,30 @@ func (n *Node) BestClaim() *Claim { return n.best } +// Tookover returns the the height at when the current BestClaim tookover. +func (n *Node) Tookover() Height { + return n.tookover +} + +// Claims returns the claims at the current height. +func (n *Node) Claims() List { + return n.claims +} + +// Supports returns the supports at the current height. +func (n *Node) Supports() List { + return n.supports +} + // AddClaim adds a Claim to the Node. -func (n *Node) AddClaim(op OutPoint, amt Amount) error { - if find(byOP(op), n.claims, n.supports) != nil { +func (n *Node) AddClaim(op OutPoint, amt Amount, val []byte) error { + if Find(ByOP(op), n.claims, n.supports) != nil { return ErrDuplicate } accepted := n.height + 1 - c := New(op, amt).setID(NewID(op)).setAccepted(accepted) + c := New(op, amt).setID(NewID(op)).setAccepted(accepted).setValue(val) c.setActiveAt(accepted + calDelay(accepted, n.tookover)) - if !isActiveAt(n.best, accepted) { + if !IsActiveAt(n.best, accepted) { c.setActiveAt(accepted) n.best, n.tookover = c, accepted } @@ -57,7 +77,7 @@ func (n *Node) AddClaim(op OutPoint, amt Amount) error { // SpendClaim spends a Claim in the Node. func (n *Node) SpendClaim(op OutPoint) error { var c *Claim - if n.claims, c = remove(n.claims, byOP(op)); c == nil { + if n.claims, c = Remove(n.claims, ByOP(op)); c == nil { return ErrNotFound } n.removed = append(n.removed, c) @@ -74,17 +94,17 @@ func (n *Node) SpendClaim(op OutPoint) error { // // For each block, all the spent claims are kept in n.removed until committed. // The paired (spend, update) commands has to happen in the same trasaction. -func (n *Node) UpdateClaim(op OutPoint, amt Amount, id ID) error { - if find(byOP(op), n.claims, n.supports) != nil { +func (n *Node) UpdateClaim(op OutPoint, amt Amount, id ID, val []byte) error { + if Find(ByOP(op), n.claims, n.supports) != nil { return ErrDuplicate } var c *Claim - if n.removed, c = remove(n.removed, byID(id)); c == nil { + if n.removed, c = Remove(n.removed, ByID(id)); c == nil { return errors.Wrapf(ErrNotFound, "remove(n.removed, byID(%s)", id) } accepted := n.height + 1 - c.setOutPoint(op).setAmt(amt).setAccepted(accepted) + c.setOutPoint(op).setAmt(amt).setAccepted(accepted).setValue(val) c.setActiveAt(accepted + calDelay(accepted, n.tookover)) if n.best != nil && n.best.ID == id { c.setActiveAt(n.tookover) @@ -95,12 +115,12 @@ func (n *Node) UpdateClaim(op OutPoint, amt Amount, id ID) error { // AddSupport adds a Support to the Node. func (n *Node) AddSupport(op OutPoint, amt Amount, id ID) error { - if find(byOP(op), n.claims, n.supports) != nil { + if Find(ByOP(op), n.claims, n.supports) != nil { return ErrDuplicate } // Accepted by rules. No effects on bidding result though. // It may be spent later. - if find(byID(id), n.claims, n.removed) == nil { + if Find(ByID(id), n.claims, n.removed) == nil { // fmt.Printf("INFO: can't find suooported claim ID: %s for %s\n", id, n.name) } @@ -117,7 +137,7 @@ func (n *Node) AddSupport(op OutPoint, amt Amount, id ID) error { // SpendSupport spends a support in the Node. func (n *Node) SpendSupport(op OutPoint) error { var s *Claim - if n.supports, s = remove(n.supports, byOP(op)); s != nil { + if n.supports, s = Remove(n.supports, ByOP(op)); s != nil { return nil } return ErrNotFound @@ -147,7 +167,7 @@ func (n *Node) AdjustTo(ht Height) *Node { // When no pending updates exist, current height is returned. func (n *Node) NextUpdate() Height { next := Height(math.MaxInt32) - min := func(l list) Height { + min := func(l List) Height { for _, v := range l { exp := v.expireAt() if n.height >= exp { @@ -187,15 +207,15 @@ func (n *Node) bid() { n.removed = nil } -func updateEffectiveAmounts(ht Height, claims, supports list) { +func updateEffectiveAmounts(ht Height, claims, supports List) { for _, c := range claims { c.EffAmt = 0 - if !isActiveAt(c, ht) { + if !IsActiveAt(c, ht) { continue } c.EffAmt = c.Amt for _, s := range supports { - if !isActiveAt(s, ht) || s.ID != c.ID { + if !IsActiveAt(s, ht) || s.ID != c.ID { continue } c.EffAmt += s.Amt @@ -203,7 +223,7 @@ func updateEffectiveAmounts(ht Height, claims, supports list) { } } -func updateActiveHeights(n *Node, lists ...list) { +func updateActiveHeights(n *Node, lists ...List) { for _, l := range lists { for _, v := range l { v.ActiveAt = v.Accepted + calDelay(n.height, n.tookover) @@ -211,11 +231,11 @@ func updateActiveHeights(n *Node, lists ...list) { } } -func findCandiadte(ht Height, claims list) *Claim { +func findCandiadte(ht Height, claims List) *Claim { var c *Claim for _, v := range claims { switch { - case !isActiveAt(v, ht): + case !IsActiveAt(v, ht): continue case c == nil: c = v diff --git a/claim/ui.go b/claim/ui.go index 526f259..720f017 100644 --- a/claim/ui.go +++ b/claim/ui.go @@ -17,8 +17,8 @@ func export(n *Node) interface{} { Tookover Height NextUpdate Height BestClaim *Claim - Claims list - Supports list + Claims List + Supports List }{ Height: n.height, Hash: hash, diff --git a/claimtrie.go b/claimtrie.go index 3156864..f1f52db 100644 --- a/claimtrie.go +++ b/claimtrie.go @@ -3,6 +3,7 @@ package claimtrie import ( "fmt" + "github.com/lbryio/claimtrie/cfg" "github.com/lbryio/claimtrie/change" "github.com/lbryio/claimtrie/claim" "github.com/lbryio/claimtrie/nodemgr" @@ -18,41 +19,71 @@ type ClaimTrie struct { cm *CommitMgr nm *nodemgr.NodeMgr tr *trie.Trie + + cleanup func() error } // New returns a ClaimTrie. -func New(dbCommit, dbTrie, dbNodeMgr *leveldb.DB) *ClaimTrie { - nm := nodemgr.New(dbNodeMgr) - cm := NewCommitMgr(dbCommit) +func New() (*ClaimTrie, error) { + path := cfg.DefaultConfig(cfg.TrieDB) + dbTrie, err := leveldb.OpenFile(path, nil) + if err != nil { + return nil, errors.Wrapf(err, "can't open %s", path) + } - return &ClaimTrie{ + path = cfg.DefaultConfig(cfg.NodeDB) + dbNodeMgr, err := leveldb.OpenFile(path, nil) + if err != nil { + return nil, errors.Wrapf(err, "can't open %s", path) + } + + path = cfg.DefaultConfig(cfg.CommitDB) + dbCommit, err := leveldb.OpenFile(path, nil) + if err != nil { + return nil, errors.Wrapf(err, "can't open %s", path) + } + + cm := NewCommitMgr(dbCommit) + if err := cm.Load(); err != nil { + return nil, errors.Wrapf(err, "cm.Load()") + } + fmt.Printf("%d of commits loaded. Head: %d\n", len(cm.commits), cm.head.Meta.Height) + + nm := nodemgr.New(dbNodeMgr) + nm.Load(cm.head.Meta.Height) + fmt.Printf("%d of nodes loaded.\n", nm.Size()) + + tr := trie.New(nm, dbTrie) + tr.SetRoot(cm.Head().MerkleRoot) + fmt.Printf("ClaimTrie Root: %s.\n", tr.MerkleHash()) + + ct := &ClaimTrie{ cm: cm, nm: nm, - tr: trie.New(nm, dbTrie), + tr: tr, + + cleanup: func() error { + if err := cm.Save(); err != nil { + return errors.Wrapf(err, "cm.Save()") + } + if err := dbTrie.Close(); err != nil { + return errors.Wrapf(err, "dbTrie.Close()") + } + if err := dbNodeMgr.Close(); err != nil { + return errors.Wrapf(err, "dbNodeMgr.Close()") + } + if err := dbCommit.Close(); err != nil { + return errors.Wrapf(err, "dbCommit.Close()") + } + return nil + }, } + return ct, nil } -// Load loads ClaimTrie, NodeManager, Trie from databases. -func (ct *ClaimTrie) Load() error { - if err := ct.cm.Load(); err != nil { - return errors.Wrapf(err, "cm.Load()") - } - fmt.Printf("%d of commits loaded. Head: %d\n", len(ct.cm.commits), ct.cm.head.Meta.Height) - - ct.nm.Load(ct.Height()) - fmt.Printf("%d of nodes loaded.\n", ct.nm.Size()) - - ct.tr.SetRoot(ct.cm.Head().MerkleRoot) - fmt.Printf("Trie root: %s.\n", ct.MerkleHash()) - return nil -} - -// Save saves ClaimTrie state to database. -func (ct *ClaimTrie) Save() error { - if err := ct.cm.Save(); err != nil { - return errors.Wrapf(err, "cm.Save()") - } - return nil +// Close saves ClaimTrie state to database. +func (ct *ClaimTrie) Close() error { + return ct.cleanup() } // Height returns the highest height of blocks commited to the ClaimTrie. diff --git a/cmd/claimtrie/main.go b/cmd/claimtrie/main.go index 2063ad1..07de400 100644 --- a/cmd/claimtrie/main.go +++ b/cmd/claimtrie/main.go @@ -149,22 +149,6 @@ func main() { Action: cmdImport, Flags: []cli.Flag{flagHeight, flagCheck, flagVerbose}, }, - { - Name: "load", - Aliases: []string{"ld"}, - Usage: "Load nodes from datbase.", - Before: parseArgs, - Action: cmdLoad, - Flags: []cli.Flag{}, - }, - { - Name: "save", - Aliases: []string{"sv"}, - Usage: "Save nodes to datbase.", - Before: parseArgs, - Action: cmdSave, - Flags: []cli.Flag{}, - }, { Name: "erase", Usage: "Erase datbase", @@ -181,28 +165,10 @@ func main() { }, } - path := cfg.DefaultConfig(cfg.TrieDB) - dbTrie, err := leveldb.OpenFile(path, nil) - if err != nil { - log.Fatalf("can't open %s, err: %s\n", path, err) + var err error + if ct, err = claimtrie.New(); err != nil { + log.Fatalf("can'y create ClaimTrie, err: %s", err) } - fmt.Printf("opened %q\n", path) - - path = cfg.DefaultConfig(cfg.NodeDB) - dbNodeMgr, err := leveldb.OpenFile(path, nil) - if err != nil { - log.Fatalf("can't open %s, err: %s\n", path, err) - } - fmt.Printf("opened %q\n", path) - - path = cfg.DefaultConfig(cfg.CommitDB) - dbCommit, err := leveldb.OpenFile(path, nil) - if err != nil { - log.Fatalf("can't open %s, err: %s\n", path, err) - } - fmt.Printf("opened %q\n", path) - - ct = claimtrie.New(dbCommit, dbTrie, dbNodeMgr) if err := app.Run(os.Args); err != nil { fmt.Printf("error: %s\n", err) } @@ -283,14 +249,6 @@ func cmdImport(c *cli.Context) error { return nil } -func cmdLoad(c *cli.Context) error { - return ct.Load() -} - -func cmdSave(c *cli.Context) error { - return ct.Save() -} - func cmdErase(c *cli.Context) error { if err := os.RemoveAll(cfg.DefaultConfig(cfg.CommitDB)); err != nil { return err @@ -329,8 +287,8 @@ func cmdShell(app *cli.App) { continue } if text == "quit" || text == "q" { - if err = ct.Save(); err != nil { - fmt.Printf("ct.Save() failed, err: %s\n", err) + if err = ct.Close(); err != nil { + fmt.Printf("ct.Close() failed, err: %s\n", err) } break } diff --git a/nodemgr/nm.go b/nodemgr/nm.go index 52b9c7f..1fe7a11 100644 --- a/nodemgr/nm.go +++ b/nodemgr/nm.go @@ -43,7 +43,7 @@ func (nm *NodeMgr) Load(ht claim.Height) { // Get returns the latest node with name specified by key. func (nm *NodeMgr) Get(key []byte) trie.Value { - return nm.nodeAt(string(key), nm.height) + return nm.NodeAt(string(key), nm.height) } // Reset resets all nodes to specified height. @@ -66,8 +66,8 @@ func (nm *NodeMgr) load(name string, ht claim.Height) *claim.Node { return NewFromChanges(name, c, ht) } -// nodeAt returns the node adjusted to specified height. -func (nm *NodeMgr) nodeAt(name string, ht claim.Height) *claim.Node { +// NodeAt returns the node adjusted to specified height. +func (nm *NodeMgr) NodeAt(name string, ht claim.Height) *claim.Node { n, ok := nm.cache[name] if !ok { n = claim.NewNode(name) @@ -84,7 +84,7 @@ func (nm *NodeMgr) nodeAt(name string, ht claim.Height) *claim.Node { // ModifyNode returns the node adjusted to specified height. func (nm *NodeMgr) ModifyNode(name string, chg *change.Change) error { ht := nm.height - n := nm.nodeAt(name, ht) + n := nm.NodeAt(name, ht) n.AdjustTo(ht) if err := execute(n, chg); err != nil { return errors.Wrapf(err, "claim.execute(n,chg)") @@ -100,12 +100,24 @@ func (nm *NodeMgr) CatchUp(ht claim.Height, notifier func(key []byte)) { nm.height = ht for name := range nm.nextUpdates[ht] { notifier([]byte(name)) - if next := nm.nodeAt(name, ht).NextUpdate(); next > ht { + if next := nm.NodeAt(name, ht).NextUpdate(); next > ht { nm.nextUpdates.set(name, next) } } } +// VisitFunc ... +type VisitFunc func(n *claim.Node) (stop bool) + +// Visit visits every node in the cache with VisiFunc. +func (nm *NodeMgr) Visit(v VisitFunc) { + for _, n := range nm.cache { + if v(n) { + return + } + } +} + // Show is a conevenient function for debugging and velopment purpose. // The proper way to handle user request would be a query function with filters specified. func (nm *NodeMgr) Show(name string, ht claim.Height, dump bool) error { @@ -119,7 +131,7 @@ func (nm *NodeMgr) Show(name string, ht claim.Height, dump bool) error { } sort.Strings(names) for _, name := range names { - n := nm.nodeAt(name, ht) + n := nm.NodeAt(name, ht) if n.BestClaim() == nil { continue }