mirror of
https://github.com/arnaucube/arbo.git
synced 2026-01-14 09:21:30 +01:00
Add computeHashes at virtual tree
This commit is contained in:
73
vt.go
73
vt.go
@@ -2,7 +2,6 @@
|
|||||||
// without computing any hash. With the idea of once all the leafs are placed in
|
// without computing any hash. With the idea of once all the leafs are placed in
|
||||||
// their positions, the hashes can be computed, avoiding computing a node hash
|
// their positions, the hashes can be computed, avoiding computing a node hash
|
||||||
// more than one time.
|
// more than one time.
|
||||||
//nolint:unused,deadcode
|
|
||||||
package arbo
|
package arbo
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -18,7 +17,7 @@ type node struct {
|
|||||||
k []byte
|
k []byte
|
||||||
v []byte
|
v []byte
|
||||||
path []bool
|
path []bool
|
||||||
// h []byte
|
h []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
type params struct {
|
type params struct {
|
||||||
@@ -60,6 +59,18 @@ func (t *vt) add(k, v []byte) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// computeHashes should be called after all the vt.add is used, once all the
|
||||||
|
// leafs are in the tree
|
||||||
|
func (t *vt) computeHashes() ([][2][]byte, error) {
|
||||||
|
var pairs [][2][]byte
|
||||||
|
var err error
|
||||||
|
pairs, err = t.root.computeHashes(t.params, pairs)
|
||||||
|
if err != nil {
|
||||||
|
return pairs, err
|
||||||
|
}
|
||||||
|
return pairs, nil
|
||||||
|
}
|
||||||
|
|
||||||
func newLeafNode(p *params, k, v []byte) *node {
|
func newLeafNode(p *params, k, v []byte) *node {
|
||||||
keyPath := make([]byte, p.hashFunction.Len())
|
keyPath := make([]byte, p.hashFunction.Len())
|
||||||
copy(keyPath[:], k)
|
copy(keyPath[:], k)
|
||||||
@@ -150,10 +161,8 @@ func (n *node) downUntilDivergence(p *params, currLvl int, oldLeaf, newLeaf *nod
|
|||||||
return fmt.Errorf("max virtual level %d", currLvl)
|
return fmt.Errorf("max virtual level %d", currLvl)
|
||||||
}
|
}
|
||||||
|
|
||||||
// if oldLeaf.path[currLvl+1] != newLeaf.path[currLvl+1] {
|
|
||||||
if oldLeaf.path[currLvl] != newLeaf.path[currLvl] {
|
if oldLeaf.path[currLvl] != newLeaf.path[currLvl] {
|
||||||
// reached divergence in next level
|
// reached divergence in next level
|
||||||
// if newLeaf.path[currLvl+1] {
|
|
||||||
if newLeaf.path[currLvl] {
|
if newLeaf.path[currLvl] {
|
||||||
n.l = oldLeaf
|
n.l = oldLeaf
|
||||||
n.r = newLeaf
|
n.r = newLeaf
|
||||||
@@ -181,10 +190,60 @@ func (n *node) downUntilDivergence(p *params, currLvl int, oldLeaf, newLeaf *nod
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *node) computeHashes() ([]kv, error) {
|
// returns an array of key-values to store in the db
|
||||||
return nil, nil
|
func (n *node) computeHashes(p *params, pairs [][2][]byte) ([][2][]byte, error) {
|
||||||
|
if pairs == nil {
|
||||||
|
pairs = [][2][]byte{}
|
||||||
|
}
|
||||||
|
var err error
|
||||||
|
t := n.typ()
|
||||||
|
switch t {
|
||||||
|
case vtLeaf:
|
||||||
|
leafKey, leafValue, err := newLeafValue(p.hashFunction, n.k, n.v)
|
||||||
|
if err != nil {
|
||||||
|
return pairs, err
|
||||||
|
}
|
||||||
|
n.h = leafKey
|
||||||
|
kv := [2][]byte{leafKey, leafValue}
|
||||||
|
pairs = append(pairs, kv)
|
||||||
|
case vtMid:
|
||||||
|
if n.l != nil {
|
||||||
|
pairs, err = n.l.computeHashes(p, pairs)
|
||||||
|
if err != nil {
|
||||||
|
return pairs, err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
n.l = &node{
|
||||||
|
h: p.emptyHash,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if n.r != nil {
|
||||||
|
pairs, err = n.r.computeHashes(p, pairs)
|
||||||
|
if err != nil {
|
||||||
|
return pairs, err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
n.r = &node{
|
||||||
|
h: p.emptyHash,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// once the sub nodes are computed, can compute the current node
|
||||||
|
// hash
|
||||||
|
k, v, err := newIntermediate(p.hashFunction, n.l.h, n.r.h)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
n.h = k
|
||||||
|
kv := [2][]byte{k, v}
|
||||||
|
pairs = append(pairs, kv)
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("ERR TMP") // TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
return pairs, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//nolint:unused
|
||||||
func (t *vt) graphviz(w io.Writer) error {
|
func (t *vt) graphviz(w io.Writer) error {
|
||||||
fmt.Fprintf(w, `digraph hierarchy {
|
fmt.Fprintf(w, `digraph hierarchy {
|
||||||
node [fontname=Monospace,fontsize=10,shape=box]
|
node [fontname=Monospace,fontsize=10,shape=box]
|
||||||
@@ -196,6 +255,7 @@ node [fontname=Monospace,fontsize=10,shape=box]
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//nolint:unused
|
||||||
func (n *node) graphviz(w io.Writer, p *params, nEmpties int) (int, error) {
|
func (n *node) graphviz(w io.Writer, p *params, nEmpties int) (int, error) {
|
||||||
nChars := 4 // TODO move to global constant
|
nChars := 4 // TODO move to global constant
|
||||||
if n == nil {
|
if n == nil {
|
||||||
@@ -254,6 +314,7 @@ func (n *node) graphviz(w io.Writer, p *params, nEmpties int) (int, error) {
|
|||||||
return nEmpties, nil
|
return nEmpties, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//nolint:unused
|
||||||
func (t *vt) printGraphviz() error {
|
func (t *vt) printGraphviz() error {
|
||||||
w := bytes.NewBufferString("")
|
w := bytes.NewBufferString("")
|
||||||
fmt.Fprintf(w,
|
fmt.Fprintf(w,
|
||||||
|
|||||||
51
vt_test.go
Normal file
51
vt_test.go
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
package arbo
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math/big"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
qt "github.com/frankban/quicktest"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestVirtualTree(t *testing.T) {
|
||||||
|
c := qt.New(t)
|
||||||
|
vTree := newVT(10, HashFunctionSha256)
|
||||||
|
|
||||||
|
c.Assert(vTree.root, qt.IsNil)
|
||||||
|
|
||||||
|
k := BigIntToBytes(big.NewInt(1))
|
||||||
|
v := BigIntToBytes(big.NewInt(2))
|
||||||
|
err := vTree.add(k, v)
|
||||||
|
c.Assert(err, qt.IsNil)
|
||||||
|
|
||||||
|
// check values
|
||||||
|
c.Assert(vTree.root.k, qt.DeepEquals, k)
|
||||||
|
c.Assert(vTree.root.v, qt.DeepEquals, v)
|
||||||
|
|
||||||
|
// compute hashes
|
||||||
|
pairs, err := vTree.computeHashes()
|
||||||
|
c.Assert(err, qt.IsNil)
|
||||||
|
c.Assert(len(pairs), qt.Equals, 1)
|
||||||
|
|
||||||
|
rootBI := BytesToBigInt(vTree.root.h)
|
||||||
|
c.Assert(rootBI.String(), qt.Equals,
|
||||||
|
"46910109172468462938850740851377282682950237270676610513794735904325820156367")
|
||||||
|
|
||||||
|
k = BigIntToBytes(big.NewInt(33))
|
||||||
|
v = BigIntToBytes(big.NewInt(44))
|
||||||
|
err = vTree.add(k, v)
|
||||||
|
c.Assert(err, qt.IsNil)
|
||||||
|
|
||||||
|
// compute hashes
|
||||||
|
pairs, err = vTree.computeHashes()
|
||||||
|
c.Assert(err, qt.IsNil)
|
||||||
|
c.Assert(len(pairs), qt.Equals, 8)
|
||||||
|
|
||||||
|
// err = vTree.printGraphviz()
|
||||||
|
// c.Assert(err, qt.IsNil)
|
||||||
|
|
||||||
|
rootBI = BytesToBigInt(vTree.root.h)
|
||||||
|
c.Assert(rootBI.String(), qt.Equals,
|
||||||
|
"59481735341404520835410489183267411392292882901306595567679529387376287440550")
|
||||||
|
c.Assert(err, qt.IsNil)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user