183 lines
4.7 KiB
Go
183 lines
4.7 KiB
Go
package claimtrie
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"github.com/lbryio/claimtrie/cfg"
|
|
"github.com/lbryio/claimtrie/change"
|
|
"github.com/lbryio/claimtrie/claim"
|
|
"github.com/lbryio/claimtrie/nodemgr"
|
|
"github.com/lbryio/claimtrie/trie"
|
|
|
|
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
|
"github.com/pkg/errors"
|
|
"github.com/syndtr/goleveldb/leveldb"
|
|
)
|
|
|
|
// ClaimTrie implements a Merkle Trie supporting linear history of commits.
|
|
type ClaimTrie struct {
|
|
cm *CommitMgr
|
|
nm *nodemgr.NodeMgr
|
|
tr *trie.Trie
|
|
|
|
cleanup func() error
|
|
}
|
|
|
|
// New returns a ClaimTrie.
|
|
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)
|
|
}
|
|
|
|
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: tr,
|
|
|
|
cleanup: func() error {
|
|
if err := nm.Save(); err != nil {
|
|
return errors.Wrapf(err, "nm.Save()")
|
|
}
|
|
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
|
|
}
|
|
|
|
// 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.
|
|
func (ct *ClaimTrie) Height() claim.Height {
|
|
return ct.cm.Head().Meta.Height
|
|
}
|
|
|
|
// Head returns the tip commit in the commit database.
|
|
func (ct *ClaimTrie) Head() *Commit {
|
|
return ct.cm.Head()
|
|
}
|
|
|
|
// Trie returns the MerkleTrie of the ClaimTrie .
|
|
func (ct *ClaimTrie) Trie() *trie.Trie {
|
|
return ct.tr
|
|
}
|
|
|
|
// NodeMgr returns the Node Manager of the ClaimTrie .
|
|
func (ct *ClaimTrie) NodeMgr() *nodemgr.NodeMgr {
|
|
return ct.nm
|
|
}
|
|
|
|
// CommitMgr returns the Commit Manager of the ClaimTrie .
|
|
func (ct *ClaimTrie) CommitMgr() *CommitMgr {
|
|
return ct.cm
|
|
}
|
|
|
|
// AddClaim adds a Claim to the ClaimTrie.
|
|
func (ct *ClaimTrie) AddClaim(name string, op claim.OutPoint, amt claim.Amount, val []byte) error {
|
|
c := change.New(change.AddClaim).SetOP(op).SetAmt(amt).SetValue(val)
|
|
return ct.modify(name, c)
|
|
}
|
|
|
|
// SpendClaim spend a Claim in the ClaimTrie.
|
|
func (ct *ClaimTrie) SpendClaim(name string, op claim.OutPoint) error {
|
|
c := change.New(change.SpendClaim).SetOP(op)
|
|
return ct.modify(name, c)
|
|
}
|
|
|
|
// UpdateClaim updates a Claim in the ClaimTrie.
|
|
func (ct *ClaimTrie) UpdateClaim(name string, op claim.OutPoint, amt claim.Amount, id claim.ID, val []byte) error {
|
|
c := change.New(change.UpdateClaim).SetOP(op).SetAmt(amt).SetID(id).SetValue(val)
|
|
return ct.modify(name, c)
|
|
}
|
|
|
|
// AddSupport adds a Support to the ClaimTrie.
|
|
func (ct *ClaimTrie) AddSupport(name string, op claim.OutPoint, amt claim.Amount, id claim.ID) error {
|
|
c := change.New(change.AddSupport).SetOP(op).SetAmt(amt).SetID(id)
|
|
return ct.modify(name, c)
|
|
}
|
|
|
|
// SpendSupport spend a support in the ClaimTrie.
|
|
func (ct *ClaimTrie) SpendSupport(name string, op claim.OutPoint) error {
|
|
c := change.New(change.SpendSupport).SetOP(op)
|
|
return ct.modify(name, c)
|
|
}
|
|
|
|
func (ct *ClaimTrie) modify(name string, c *change.Change) error {
|
|
c.SetHeight(ct.Height() + 1).SetName(name)
|
|
if err := ct.nm.ModifyNode(name, c); err != nil {
|
|
return err
|
|
}
|
|
ct.tr.Update([]byte(name))
|
|
return nil
|
|
}
|
|
|
|
// MerkleHash returns the Merkle Hash of the ClaimTrie.
|
|
func (ct *ClaimTrie) MerkleHash() *chainhash.Hash {
|
|
return ct.tr.MerkleHash()
|
|
}
|
|
|
|
// Commit commits the current changes into database.
|
|
func (ct *ClaimTrie) Commit(ht claim.Height) {
|
|
if ht < ct.Height() {
|
|
return
|
|
}
|
|
for i := ct.Height() + 1; i <= ht; i++ {
|
|
ct.nm.CatchUp(i, ct.tr.Update)
|
|
}
|
|
h := ct.MerkleHash()
|
|
ct.cm.Commit(ht, h)
|
|
ct.tr.SetRoot(h)
|
|
}
|
|
|
|
// Reset resets the tip commit to a previous height specified.
|
|
func (ct *ClaimTrie) Reset(ht claim.Height) error {
|
|
if ht > ct.Height() {
|
|
return ErrInvalidHeight
|
|
}
|
|
ct.cm.Reset(ht)
|
|
ct.nm.Reset(ht)
|
|
ct.tr.SetRoot(ct.Head().MerkleRoot)
|
|
return nil
|
|
}
|