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

Split node reference vs. index to separate interfaces for API clarity #91

Merged
merged 8 commits into from
Oct 4, 2024
4 changes: 2 additions & 2 deletions go-sdk/integration-test/db_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ func (s *SqliteTestSuite) TestSqliteStorage() {
dbRoot := core.SMTRoot{Name: s.smtName}
err = s.gormDB.Table(core.TreeRootsTable).First(&dbRoot).Error
assert.NoError(s.T(), err)
assert.Equal(s.T(), root.Hex(), dbRoot.RootIndex)
assert.Equal(s.T(), root.Hex(), dbRoot.RootRef)

dbNode := core.SMTNode{RefKey: n1.Ref().Hex()}
err = s.gormDB.Table(core.NodesTablePrefix + s.smtName).First(&dbNode).Error
Expand Down Expand Up @@ -155,7 +155,7 @@ func TestPostgresStorage(t *testing.T) {
dbRoot := core.SMTRoot{Name: "test_1"}
err = db.Table(core.TreeRootsTable).First(&dbRoot).Error
assert.NoError(t, err)
assert.Equal(t, root.Hex(), dbRoot.RootIndex)
assert.Equal(t, root.Hex(), dbRoot.RootRef)

dbNode := core.SMTNode{RefKey: n1.Ref().Hex()}
err = db.Table(core.NodesTablePrefix + "test_1").First(&dbNode).Error
Expand Down
20 changes: 10 additions & 10 deletions go-sdk/internal/sparse-merkle-tree/node/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,10 @@ type nodeIndex [32]byte
type node struct {
nodeType core.NodeType
index core.NodeIndex
refKey core.NodeIndex
refKey core.NodeRef
value core.Indexable
leftChild core.NodeIndex
rightChild core.NodeIndex
leftChild core.NodeRef
rightChild core.NodeRef
}

// //////////////////////////////////////
Expand Down Expand Up @@ -70,7 +70,7 @@ func NewLeafNode(v core.Indexable) (core.Node, error) {
return n, err
}

func NewBranchNode(leftChild, rightChild core.NodeIndex) (core.Node, error) {
func NewBranchNode(leftChild, rightChild core.NodeRef) (core.Node, error) {
n := &node{nodeType: core.NodeTypeBranch, leftChild: leftChild, rightChild: rightChild}
elements := []*big.Int{leftChild.BigInt(), rightChild.BigInt()}
hash, err := poseidon.Hash(elements)
Expand All @@ -89,19 +89,19 @@ func (n *node) Index() core.NodeIndex {
return n.index
}

func (n *node) Ref() core.NodeIndex {
func (n *node) Ref() core.NodeRef {
return n.refKey
}

func (n *node) Value() core.Indexable {
return n.value
}

func (n *node) LeftChild() core.NodeIndex {
func (n *node) LeftChild() core.NodeRef {
return n.leftChild
}

func (n *node) RightChild() core.NodeIndex {
func (n *node) RightChild() core.NodeRef {
return n.rightChild
}

Expand Down Expand Up @@ -145,20 +145,20 @@ func (idx *nodeIndex) IsZero() bool {
return idx.BigInt().Sign() == 0
}

func (idx *nodeIndex) Equal(other core.NodeIndex) bool {
func (idx *nodeIndex) Equal(other core.NodeRef) bool {
return idx.BigInt().Cmp(other.BigInt()) == 0
}

// getPath returns the binary path, from the root to the leaf.
func (idx *nodeIndex) ToPath(levels int) []bool {
path := make([]bool, levels)
for l := 0; l < levels; l++ {
path[l] = idx.IsBitOn(uint(l))
path[l] = idx.IsBitOne(uint(l))
}
return path
}

func (idx *nodeIndex) IsBitOn(pos uint) bool {
func (idx *nodeIndex) IsBitOne(pos uint) bool {
if pos >= 256 {
return false
}
Expand Down
30 changes: 15 additions & 15 deletions go-sdk/internal/sparse-merkle-tree/smt/merkletree.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ const MAX_TREE_HEIGHT = 256
type sparseMerkleTree struct {
sync.RWMutex
db core.Storage
rootKey core.NodeIndex
rootKey core.NodeRef
maxLevels int
}

Expand All @@ -44,10 +44,10 @@ func NewMerkleTree(db core.Storage, maxLevels int) (core.SparseMerkleTree, error
}
mt := sparseMerkleTree{db: db, maxLevels: maxLevels}

root, err := mt.db.GetRootNodeIndex()
root, err := mt.db.GetRootNodeRef()
if err == core.ErrNotFound {
mt.rootKey = node.ZERO_INDEX
err = mt.db.UpsertRootNodeIndex(mt.rootKey)
err = mt.db.UpsertRootNodeRef(mt.rootKey)
if err != nil {
return nil, err
}
Expand All @@ -59,7 +59,7 @@ func NewMerkleTree(db core.Storage, maxLevels int) (core.SparseMerkleTree, error
return &mt, nil
}

func (mt *sparseMerkleTree) Root() core.NodeIndex {
func (mt *sparseMerkleTree) Root() core.NodeRef {
mt.RLock()
defer mt.RUnlock()
return mt.rootKey
Expand Down Expand Up @@ -93,7 +93,7 @@ func (mt *sparseMerkleTree) AddLeaf(node core.Node) error {

// update the root node index in the storage
log.L().Infof("Upserting root node index to %s", mt.rootKey.Hex())
err = batch.UpsertRootNodeIndex(mt.rootKey)
err = batch.UpsertRootNodeRef(mt.rootKey)
if err != nil {
log.L().Errorf("Error upserting root node %s: %v, rolling back", mt.rootKey.Hex(), err)
_ = batch.Rollback()
Expand All @@ -114,7 +114,7 @@ func (mt *sparseMerkleTree) AddLeaf(node core.Node) error {

// GetNode gets a node by key from the merkle tree. Empty nodes are not stored in the
// tree: they are all the same and assumed to always exist.
func (mt *sparseMerkleTree) GetNode(key core.NodeIndex) (core.Node, error) {
func (mt *sparseMerkleTree) GetNode(key core.NodeRef) (core.Node, error) {
mt.RLock()
defer mt.RUnlock()
return mt.getNode(key)
Expand All @@ -123,7 +123,7 @@ func (mt *sparseMerkleTree) GetNode(key core.NodeIndex) (core.Node, error) {
// GenerateProofs generates a list of proofs of existence (or non-existence) of the provided
// leaf nodes that are represented by their indexes. An optional Merkle tree root can be provided.
// If rootKey is not provided, the current Merkle tree root is used
func (mt *sparseMerkleTree) GenerateProofs(keys []*big.Int, rootKey core.NodeIndex) ([]core.Proof, []*big.Int, error) {
func (mt *sparseMerkleTree) GenerateProofs(keys []*big.Int, rootKey core.NodeRef) ([]core.Proof, []*big.Int, error) {
mt.RLock()
defer mt.RUnlock()

Expand All @@ -141,9 +141,9 @@ func (mt *sparseMerkleTree) GenerateProofs(keys []*big.Int, rootKey core.NodeInd
return merkleProofs, foundValues, nil
}

func (mt *sparseMerkleTree) generateProof(key *big.Int, rootKey core.NodeIndex) (core.Proof, *big.Int, error) {
func (mt *sparseMerkleTree) generateProof(key *big.Int, rootKey core.NodeRef) (core.Proof, *big.Int, error) {
p := &proof{}
var siblingKey core.NodeIndex
var siblingKey core.NodeRef

kHash, err := node.NewNodeIndexFromBigInt(key)
if err != nil {
Expand Down Expand Up @@ -198,7 +198,7 @@ func (mt *sparseMerkleTree) generateProof(key *big.Int, rootKey core.NodeIndex)
}

// must be called from inside a read lock
func (mt *sparseMerkleTree) getNode(key core.NodeIndex) (core.Node, error) {
func (mt *sparseMerkleTree) getNode(key core.NodeRef) (core.Node, error) {
if key.IsZero() {
return node.NewEmptyNode(), nil
}
Expand All @@ -219,7 +219,7 @@ func (mt *sparseMerkleTree) getNode(key core.NodeIndex) (core.Node, error) {
// as children of a new branch node.
// - if the current node is a branch node, it will continue traversing the tree, using the
// next bit of the new node's index to determine which child to go down to.
func (mt *sparseMerkleTree) addLeaf(batch core.Transaction, newLeaf core.Node, currentNodeIndex core.NodeIndex, level int, path []bool) (core.NodeIndex, error) {
func (mt *sparseMerkleTree) addLeaf(batch core.Transaction, newLeaf core.Node, currentNodeRef core.NodeRef, level int, path []bool) (core.NodeRef, error) {
log.WithLogField("level", strconv.Itoa(level)).Debugf("Adding leaf node %s", newLeaf.Ref().Hex())
if level > mt.maxLevels-1 {
// we have exhausted all levels but could not find a unique path for the new leaf.
Expand All @@ -228,8 +228,8 @@ func (mt *sparseMerkleTree) addLeaf(batch core.Transaction, newLeaf core.Node, c
return nil, ErrReachedMaxLevel
}

var nextKey core.NodeIndex
currentNode, err := mt.getNode(currentNodeIndex)
var nextKey core.NodeRef
currentNode, err := mt.getNode(currentNodeRef)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -289,7 +289,7 @@ func (mt *sparseMerkleTree) addLeaf(batch core.Transaction, newLeaf core.Node, c
// must be called from inside a write lock
// addNode adds a node into the MT. Empty nodes are not stored in the tree;
// they are all the same and assumed to always exist.
func (mt *sparseMerkleTree) addNode(batch core.Transaction, n core.Node) (core.NodeIndex, error) {
func (mt *sparseMerkleTree) addNode(batch core.Transaction, n core.Node) (core.NodeRef, error) {
if n.Type() == core.NodeTypeEmpty {
return n.Ref(), nil
}
Expand All @@ -301,7 +301,7 @@ func (mt *sparseMerkleTree) addNode(batch core.Transaction, n core.Node) (core.N
// must be called from inside a write lock
// extendPath extends the path of two leaf nodes, which share the same beginnging part of
// their indexes, until their paths diverge, creating ancestor branch nodes as needed.
func (mt *sparseMerkleTree) extendPath(batch core.Transaction, newLeaf core.Node, oldLeaf core.Node, level int, pathNewLeaf []bool, pathOldLeaf []bool) (core.NodeIndex, error) {
func (mt *sparseMerkleTree) extendPath(batch core.Transaction, newLeaf core.Node, oldLeaf core.Node, level int, pathNewLeaf []bool, pathOldLeaf []bool) (core.NodeRef, error) {
if level > mt.maxLevels-2 {
return nil, ErrReachedMaxLevel
}
Expand Down
6 changes: 3 additions & 3 deletions go-sdk/internal/sparse-merkle-tree/smt/merkletree_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,16 @@ type mockStorage struct {
GetRootNodeIndex_customError bool
}

func (ms *mockStorage) GetRootNodeIndex() (core.NodeIndex, error) {
func (ms *mockStorage) GetRootNodeRef() (core.NodeRef, error) {
if ms.GetRootNodeIndex_customError {
return nil, fmt.Errorf("nasty error in get root")
}
return nil, core.ErrNotFound
}
func (ms *mockStorage) UpsertRootNodeIndex(core.NodeIndex) error {
func (ms *mockStorage) UpsertRootNodeRef(core.NodeRef) error {
return fmt.Errorf("nasty error in upsert root")
}
func (ms *mockStorage) GetNode(core.NodeIndex) (core.Node, error) {
func (ms *mockStorage) GetNode(core.NodeRef) (core.Node, error) {
return nil, nil
}
func (ms *mockStorage) InsertNode(core.Node) error {
Expand Down
20 changes: 10 additions & 10 deletions go-sdk/internal/sparse-merkle-tree/smt/proof.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import (
// non-existence.
type proof struct {
existence bool
siblings []core.NodeIndex
siblings []core.NodeRef
depth uint
existingNode core.Node
// nonEmptySiblings is a bitmap of non-empty Siblings found in Siblings. This helps
Expand All @@ -40,7 +40,7 @@ func (p *proof) IsExistenceProof() bool {
return p.existence
}

func (p *proof) Siblings() []core.NodeIndex {
func (p *proof) Siblings() []core.NodeRef {
return p.siblings
}

Expand Down Expand Up @@ -71,9 +71,9 @@ func (p *proof) IsNonEmptySibling(level uint) bool {
return isBitOnBigEndian(p.nonEmptySiblings, level)
}

func (p *proof) AllSiblings() []core.NodeIndex {
func (p *proof) AllSiblings() []core.NodeRef {
sibIdx := 0
siblings := []core.NodeIndex{}
siblings := []core.NodeRef{}
for level := 0; level < int(p.depth); level++ {
if p.IsNonEmptySibling(uint(level)) {
siblings = append(siblings, p.siblings[sibIdx])
Expand All @@ -89,15 +89,15 @@ func (p *proof) AllSiblings() []core.NodeIndex {
func (p *proof) getPath(index core.NodeIndex) []bool {
path := make([]bool, p.depth)
for n := 0; n < int(p.depth); n++ {
path[n] = index.IsBitOn(uint(n))
path[n] = index.IsBitOne(uint(n))
}
return path
}

// ToCircomVerifierProof enhances the generic merkle proof with additional
// signals required by the circuit for Sparse Merkle Tree proof verification:
// https://github.com/iden3/circomlib/blob/master/circuits/smt/smtverifier.circom
func (p *proof) ToCircomVerifierProof(k, v *big.Int, rootKey core.NodeIndex, levels int) (*core.CircomVerifierProof, error) {
func (p *proof) ToCircomVerifierProof(k, v *big.Int, rootKey core.NodeRef, levels int) (*core.CircomVerifierProof, error) {
var cp core.CircomVerifierProof
cp.Root = rootKey
cp.Siblings = p.AllSiblings()
Expand Down Expand Up @@ -131,7 +131,7 @@ func (p *proof) ToCircomVerifierProof(k, v *big.Int, rootKey core.NodeIndex, lev
}

// VerifyProof verifies the Merkle Proof for the entry and root.
func VerifyProof(rootKey core.NodeIndex, p core.Proof, leafNode core.Node) bool {
func VerifyProof(rootKey core.NodeRef, p core.Proof, leafNode core.Node) bool {
rootFromProof, err := calculateRootFromProof(p.(*proof), leafNode)
if err != nil {
return false
Expand All @@ -141,9 +141,9 @@ func VerifyProof(rootKey core.NodeIndex, p core.Proof, leafNode core.Node) bool

// CalculateRootFromProof calculates the root that would correspond to a tree whose
// siblings are the ones in the proof with the leaf node
func calculateRootFromProof(proof *proof, leafNode core.Node) (core.NodeIndex, error) {
func calculateRootFromProof(proof *proof, leafNode core.Node) (core.NodeRef, error) {
sibIdx := len(proof.siblings) - 1
var midKey core.NodeIndex
var midKey core.NodeRef
if proof.existence {
midKey = leafNode.Ref()
} else {
Expand All @@ -157,7 +157,7 @@ func calculateRootFromProof(proof *proof, leafNode core.Node) (core.NodeIndex, e
}
}
path := proof.getPath(leafNode.Index())
var siblingKey core.NodeIndex
var siblingKey core.NodeRef
for level := int(proof.depth) - 1; level >= 0; level-- {
if proof.IsNonEmptySibling(uint(level)) {
siblingKey = proof.siblings[sibIdx]
Expand Down
6 changes: 4 additions & 2 deletions go-sdk/internal/sparse-merkle-tree/smt/smt_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -152,9 +152,12 @@ func (s *MerkleTreeTestSuite) TestAddNode() {

// test storage persistence
rawDB := mt.(*sparseMerkleTree).db
rootIdx, err := rawDB.GetRootNodeIndex()
rootIdx, err := rawDB.GetRootNodeRef()
assert.NoError(s.T(), err)
assert.Equal(s.T(), "abacf46f5217552ee28fe50b8fd7ca6aa46daeb9acf9f60928654c3b1a472f23", rootIdx.Hex())
dbNode1, err := rawDB.GetNode(n1.Ref())
assert.NoError(s.T(), err)
assert.Equal(s.T(), n1.Index().Hex(), dbNode1.Index().Hex())

// test storage persistence across tree creation
mt2, err := NewMerkleTree(s.db, 10)
Expand Down Expand Up @@ -242,7 +245,6 @@ func (s *MerkleTreeTestSuite) TestVerifyProof() {
assert.NoError(s.T(), err)
startProving <- node
done <- true
fmt.Printf("Added node %d\n", idx)
}(value, idx)
}

Expand Down
24 changes: 12 additions & 12 deletions go-sdk/internal/sparse-merkle-tree/storage/sql.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ func NewSqlStorage(p core.SqlDBProvider, smtName string) *sqlStorage {
}
}

func (s *sqlStorage) GetRootNodeIndex() (core.NodeIndex, error) {
func (s *sqlStorage) GetRootNodeRef() (core.NodeRef, error) {
root := core.SMTRoot{
Name: s.smtName,
}
Expand All @@ -51,15 +51,15 @@ func (s *sqlStorage) GetRootNodeIndex() (core.NodeIndex, error) {
} else if err != nil {
return nil, err
}
idx, err := node.NewNodeIndexFromHex(root.RootIndex)
idx, err := node.NewNodeIndexFromHex(root.RootRef)
return idx, err
}

func (s *sqlStorage) UpsertRootNodeIndex(root core.NodeIndex) error {
return upsertRootNodeIndex(s.p.DB(), s.smtName, root)
func (s *sqlStorage) UpsertRootNodeRef(root core.NodeRef) error {
return upsertRootNodeRef(s.p.DB(), s.smtName, root)
}

func (s *sqlStorage) GetNode(ref core.NodeIndex) (core.Node, error) {
func (s *sqlStorage) GetNode(ref core.NodeRef) (core.Node, error) {
return getNode(s.p.DB(), s.nodesTableName, ref)
}

Expand All @@ -81,11 +81,11 @@ type sqlTxStorage struct {
nodesTableName string
}

func (b *sqlTxStorage) UpsertRootNodeIndex(root core.NodeIndex) error {
return upsertRootNodeIndex(b.tx, b.smtName, root)
func (b *sqlTxStorage) UpsertRootNodeRef(root core.NodeRef) error {
return upsertRootNodeRef(b.tx, b.smtName, root)
}

func (b *sqlTxStorage) GetNode(ref core.NodeIndex) (core.Node, error) {
func (b *sqlTxStorage) GetNode(ref core.NodeRef) (core.Node, error) {
return getNode(b.tx, b.nodesTableName, ref)
}

Expand All @@ -105,15 +105,15 @@ func (m *sqlStorage) Close() {
m.p.Close()
}

func upsertRootNodeIndex(batchOrDb *gorm.DB, name string, root core.NodeIndex) error {
func upsertRootNodeRef(batchOrDb *gorm.DB, name string, root core.NodeRef) error {
err := batchOrDb.Table(core.TreeRootsTable).Save(&core.SMTRoot{
RootIndex: root.Hex(),
Name: name,
RootRef: root.Hex(),
Name: name,
}).Error
return err
}

func getNode(batchOrDb *gorm.DB, nodesTableName string, ref core.NodeIndex) (core.Node, error) {
func getNode(batchOrDb *gorm.DB, nodesTableName string, ref core.NodeRef) (core.Node, error) {
// the node's reference key (not the index) is used as the key to
// store the node in the DB
n := core.SMTNode{
Expand Down
Loading
Loading