Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: next hard fork #5

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions addrmgr/addrmanager_internal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,12 @@ func TestAddrManagerSerialization(t *testing.T) {
expectedAddrs := make(map[string]*wire.NetAddress, numAddrs)
for i := 0; i < numAddrs; i++ {
addr := randAddr(t)
cnt := len(expectedAddrs)
expectedAddrs[NetAddressKey(addr)] = addr
if len(expectedAddrs) == cnt {
i-- // accidentally generated a duplicate
continue
}
addrMgr.AddAddress(addr, randAddr(t))
}

Expand Down
69 changes: 69 additions & 0 deletions blockchain/claimtrie.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,21 @@ package blockchain
import (
"bytes"
"fmt"
"strings"

"github.com/pkg/errors"

"github.com/lbryio/lbcd/chaincfg/chainhash"
"github.com/lbryio/lbcd/txscript"
"github.com/lbryio/lbcd/wire"
btcutil "github.com/lbryio/lbcutil"

"github.com/lbryio/lbcd/claimtrie"
"github.com/lbryio/lbcd/claimtrie/change"
"github.com/lbryio/lbcd/claimtrie/merkletrie"
"github.com/lbryio/lbcd/claimtrie/node"
"github.com/lbryio/lbcd/claimtrie/normalization"
"github.com/lbryio/lbcd/claimtrie/param"
)

func (b *BlockChain) SetClaimtrieHeader(block *btcutil.Block, view *UtxoViewpoint) error {
Expand Down Expand Up @@ -181,3 +185,68 @@ func (b *BlockChain) GetClaimsForName(height int32, name string) (string, *node.
n.SortClaimsByBid()
return string(normalizedName), n, nil
}

func (b *BlockChain) GetProofForName(name, id string, bid, seq int) (chainhash.Hash, int32, *node.Claim, int32, int32, string, []merkletrie.HashSidePair, error) {
// results: block hash, height, claim, bid, takeover, name, pairs, err

b.chainLock.RLock()
defer b.chainLock.RUnlock()

tip := b.bestChain.Tip()

normalizedName := normalization.NormalizeIfNecessary([]byte(name), tip.height)

if tip.height < param.ActiveParams.GrandForkHeight {
err := errors.Errorf("Unable to generate proofs for claims before height %d",
param.ActiveParams.GrandForkHeight)
return tip.hash, tip.height, nil, 0, 0, string(normalizedName), nil, err
}

n, err := b.claimTrie.NodeAt(tip.height, normalizedName)
if n == nil && err == nil {
err = errors.Errorf("Unable to locate a claim with name %s at height %d", normalizedName, tip.height)
}
if err != nil {
return tip.hash, tip.height, nil, 0, 0, string(normalizedName), nil, err
}

// now find the desired claim
n.SortClaimsByBid()
var claim *node.Claim
for i, c := range n.Claims {
if c.Status != node.Activated {
continue
}
if bid >= 0 && i == bid {
claim = c
bid = i
break
}
if seq >= 0 && int(c.Sequence) == seq {
claim = c
bid = i
break
}
if len(id) > 0 && strings.HasPrefix(c.ClaimID.String(), id) {
claim = c
bid = i
break
}
}
if claim == nil {
if bid >= 0 {
err = errors.Errorf("Unable to locate a claim named %s with bid %d at height %d", normalizedName, bid, tip.height)
}
if seq >= 0 {
err = errors.Errorf("Unable to locate a claim named %s with sequence %d at height %d", normalizedName, seq, tip.height)
}
if len(id) > 0 {
err = errors.Errorf("Unable to locate a claim named %s with ID %s at height %d", normalizedName, id, tip.height)
}
return tip.hash, tip.height, nil, 0, 0, string(normalizedName), nil, err
}

pairs := b.claimTrie.MerklePath(normalizedName, n, bid)

return tip.hash, tip.height, claim, int32(bid), n.TakenOverAt, string(normalizedName), pairs, nil
}
3 changes: 2 additions & 1 deletion blockchain/validate.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (

"github.com/lbryio/lbcd/chaincfg"
"github.com/lbryio/lbcd/chaincfg/chainhash"
"github.com/lbryio/lbcd/claimtrie/param"
"github.com/lbryio/lbcd/txscript"
"github.com/lbryio/lbcd/wire"
btcutil "github.com/lbryio/lbcutil"
Expand Down Expand Up @@ -547,7 +548,7 @@ func checkBlockSanity(block *btcutil.Block, powLimit *big.Int, timeSource Median
// Do some preliminary checks on each transaction to ensure they are
// sane before continuing.
for _, tx := range transactions {
err := CheckTransactionSanity(tx, false)
err := CheckTransactionSanity(tx, block.Height() >= param.ActiveParams.GrandForkHeight)
if err != nil {
return err
}
Expand Down
37 changes: 37 additions & 0 deletions btcjson/claimcmds.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ func init() {
MustRegisterCmd("getclaimsfornamebybid", (*GetClaimsForNameByBidCmd)(nil), flags)
MustRegisterCmd("getclaimsfornamebyseq", (*GetClaimsForNameBySeqCmd)(nil), flags)
MustRegisterCmd("normalize", (*GetNormalizedCmd)(nil), flags)

MustRegisterCmd("getprooffornamebyid", (*GetProofForNameByIDCmd)(nil), flags)
MustRegisterCmd("getprooffornamebybid", (*GetProofForNameByBidCmd)(nil), flags)
MustRegisterCmd("getprooffornamebyseq", (*GetProofForNameBySeqCmd)(nil), flags)
}

// optional inputs are required to be pointers, but they support things like `jsonrpcdefault:"false"`
Expand Down Expand Up @@ -95,3 +99,36 @@ type GetNormalizedCmd struct {
type GetNormalizedResult struct {
NormalizedName string `json:"normalizedname"`
}

type GetProofForNameByIDCmd struct {
Name string `json:"name"`
PartialClaimID string `json:"partialclaimid"`
}

type GetProofForNameByBidCmd struct {
Name string `json:"name"`
Bid int `json:"bid"`
}

type GetProofForNameBySeqCmd struct {
Name string `json:"name"`
Sequence int `json:"sequence"`
}

type ProofPairResult struct {
Right bool `json:"right"`
Hash string `json:"hash"`
}

type ProofResult struct { // should we include the claim trie hash?
BlockHash string `json:"blockhash"`
BlockHeight int32 `json:"blockheight"`
NormalizedName string `json:"normalizedname"`
ClaimID string `json:"claimid"`
TXID string `json:"txid"`
N uint32 `json:"n"`
Bid int32 `json:"bid"`
Sequence int32 `json:"sequence"`
Takeover int32 `json:"takeover"`
Pairs []ProofPairResult `json:"pairs"`
}
30 changes: 27 additions & 3 deletions claimtrie/claimtrie.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,9 @@ func New(cfg config.Config) (*ClaimTrie, error) {
return nil, errors.Wrap(err, "creating node base manager")
}
normalizingManager := node.NewNormalizingManager(baseManager)
nodeManager := &node.HashV2Manager{Manager: normalizingManager}
hashV2Manager := &node.HashV2Manager{Manager: normalizingManager}
nodeManager := &node.HashV3Manager{Manager: hashV2Manager}

cleanups = append(cleanups, nodeManager.Close)

var trie merkletrie.MerkleTrie
Expand Down Expand Up @@ -281,7 +283,8 @@ func (ct *ClaimTrie) AppendBlock(temporary bool) error {
}

func (ct *ClaimTrie) updateTrieForHashForkIfNecessary() bool {
if ct.height != param.ActiveParams.AllClaimsInMerkleForkHeight {
if ct.height != param.ActiveParams.AllClaimsInMerkleForkHeight &&
ct.height != param.ActiveParams.GrandForkHeight {
return false
}

Expand All @@ -303,7 +306,7 @@ func removeDuplicates(names [][]byte) [][]byte { // this might be too expensive;
return names
}

// ResetHeight resets the ClaimTrie to a previous known height..
// ResetHeight resets the ClaimTrie to a previous known height.
func (ct *ClaimTrie) ResetHeight(height int32) error {

names := make([][]byte, 0)
Expand All @@ -320,6 +323,9 @@ func (ct *ClaimTrie) ResetHeight(height int32) error {
}

passedHashFork := ct.height >= param.ActiveParams.AllClaimsInMerkleForkHeight && height < param.ActiveParams.AllClaimsInMerkleForkHeight
if !passedHashFork {
passedHashFork = ct.height >= param.ActiveParams.GrandForkHeight && height < param.ActiveParams.GrandForkHeight
}
hash, err := ct.blockRepo.Get(height)
if err != nil {
return err
Expand Down Expand Up @@ -451,3 +457,21 @@ func interruptRequested(interrupted <-chan struct{}) bool {

return false
}

func (ct *ClaimTrie) MerklePath(name []byte, n *node.Node, bid int) []merkletrie.HashSidePair {
pairs := ct.merkleTrie.MerklePath(name)
// TODO: organize this code better
// this is the 2nd half of the above merkle tree computation
// it's done like this so we don't have to create the Node object multiple times
claimHashes := node.ComputeClaimHashes(name, n)
partials := node.ComputeMerklePath(claimHashes, bid)
for i := len(partials) - 1; i >= 0; i-- {
pairs = append(pairs, merkletrie.HashSidePair{Right: ((bid >> i) & 1) > 0, Hash: partials[i]})
}

// reverse the list order:
for i, j := 0, len(pairs)-1; i < j; i, j = i+1, j-1 {
pairs[i], pairs[j] = pairs[j], pairs[i]
}
return pairs
}
64 changes: 64 additions & 0 deletions claimtrie/claimtrie_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"github.com/lbryio/lbcd/claimtrie/change"
"github.com/lbryio/lbcd/claimtrie/config"
"github.com/lbryio/lbcd/claimtrie/merkletrie"
"github.com/lbryio/lbcd/claimtrie/node"
"github.com/lbryio/lbcd/claimtrie/param"

"github.com/lbryio/lbcd/chaincfg/chainhash"
Expand Down Expand Up @@ -1025,3 +1026,66 @@ func TestBlock884431(t *testing.T) {
r.NoError(err)
r.Equal(o11.String(), n.BestClaim.OutPoint.String())
}

func TestMerklePath(t *testing.T) {
r := require.New(t)
setup(t)
param.ActiveParams.ActiveDelayFactor = 1
param.ActiveParams.NormalizedNameForkHeight = 5
param.ActiveParams.AllClaimsInMerkleForkHeight = 6
param.ActiveParams.GrandForkHeight = 7

ct, err := New(cfg)
r.NoError(err)
r.NotNil(ct)
defer ct.Close()

hash := chainhash.HashH([]byte{1, 2, 3})
o1 := wire.OutPoint{Hash: hash, Index: 1}
o2 := wire.OutPoint{Hash: hash, Index: 2}
o3 := wire.OutPoint{Hash: hash, Index: 3}

err = ct.AddClaim([]byte("test"), o1, change.NewClaimID(o1), 1)
r.NoError(err)

err = ct.AddClaim([]byte("test"), o2, change.NewClaimID(o2), 2)
r.NoError(err)

err = ct.AddClaim([]byte("tester"), o3, change.NewClaimID(o3), 1)
r.NoError(err)

for i := 0; i < 10; i++ {
err = ct.AppendBlock(false)
r.NoError(err)
}

n, err := ct.NodeAt(ct.height, []byte("test"))
r.NoError(err)
pairs := ct.MerklePath([]byte("test"), n, 0)
claimHash, err := node.ComputeBidSeqNameHash([]byte("test"), n.Claims[0], 0, n.TakenOverAt)
r.NoError(err)
validatePairs(r, pairs, ct.MerkleHash(), claimHash)

pairs = ct.MerklePath([]byte("test"), n, 1)
claimHash, err = node.ComputeBidSeqNameHash([]byte("test"), n.Claims[1], 1, n.TakenOverAt)
r.NoError(err)
validatePairs(r, pairs, ct.MerkleHash(), claimHash)

n, err = ct.NodeAt(ct.height, []byte("tester"))
r.NoError(err)
pairs = ct.MerklePath([]byte("tester"), n, 0)
claimHash, err = node.ComputeBidSeqNameHash([]byte("tester"), n.Claims[0], 0, n.TakenOverAt)
r.NoError(err)
validatePairs(r, pairs, ct.MerkleHash(), claimHash)
}

func validatePairs(r *require.Assertions, pairs []merkletrie.HashSidePair, target *chainhash.Hash, claimHash *chainhash.Hash) {
for i := range pairs {
if pairs[i].Right {
claimHash = node.HashMerkleBranches(pairs[i].Hash, claimHash)
} else {
claimHash = node.HashMerkleBranches(claimHash, pairs[i].Hash)
}
}
r.True(claimHash.IsEqual(target))
}
4 changes: 4 additions & 0 deletions claimtrie/merkletrie/merkletrie.go
Original file line number Diff line number Diff line change
Expand Up @@ -253,3 +253,7 @@ func (t *PersistentTrie) Dump(s string) {
func (t *PersistentTrie) Flush() error {
return t.repo.Flush()
}

func (t *PersistentTrie) MerklePath(name []byte) []HashSidePair {
panic("MerklePath not implemented in PersistentTrie")
}
Loading
Loading