| 
						
						
							
								
							
						
						
					 | 
				
				 | 
				
					@ -12,7 +12,6 @@ package arbo | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					import ( | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						"bytes" | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						"crypto/sha256" | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						"encoding/binary" | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						"encoding/hex" | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						"fmt" | 
				
			
			
		
	
	
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
				
				 | 
				
					@ -69,11 +68,10 @@ var ( | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					// Tree defines the struct that implements the MerkleTree functionalities
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					type Tree struct { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						sync.RWMutex | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						dbBatch     db.Batch | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						batchMemory kvMap // TODO TMP
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						db          db.Database | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						maxLevels   int | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						root        []byte | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						db        db.Database | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						maxLevels int | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						root      []byte | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						hashFunction HashFunction | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						// TODO in the methods that use it, check if emptyHash param is len>0
 | 
				
			
			
		
	
	
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
				
				 | 
				
					@ -83,54 +81,43 @@ type Tree struct { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						dbg *dbgStats | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					// bmKeySize stands for batchMemoryKeySize
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					const bmKeySize = sha256.Size | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					// TMP
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					type kvMap map[[bmKeySize]byte]kv | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					// Get retreives the value respective to a key from the KvMap
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					func (m kvMap) Get(k []byte) ([]byte, bool) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						v, ok := m[sha256.Sum256(k)] | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						return v.v, ok | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					// Put stores a key and a value in the KvMap
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					func (m kvMap) Put(k, v []byte) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						m[sha256.Sum256(k)] = kv{k: k, v: v} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					// NewTree returns a new Tree, if there is a Tree still in the given database, it
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					// will load it.
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					func NewTree(database db.Database, maxLevels int, hash HashFunction) (*Tree, error) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						t := Tree{db: database, maxLevels: maxLevels, hashFunction: hash} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						t.emptyHash = make([]byte, t.hashFunction.Len()) // empty
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						root, err := t.dbGet(dbKeyRoot) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						if err == ErrKeyNotFound { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						wTx := t.db.WriteTx() | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						defer wTx.Discard() | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						root, err := wTx.Get(dbKeyRoot) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						if err == db.ErrKeyNotFound { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							// store new root 0
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							t.dbBatch = t.db.NewBatch() | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							t.batchMemory = make(map[[bmKeySize]byte]kv) // TODO TMP
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							t.root = t.emptyHash | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							if err = t.dbPut(dbKeyRoot, t.root); err != nil { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							if err = wTx.Set(dbKeyRoot, t.root); err != nil { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
								return nil, err | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							if err = t.setNLeafs(0); err != nil { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							if err = t.setNLeafs(wTx, 0); err != nil { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
								return nil, err | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							if err = t.dbBatch.Write(); err != nil { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							if err = wTx.Commit(); err != nil { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
								return nil, err | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							return &t, err | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							return &t, nil | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						} else if err != nil { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							return nil, err | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						if err = wTx.Commit(); err != nil { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							return nil, err | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						t.root = root | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						return &t, nil | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					// Root returns the root of the Tree
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					func (t *Tree) Root() []byte { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						// TODO get Root from db
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						return t.root | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
	
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
				
				 | 
				
					@ -143,18 +130,28 @@ func (t *Tree) HashFunction() HashFunction { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					// the indexes of the keys failed to add. Supports empty values as input
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					// parameters, which is equivalent to 0 valued byte array.
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					func (t *Tree) AddBatch(keys, values [][]byte) ([]int, error) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						wTx := t.db.WriteTx() | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						defer wTx.Discard() | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						invalids, err := t.AddBatchWithTx(wTx, keys, values) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						if err != nil { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							return invalids, err | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						return invalids, wTx.Commit() | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					// AddBatchWithTx does the same than the AddBatch method, but allowing to pass
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					// the db.WriteTx that is used. The db.WriteTx will not be committed inside
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					// this method.
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					func (t *Tree) AddBatchWithTx(wTx db.WriteTx, keys, values [][]byte) ([]int, error) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						t.Lock() | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						defer t.Unlock() | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						vt, err := t.loadVT() | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						vt, err := t.loadVT(wTx) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						if err != nil { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							return nil, err | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						// TODO check validity of keys & values for Tree.hashFunction (maybe do
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						// not add the checks, as would need more time, and this could be
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						// checked/ensured before calling this method)
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						e := []byte{} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						// equal the number of keys & values
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						if len(keys) > len(values) { | 
				
			
			
		
	
	
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
				
				 | 
				
					@ -183,37 +180,31 @@ func (t *Tree) AddBatch(keys, values [][]byte) ([]int, error) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						t.root = vt.root.h | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						// store pairs in db
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						t.dbBatch = t.db.NewBatch() | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						t.batchMemory = make(map[[bmKeySize]byte]kv) // TODO TMP
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						for i := 0; i < len(pairs); i++ { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							if err := t.dbPut(pairs[i][0], pairs[i][1]); err != nil { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							if err := wTx.Set(pairs[i][0], pairs[i][1]); err != nil { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
								return nil, err | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						// store root to db
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						if err := t.dbPut(dbKeyRoot, t.root); err != nil { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						if err := wTx.Set(dbKeyRoot, t.root); err != nil { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							return nil, err | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						// update nLeafs
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						if err := t.incNLeafs(len(keys) - len(invalids)); err != nil { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						if err := t.incNLeafs(wTx, len(keys)-len(invalids)); err != nil { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							return nil, err | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						// commit db dbBatch
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						if err := t.dbBatch.Write(); err != nil { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							return nil, err | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						return invalids, nil | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					// loadVT loads a new virtual tree (vt) from the current Tree, which contains
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					// the same leafs.
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					func (t *Tree) loadVT() (vt, error) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					func (t *Tree) loadVT(rTx db.ReadTx) (vt, error) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						vt := newVT(t.maxLevels, t.hashFunction) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						vt.params.dbg = t.dbg | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						err := t.Iterate(nil, func(k, v []byte) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						err := t.IterateWithTx(rTx, nil, func(k, v []byte) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							if v[0] != PrefixValueLeaf { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
								return | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							} | 
				
			
			
		
	
	
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
				
				 | 
				
					@ -227,44 +218,50 @@ func (t *Tree) loadVT() (vt, error) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						return vt, err | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					// Add inserts the key-value into the Tree.  If the inputs come from a *big.Int,
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					// is expected that are represented by a Little-Endian byte array (for circom
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					// compatibility).
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					// Add inserts the key-value into the Tree.  If the inputs come from a
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					// *big.Int, is expected that are represented by a Little-Endian byte array
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					// (for circom compatibility).
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					func (t *Tree) Add(k, v []byte) error { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						t.Lock() | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						defer t.Unlock() | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						wTx := t.db.WriteTx() | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						defer wTx.Discard() | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						var err error | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						t.dbBatch = t.db.NewBatch() | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						t.batchMemory = make(map[[bmKeySize]byte]kv) // TODO TMP
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						if err := t.AddWithTx(wTx, k, v); err != nil { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							return err | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						// TODO check validity of key & value for Tree.hashFunction (maybe do
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						// not add the checks, as would need more time, and this could be
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						// checked/ensured before calling this method)
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						return wTx.Commit() | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					// AddWithTx does the same than the Add method, but allowing to pass the
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					// db.WriteTx that is used. The db.WriteTx will not be committed inside this
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					// method.
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					func (t *Tree) AddWithTx(wTx db.WriteTx, k, v []byte) error { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						t.Lock() | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						defer t.Unlock() | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						err = t.add(0, k, v) // add from level 0
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						err := t.add(wTx, 0, k, v) // add from level 0
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						if err != nil { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							return err | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						// store root to db
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						if err := t.dbPut(dbKeyRoot, t.root); err != nil { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						if err := wTx.Set(dbKeyRoot, t.root); err != nil { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							return err | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						// update nLeafs
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						if err = t.incNLeafs(1); err != nil { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						if err = t.incNLeafs(wTx, 1); err != nil { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							return err | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						return t.dbBatch.Write() | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						return nil | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					func (t *Tree) add(fromLvl int, k, v []byte) error { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					func (t *Tree) add(wTx db.WriteTx, fromLvl int, k, v []byte) error { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						keyPath := make([]byte, t.hashFunction.Len()) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						copy(keyPath[:], k) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						path := getPath(t.maxLevels, keyPath) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						// go down to the leaf
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						var siblings [][]byte | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						_, _, siblings, err := t.down(k, t.root, siblings, path, fromLvl, false) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						_, _, siblings, err := t.down(wTx, k, t.root, siblings, path, fromLvl, false) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						if err != nil { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							return err | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						} | 
				
			
			
		
	
	
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
				
				 | 
				
					@ -274,7 +271,7 @@ func (t *Tree) add(fromLvl int, k, v []byte) error { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							return err | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						if err := t.dbPut(leafKey, leafValue); err != nil { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						if err := wTx.Set(leafKey, leafValue); err != nil { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							return err | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
	
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
				
				 | 
				
					@ -283,7 +280,7 @@ func (t *Tree) add(fromLvl int, k, v []byte) error { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							t.root = leafKey | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							return nil | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						root, err := t.up(leafKey, siblings, path, len(siblings)-1, fromLvl) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						root, err := t.up(wTx, leafKey, siblings, path, len(siblings)-1, fromLvl) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						if err != nil { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							return err | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						} | 
				
			
			
		
	
	
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
				
				 | 
				
					@ -293,7 +290,7 @@ func (t *Tree) add(fromLvl int, k, v []byte) error { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					// down goes down to the leaf recursively
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					func (t *Tree) down(newKey, currKey []byte, siblings [][]byte, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					func (t *Tree) down(rTx db.ReadTx, newKey, currKey []byte, siblings [][]byte, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						path []bool, currLvl int, getLeaf bool) ( | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						[]byte, []byte, [][]byte, error) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						if currLvl > t.maxLevels-1 { | 
				
			
			
		
	
	
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
				
				 | 
				
					@ -306,7 +303,7 @@ func (t *Tree) down(newKey, currKey []byte, siblings [][]byte, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							// empty value
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							return currKey, emptyValue, siblings, nil | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						currValue, err = t.dbGet(currKey) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						currValue, err = rTx.Get(currKey) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						if err != nil { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							return nil, nil, nil, err | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						} | 
				
			
			
		
	
	
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
				
				 | 
				
					@ -353,12 +350,12 @@ func (t *Tree) down(newKey, currKey []byte, siblings [][]byte, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
								// right
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
								lChild, rChild := ReadIntermediateChilds(currValue) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
								siblings = append(siblings, lChild) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
								return t.down(newKey, rChild, siblings, path, currLvl+1, getLeaf) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
								return t.down(rTx, newKey, rChild, siblings, path, currLvl+1, getLeaf) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							// left
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							lChild, rChild := ReadIntermediateChilds(currValue) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							siblings = append(siblings, rChild) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							return t.down(newKey, lChild, siblings, path, currLvl+1, getLeaf) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							return t.down(rTx, newKey, lChild, siblings, path, currLvl+1, getLeaf) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						default: | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							return nil, nil, nil, ErrInvalidValuePrefix | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						} | 
				
			
			
		
	
	
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
				
				 | 
				
					@ -389,7 +386,8 @@ func (t *Tree) downVirtually(siblings [][]byte, oldKey, newKey []byte, oldPath, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					// up goes up recursively updating the intermediate nodes
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					func (t *Tree) up(key []byte, siblings [][]byte, path []bool, currLvl, toLvl int) ([]byte, error) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					func (t *Tree) up(wTx db.WriteTx, key []byte, siblings [][]byte, path []bool, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						currLvl, toLvl int) ([]byte, error) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						var k, v []byte | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						var err error | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						if path[currLvl+toLvl] { | 
				
			
			
		
	
	
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
				
				 | 
				
					@ -404,7 +402,7 @@ func (t *Tree) up(key []byte, siblings [][]byte, path []bool, currLvl, toLvl int | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						// store k-v to db
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						if err = t.dbPut(k, v); err != nil { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						if err = wTx.Set(k, v); err != nil { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							return nil, err | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
	
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
				
				 | 
				
					@ -413,7 +411,7 @@ func (t *Tree) up(key []byte, siblings [][]byte, path []bool, currLvl, toLvl int | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							return k, nil | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						return t.up(k, siblings, path, currLvl-1, toLvl) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						return t.up(wTx, k, siblings, path, currLvl-1, toLvl) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					func (t *Tree) newLeafValue(k, v []byte) ([]byte, []byte, error) { | 
				
			
			
		
	
	
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
				
				 | 
				
					@ -507,19 +505,30 @@ func getPath(numLevels int, k []byte) []bool { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					// Update updates the value for a given existing key. If the given key does not
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					// exist, returns an error.
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					func (t *Tree) Update(k, v []byte) error { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						wTx := t.db.WriteTx() | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						defer wTx.Discard() | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						if err := t.UpdateWithTx(wTx, k, v); err != nil { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							return err | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						return wTx.Commit() | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					// UpdateWithTx does the same than the Update method, but allowing to pass the
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					// db.WriteTx that is used. The db.WriteTx will not be committed inside this
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					// method.
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					func (t *Tree) UpdateWithTx(wTx db.WriteTx, k, v []byte) error { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						t.Lock() | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						defer t.Unlock() | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						var err error | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						t.dbBatch = t.db.NewBatch() | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						t.batchMemory = make(map[[bmKeySize]byte]kv) // TODO TMP
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						keyPath := make([]byte, t.hashFunction.Len()) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						copy(keyPath[:], k) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						path := getPath(t.maxLevels, keyPath) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						var siblings [][]byte | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						_, valueAtBottom, siblings, err := t.down(k, t.root, siblings, path, 0, true) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						_, valueAtBottom, siblings, err := t.down(wTx, k, t.root, siblings, path, 0, true) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						if err != nil { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							return err | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						} | 
				
			
			
		
	
	
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
				
				 | 
				
					@ -533,39 +542,48 @@ func (t *Tree) Update(k, v []byte) error { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							return err | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						if err := t.dbPut(leafKey, leafValue); err != nil { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						if err := wTx.Set(leafKey, leafValue); err != nil { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							return err | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						// go up to the root
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						if len(siblings) == 0 { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							t.root = leafKey | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							return t.dbBatch.Write() | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							return nil | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						root, err := t.up(leafKey, siblings, path, len(siblings)-1, 0) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						root, err := t.up(wTx, leafKey, siblings, path, len(siblings)-1, 0) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						if err != nil { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							return err | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						t.root = root | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						// store root to db
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						if err := t.dbPut(dbKeyRoot, t.root); err != nil { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						if err := wTx.Set(dbKeyRoot, t.root); err != nil { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							return err | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						return t.dbBatch.Write() | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						return nil | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					// GenProof generates a MerkleTree proof for the given key. The leaf value is
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					// returned, together with the packed siblings of the proof, and a boolean
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					// parameter that indicates if the proof is of existence (true) or not (false).
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					func (t *Tree) GenProof(k []byte) ([]byte, []byte, []byte, bool, error) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						rTx := t.db.ReadTx() | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						defer rTx.Discard() | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						return t.GenProofWithTx(rTx, k) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					// GenProofWithTx does the same than the GenProof method, but allowing to pass
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					// the db.ReadTx that is used.
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					func (t *Tree) GenProofWithTx(rTx db.ReadTx, k []byte) ([]byte, []byte, []byte, bool, error) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						keyPath := make([]byte, t.hashFunction.Len()) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						copy(keyPath[:], k) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						path := getPath(t.maxLevels, keyPath) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						// go down to the leaf
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						var siblings [][]byte | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						_, value, siblings, err := t.down(k, t.root, siblings, path, 0, true) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						_, value, siblings, err := t.down(rTx, k, t.root, siblings, path, 0, true) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						if err != nil { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							return nil, nil, nil, false, err | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						} | 
				
			
			
		
	
	
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
				
				 | 
				
					@ -656,13 +674,22 @@ func bytesToBitmap(b []byte) []bool { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					// Get returns the value for a given key
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					func (t *Tree) Get(k []byte) ([]byte, []byte, error) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						rTx := t.db.ReadTx() | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						defer rTx.Discard() | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						return t.GetWithTx(rTx, k) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					// GetWithTx does the same than the Get method, but allowing to pass the
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					// db.ReadTx that is used.
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					func (t *Tree) GetWithTx(rTx db.ReadTx, k []byte) ([]byte, []byte, error) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						keyPath := make([]byte, t.hashFunction.Len()) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						copy(keyPath[:], k) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						path := getPath(t.maxLevels, keyPath) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						// go down to the leaf
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						var siblings [][]byte | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						_, value, _, err := t.down(k, t.root, siblings, path, 0, true) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						_, value, _, err := t.down(rTx, k, t.root, siblings, path, 0, true) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						if err != nil { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							return nil, nil, err | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						} | 
				
			
			
		
	
	
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
				
				 | 
				
					@ -711,55 +738,19 @@ func CheckProof(hashFunc HashFunction, k, v, root, packedSiblings []byte) (bool, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						return false, nil | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					func (t *Tree) dbPut(k, v []byte) error { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						if t.dbBatch == nil { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							return ErrDBNoTx | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						t.dbg.incDbPut() | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						t.batchMemory.Put(k, v) // TODO TMP
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						return t.dbBatch.Put(k, v) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					func (t *Tree) dbGet(k []byte) ([]byte, error) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						// if key is empty, return empty as value
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						if bytes.Equal(k, t.emptyHash) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							return t.emptyHash, nil | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						t.dbg.incDbGet() | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						v, err := t.db.Get(k) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						if err == nil { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							return v, nil | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						if t.dbBatch != nil { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							// TODO TMP
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							v, ok := t.batchMemory.Get(k) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							if !ok { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
								return nil, ErrKeyNotFound | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							// /TMP
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							return v, nil | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						return nil, ErrKeyNotFound | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					// Warning: should be called with a Tree.dbBatch created, and with a
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					// Tree.dbBatch.Write after the incNLeafs call.
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					func (t *Tree) incNLeafs(nLeafs int) error { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					func (t *Tree) incNLeafs(wTx db.WriteTx, nLeafs int) error { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						oldNLeafs, err := t.GetNLeafs() | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						if err != nil { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							return err | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						newNLeafs := oldNLeafs + nLeafs | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						return t.setNLeafs(newNLeafs) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						return t.setNLeafs(wTx, newNLeafs) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					// Warning: should be called with a Tree.dbBatch created, and with a
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					// Tree.dbBatch.Write after the setNLeafs call.
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					func (t *Tree) setNLeafs(nLeafs int) error { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					func (t *Tree) setNLeafs(wTx db.WriteTx, nLeafs int) error { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						b := make([]byte, 8) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						binary.LittleEndian.PutUint64(b, uint64(nLeafs)) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						if err := t.dbPut(dbKeyNLeafs, b); err != nil { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						if err := wTx.Set(dbKeyNLeafs, b); err != nil { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							return err | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						return nil | 
				
			
			
		
	
	
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
				
				 | 
				
					@ -767,7 +758,16 @@ func (t *Tree) setNLeafs(nLeafs int) error { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					// GetNLeafs returns the number of Leafs of the Tree.
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					func (t *Tree) GetNLeafs() (int, error) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						b, err := t.dbGet(dbKeyNLeafs) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						rTx := t.db.ReadTx() | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						defer rTx.Discard() | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						return t.GetNLeafsWithTx(rTx) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					// GetNLeafsWithTx does the same than the GetNLeafs method, but allowing to
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					// pass the db.ReadTx that is used.
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					func (t *Tree) GetNLeafsWithTx(rTx db.ReadTx) (int, error) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						b, err := rTx.Get(dbKeyNLeafs) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						if err != nil { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							return 0, err | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						} | 
				
			
			
		
	
	
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
				
				 | 
				
					@ -802,11 +802,20 @@ func (t *Tree) Snapshot(rootKey []byte) (*Tree, error) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					// Iterate iterates through the full Tree, executing the given function on each
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					// node of the Tree.
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					func (t *Tree) Iterate(rootKey []byte, f func([]byte, []byte)) error { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						rTx := t.db.ReadTx() | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						defer rTx.Discard() | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						return t.IterateWithTx(rTx, rootKey, f) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					// IterateWithTx does the same than the Iterate method, but allowing to pass
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					// the db.ReadTx that is used.
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					func (t *Tree) IterateWithTx(rTx db.ReadTx, rootKey []byte, f func([]byte, []byte)) error { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						// allow to define which root to use
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						if rootKey == nil { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							rootKey = t.Root() | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						return t.iter(rootKey, f) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						return t.iter(rTx, rootKey, f) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					// IterateWithStop does the same than Iterate, but with int for the current
 | 
				
			
			
		
	
	
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
				
				 | 
				
					@ -817,13 +826,33 @@ func (t *Tree) IterateWithStop(rootKey []byte, f func(int, []byte, []byte) bool) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						if rootKey == nil { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							rootKey = t.Root() | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						return t.iterWithStop(rootKey, 0, f) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						rTx := t.db.ReadTx() | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						defer rTx.Discard() | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						return t.iterWithStop(rTx, rootKey, 0, f) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					func (t *Tree) iterWithStop(k []byte, currLevel int, f func(int, []byte, []byte) bool) error { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						v, err := t.dbGet(k) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						if err != nil { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							return err | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					// IterateWithStopWithTx does the same than the IterateWithStop method, but
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					// allowing to pass the db.ReadTx that is used.
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					func (t *Tree) IterateWithStopWithTx(rTx db.ReadTx, rootKey []byte, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						f func(int, []byte, []byte) bool) error { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						// allow to define which root to use
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						if rootKey == nil { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							rootKey = t.Root() | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						return t.iterWithStop(rTx, rootKey, 0, f) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					func (t *Tree) iterWithStop(rTx db.ReadTx, k []byte, currLevel int, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						f func(int, []byte, []byte) bool) error { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						var v []byte | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						var err error | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						if bytes.Equal(k, t.emptyHash) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							v = t.emptyHash | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						} else { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							v, err = rTx.Get(k) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							if err != nil { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
								return err | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						currLevel++ | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
	
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
				
				 | 
				
					@ -838,10 +867,10 @@ func (t *Tree) iterWithStop(k []byte, currLevel int, f func(int, []byte, []byte) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
								return nil | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							l, r := ReadIntermediateChilds(v) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							if err = t.iterWithStop(l, currLevel, f); err != nil { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							if err = t.iterWithStop(rTx, l, currLevel, f); err != nil { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
								return err | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							if err = t.iterWithStop(r, currLevel, f); err != nil { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							if err = t.iterWithStop(rTx, r, currLevel, f); err != nil { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
								return err | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						default: | 
				
			
			
		
	
	
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
				
				 | 
				
					@ -850,12 +879,12 @@ func (t *Tree) iterWithStop(k []byte, currLevel int, f func(int, []byte, []byte) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						return nil | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					func (t *Tree) iter(k []byte, f func([]byte, []byte)) error { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					func (t *Tree) iter(rTx db.ReadTx, k []byte, f func([]byte, []byte)) error { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						f2 := func(currLvl int, k, v []byte) bool { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							f(k, v) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							return false | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						return t.iterWithStop(k, 0, f2) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						return t.iterWithStop(rTx, k, 0, f2) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					// Dump exports all the Tree leafs in a byte array of length:
 | 
				
			
			
		
	
	
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
				
				 | 
				
					@ -936,8 +965,11 @@ node [fontname=Monospace,fontsize=10,shape=box] | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						if rootKey == nil { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							rootKey = t.Root() | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						rTx := t.db.ReadTx() | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						defer rTx.Discard() | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						nEmpties := 0 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						err := t.iterWithStop(rootKey, 0, func(currLvl int, k, v []byte) bool { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						err := t.iterWithStop(rTx, rootKey, 0, func(currLvl int, k, v []byte) bool { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							if currLvl == untilLvl { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
								return true // to stop the iter from going down
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							} | 
				
			
			
		
	
	
		
			
				
					| 
						
							
								
							
						
						
						
					 | 
				
				 | 
				
					
 |