Use errors (instead of error codes)

This commit is contained in:
Oren 2017-03-26 12:00:20 +03:00
parent 44a9a39c84
commit fe85196dd6
2 changed files with 49 additions and 97 deletions

View file

@ -58,9 +58,9 @@ func (t BTree) Root() []byte {
// if incorrectly built or modified. // if incorrectly built or modified.
// Checks the rep invariants // Checks the rep invariants
func (t BTree) Validate() error { func (t BTree) Validate() error {
count, height, error := t.root.validate() count, height, err := t.root.validate()
if error != nil { if err != nil {
return error return err
} }
if count != t.count { if count != t.count {
return fmt.Errorf("Incorrect count. Was %d, should be %d", t.count, count) return fmt.Errorf("Incorrect count. Was %d, should be %d", t.count, count)
@ -122,7 +122,7 @@ func rootHash(count uint64, data []byte) []byte {
h.Reset() h.Reset()
h.Write(data) h.Write(data)
binary.Write(h, binary.LittleEndian, count) binary.Write(h, binary.LittleEndian, count)
return h.Sum(make([]byte, 0)) return h.Sum(nil)
} }
func makeHash(left, right *node) []byte { func makeHash(left, right *node) []byte {
@ -156,21 +156,21 @@ func GetHeight(count uint64) int {
// BMT - The BMT Representation of the data // BMT - The BMT Representation of the data
// ROOT - BMT Root // ROOT - BMT Root
// Count - Numers of leafs at the BMT // Count - Numers of leafs at the BMT
// error - if exist validation(-1) count(-2) ok(0) // error -
func BuildBMT(h Hasher, data []byte, segmentsize int) (bmt *BTree, roor *Root, count int, errorcode int) { func BuildBMT(h Hasher, data []byte, segmentsize int) (bmt *BTree, roor *Root, count int, err error) {
blocks := splitData(data, segmentsize) blocks := splitData(data, segmentsize)
hashFunc = h hashFunc = h
leafcount := len(blocks) leafcount := len(blocks)
tree := Build(blocks) tree := Build(blocks)
err := tree.Validate() err = tree.Validate()
if err != nil { if err != nil {
return nil, nil, 0, -1 return nil, nil, 0, errors.New("Validation error")
} }
if tree.Count() != uint64(leafcount) { if tree.Count() != uint64(leafcount) {
return nil, nil, 0, -2 return nil, nil, 0, errors.New("Validation count error")
} }
return tree, &Root{uint64(leafcount), tree.Root()}, leafcount, 0 return tree, &Root{uint64(leafcount), tree.Root()}, leafcount, nil
//r := Root{uint64(count), tree.Root()} //r := Root{uint64(count), tree.Root()}
} }
@ -260,30 +260,29 @@ type Root struct {
} }
// Proves the inclusion of an element at the given index with the value thats the first entry in proof // Proves the inclusion of an element at the given index with the value thats the first entry in proof
func (r *Root) CheckProof(h Hasher, proof [][]byte, index int) bool { func (r *Root) CheckProof(h Hasher, proof [][]byte, index int) (bool, error) {
hashFunc = h hashFunc = h
t_height := GetHeight(r.Count) theight := GetHeight(r.Count)
root, ok := checkNode(t_height, proof, uint64(index), r.Count) var root, ok, err = checkNode(theight, proof, uint64(index), r.Count)
base := rootHash(r.Count, root) base := rootHash(r.Count, root)
return ok && bytes.Equal(r.Base, base) return ok && bytes.Equal(r.Base, base), err
} }
func checkNode(height int, proof [][]byte, index, count uint64) ([]byte, bool) { func checkNode(height int, proof [][]byte, index uint64, count uint64) (hash []byte, ok bool, err error) {
if len(proof) == 0 { if len(proof) == 0 {
fmt.Println("Empty") return nil, false, errors.New("checkNode : proof is empty")
return nil, false
} }
if count <= index { if count <= index {
fmt.Println("bad count", count, index) fmt.Println("bad count", count, index)
return nil, false return nil, false, fmt.Errorf("bad count %d at index %d", count, index)
} }
if height == 1 { if height == 1 {
if index != 0 || len(proof) != 1 { if index != 0 || len(proof) != 1 {
fmt.Println("BAD", index, proof) fmt.Println("BAD", index, proof)
return nil, false return nil, false, fmt.Errorf("BAD %d %d", index, proof)
} }
return proof[0], true return proof[0], true, nil
} }
childIndex := index >> uint(height-2) childIndex := index >> uint(height-2)
@ -291,7 +290,7 @@ func checkNode(height int, proof [][]byte, index, count uint64) ([]byte, bool) {
nextIndex := index & mask nextIndex := index & mask
var data []byte var data []byte
var ok bool //var ok bool
h := hashFunc() h := hashFunc()
h.Reset() h.Reset()
@ -301,7 +300,7 @@ func checkNode(height int, proof [][]byte, index, count uint64) ([]byte, bool) {
if childIndex == 1 { if childIndex == 1 {
nextCount = count & mask nextCount = count & mask
h.Write(proof[last]) h.Write(proof[last])
data, ok = checkNode(height-1, proof[:last], nextIndex, nextCount) data, ok, err = checkNode(height-1, proof[:last], nextIndex, nextCount)
h.Write(data) h.Write(data)
} else { } else {
nextCount = count nextCount = count
@ -309,39 +308,38 @@ func checkNode(height int, proof [][]byte, index, count uint64) ([]byte, bool) {
nextCount = ^mask nextCount = ^mask
} }
if count == nextCount { if count == nextCount {
data, ok = checkNode(height-1, proof, nextIndex, nextCount) data, ok, err = checkNode(height-1, proof, nextIndex, nextCount)
h.Write(data) h.Write(data)
} else { } else {
data, ok = checkNode(height-1, proof[:last], nextIndex, nextCount) data, ok, err = checkNode(height-1, proof[:last], nextIndex, nextCount)
h.Write(data) h.Write(data)
h.Write(proof[last]) h.Write(proof[last])
} }
} }
hash := h.Sum(make([]byte, 0)) hash = h.Sum(make([]byte, 0))
return hash, ok return hash, ok, nil
} }
// ShakeHash defines the interface to hash functions that // BMTHash defines the interface to hash functions that
// support arbitrary-length output.
type BMTHash interface { type BMTHash interface {
// Write absorbs more data into the hash's state. It panics if input is // Write absorbs more data into the hash's state. It panics if input is
// written to it after output has been read from it. // written to it after output has been read from it.
io.Writer io.Writer
// Read reads more output from the hash; reading affects the hash's // Read reads more output from the hash; reading affects the hash's
// state. (ShakeHash.Read is thus very different from Hash.Sum) // state.
// It never returns an error. // It never returns an error.
io.Reader io.Reader
// Clone returns a copy of the ShakeHash in its current state. // Clone returns a copy of the BMTHash in its current state.
Clone() BMTHash Clone() BMTHash
// Reset resets the ShakeHash to its initial state. // Reset resets the BMTHash to its initial state.
Reset() Reset()
} }
// Reset clears the internal state by zeroing the sponge state and // Reset clears the internal state
func (d *state) Reset() { func (d *state) Reset() {
d.root = Root{Count: 0, Base: nil} d.root = Root{Count: 0, Base: nil}
d.btree = BTree{count: 0, root: nil, rootHash: nil} d.btree = BTree{count: 0, root: nil, rootHash: nil}
@ -354,7 +352,7 @@ func (d *state) Write(p []byte) (written int, err error) {
d.btree = *tree d.btree = *tree
d.root = *r d.root = *r
if err1 != 0 { if err1 != nil {
err = errors.New("bmt write error") err = errors.New("bmt write error")
} }

View file

@ -2,53 +2,17 @@ package storage
import ( import (
"fmt" "fmt"
"io/ioutil"
"testing" "testing"
"github.com/ethereum/go-ethereum/crypto/sha3" "github.com/ethereum/go-ethereum/crypto/sha3"
) )
func TestGetHeight(t *testing.T) {
data := [][2]int{
{0, 0},
{1, 1},
{2, 2},
{3, 3},
{4, 3},
{255, 9},
{256, 9},
{257, 10},
}
for _, v := range data {
h := GetHeight(uint64(v[0]))
if !(v[1] == h) {
t.Errorf("GetHeight(%d)!=%d (was %d)", v[0], v[1], h)
}
}
}
func TestGetHeight2(t *testing.T) {
for i := 1; i < 1000; i++ {
h := GetHeight(uint64(i))
upperBound := 1 << uint(h-1)
lowerBound := (1 << uint(h-2)) + 1
if i < lowerBound {
t.Errorf("GetHeight(%d) too high: %d", i, h)
}
if i > upperBound {
t.Errorf("GetHeight(%d) too low: %d", i, h)
}
}
}
func TestBuildBMT3(t *testing.T) { func TestBuildBMT3(t *testing.T) {
// Grab some data to make the tree out of, and partition // Grab some data to make the tree out of, and partition
data, err := ioutil.ReadFile("binarymerkle_test.go") // assume testdata exists data := make([]byte, 4096)
if err != nil { tdata := testDataReader(4096)
fmt.Println(err) tdata.Read(data)
return
}
var thashFunc = MakeHashFunc("BMTSHA3") var thashFunc = MakeHashFunc("BMTSHA3")
var h = thashFunc() var h = thashFunc()
h.Reset() h.Reset()
@ -73,35 +37,28 @@ func TestBuildBMT3(t *testing.T) {
func TestBuildBMT(t *testing.T) { func TestBuildBMT(t *testing.T) {
// Grab some data to make the tree out of, and partition // Grab some data to make the tree out of, and partition
data, err := ioutil.ReadFile("binarymerkle_test.go") // assume testdata exists data := make([]byte, 4096)
if err != nil { tdata := testDataReader(4096)
fmt.Println(err) tdata.Read(data)
return
}
tree, r, count, err1 := BuildBMT(sha3.NewKeccak256, data, 1) tree, r, count, err1 := BuildBMT(sha3.NewKeccak256, data, 1)
switch err1 { if err1 != nil {
case -1: fmt.Println(err1)
t.Errorf("BMT Validation error")
return return
case -2:
t.Errorf("BMT leaf count validation error")
return
case 0:
fmt.Println("Build BMT OK ", count)
} }
fmt.Println(tree.Root()) fmt.Println(tree.Root())
//var ok bool
for i := 0; i < count; i++ { for i := 0; i < count; i++ {
p := tree.InclusionProof(i) p := tree.InclusionProof(i)
fmt.Println(p) fmt.Println(p)
ok := r.CheckProof(sha3.NewKeccak256, p, i) ok, err := r.CheckProof(sha3.NewKeccak256, p, i)
if !ok {
if !ok || (err != nil) {
t.Errorf("proof %d failed", i) t.Errorf("proof %d failed", i)
} }
} }
@ -110,12 +67,9 @@ func TestBuildBMT(t *testing.T) {
func TestBuildBMT2(t *testing.T) { func TestBuildBMT2(t *testing.T) {
// Grab some data to make the tree out of, and partition data := make([]byte, 4096)
data, err := ioutil.ReadFile("binarymerkle_test.go") // assume testdata exists tdata := testDataReader(4096)
if err != nil { tdata.Read(data)
fmt.Println(err)
return
}
fmt.Println(len(data)) fmt.Println(len(data))
blocks := splitData(data, 2) blocks := splitData(data, 2)
@ -142,8 +96,8 @@ func TestBuildBMT2(t *testing.T) {
fmt.Println(p) fmt.Println(p)
ok := r.CheckProof(sha3.NewKeccak256, p, i) ok, err := r.CheckProof(sha3.NewKeccak256, p, i)
if !ok { if !ok || (err != nil) {
t.Errorf("proof %d failed", i) t.Errorf("proof %d failed", i)
} }
} }