progress on a streaming interface

This commit is contained in:
Vincent Batts 2015-03-25 17:28:17 -04:00
parent 949cec0dce
commit fd362c6aa5
3 changed files with 74 additions and 18 deletions

22
node.go
View File

@ -1,23 +1,22 @@
package merkle package merkle
import ( import (
"crypto" "crypto/sha1"
_ "crypto/sha1" // to satisfy our DefaultHash
"fmt" "fmt"
"hash" "hash"
) )
var ( var (
// DefaultHash is for checksum of blocks and nodes // DefaultHashMaker is for checksum of blocks and nodes
DefaultHash = crypto.SHA1 DefaultHashMaker = func() hash.Hash { return sha1.New() }
) )
// HashMaker produces a new has for use in making checksums // HashMaker produces a new has for use in making checksums
type HashMaker func() hash.Hash type HashMaker func() hash.Hash
// NewNode returns a new Node with the DefaultHash for checksums // NewNode returns a new Node with the DefaultHashMaker for checksums
func NewNode() *Node { func NewNode() *Node {
return NewNodeHash(DefaultHash.New) return NewNodeHash(DefaultHashMaker)
} }
// NewNodeHash returns a new Node using the provided crypto.Hash for checksums // NewNodeHash returns a new Node using the provided crypto.Hash for checksums
@ -25,13 +24,22 @@ func NewNodeHash(h HashMaker) *Node {
return &Node{hash: h} return &Node{hash: h}
} }
// NewNodeHashBlock returns a new Node using the provided crypto.Hash, and calculates the block's checksum
func NewNodeHashBlock(h HashMaker, b []byte) *Node {
n := &Node{hash: h}
h1 := n.hash()
h1.Write(b)
n.checksum = h1.Sum(nil)
return n
}
// Node is a fundamental part of the tree. // Node is a fundamental part of the tree.
type Node struct { type Node struct {
hash HashMaker hash HashMaker
checksum []byte checksum []byte
Parent, Left, Right *Node Parent, Left, Right *Node
pos int // XXX maybe keep their order when it is a direct block's hash //pos int // XXX maybe keep their order when it is a direct block's hash
} }
// IsLeaf indicates this node is for specific block (and has no children) // IsLeaf indicates this node is for specific block (and has no children)

View File

@ -9,7 +9,7 @@ import (
func TestNodeSums(t *testing.T) { func TestNodeSums(t *testing.T) {
var ( var (
nodes []*Node nodes []*Node
h = DefaultHash.New() h = DefaultHashMaker()
words = `Who were expelled from the academy for crazy & publishing obscene odes on the windows of the skull` words = `Who were expelled from the academy for crazy & publishing obscene odes on the windows of the skull`
expectedChecksum = "819fe8fed7a46900bd0613344c5ba2be336c74db" expectedChecksum = "819fe8fed7a46900bd0613344c5ba2be336c74db"
) )
@ -19,7 +19,7 @@ func TestNodeSums(t *testing.T) {
t.Errorf("on word %q, encountered %s", word, err) t.Errorf("on word %q, encountered %s", word, err)
} }
sum := h.Sum(nil) sum := h.Sum(nil)
nodes = append(nodes, &Node{checksum: sum, hash: DefaultHash.New}) nodes = append(nodes, &Node{checksum: sum, hash: DefaultHashMaker})
} }
newNodes := nodes newNodes := nodes

View File

@ -1,14 +1,18 @@
package merkle package merkle
import "hash" import (
"hash"
"log"
)
// NewHash provides a hash.Hash to generate a merkle.Tree checksum, given a // NewHash provides a hash.Hash to generate a merkle.Tree checksum, given a
// HashMaker for the checksums of the blocks written and the blockSize of each // HashMaker for the checksums of the blocks written and the blockSize of each
// block per node in the tree. // block per node in the tree.
func NewHash(hm HashMaker, merkleBlockSize int) hash.Hash { func NewHash(hm HashMaker, merkleBlockLength int) hash.Hash {
mh := new(merkleHash) mh := new(merkleHash)
mh.blockSize = merkleBlockSize mh.blockSize = merkleBlockLength
mh.hm = hm mh.hm = hm
mh.tree = &Tree{Nodes: []*Node{}, BlockLength: merkleBlockLength}
return mh return mh
} }
@ -18,9 +22,11 @@ func NewHash(hm HashMaker, merkleBlockSize int) hash.Hash {
// TODO satisfy the hash.Hash interface // TODO satisfy the hash.Hash interface
type merkleHash struct { type merkleHash struct {
blockSize int blockSize int
tree Tree tree *Tree
hm HashMaker hm HashMaker
lastBlock []byte // as needed, for Sum()
partialLastBlock bool
} }
// XXX this will be tricky, as the last block can be less than the BlockSize. // XXX this will be tricky, as the last block can be less than the BlockSize.
@ -32,15 +38,57 @@ type merkleHash struct {
// //
// if that last block was complete, then no worries. start the next node. // if that last block was complete, then no worries. start the next node.
func (mh *merkleHash) Sum(b []byte) []byte { func (mh *merkleHash) Sum(b []byte) []byte {
return nil // TODO check if len(mh.lastBlock) < blockSize
sum, err := mh.tree.Root().Checksum()
if err != nil {
log.Println(err)
}
return sum
} }
func (mh *merkleHash) Write(b []byte) (int, error) { func (mh *merkleHash) Write(b []byte) (int, error) {
return 0, nil // basically we need to:
// * chunk these writes into blockSize
// * create Node of the sum
// * add the Node to the tree
// * stash remainder in the mh.lastBlock
var (
curBlock = make([]byte, mh.blockSize)
numBytes int = 0
numWritten int
)
if mh.lastBlock != nil && len(mh.lastBlock) > 0 {
numBytes = copy(curBlock, mh.lastBlock)
// not adding to numWritten, since these blocks were accounted for in a
// prior Write()
}
if numBytes > 0 {
copy(curBlock, b[:(mh.blockSize-numBytes)])
numWritten += (mh.blockSize - numBytes)
// TODO Node for curBlock
n := NewNodeHashBlock(mh.hm, curBlock)
_ = n
}
numBytes = len(b) - numBytes
for i := 0; i < numBytes/mh.blockSize; i++ {
// TODO Node for curBlock
}
// TODO stash (numBytes % mh.blockSize) in mh.lastBlock
// TODO if len(mh.lastBlock) < blockSize, then set that before returning
return numWritten, nil
} }
func (mh *merkleHash) Reset() { func (mh *merkleHash) Reset() {
mh.Tree = Tree{} mh.tree = &Tree{}
mh.lastBlock = nil
} }
// likely not the best to pass this through and not use our own node block
// size, but let's revisit this.
func (mh *merkleHash) BlockSize() int { return mh.hm().BlockSize() } func (mh *merkleHash) BlockSize() int { return mh.hm().BlockSize() }
func (mh *merkleHash) Size() int { return mh.hm().Size() } func (mh *merkleHash) Size() int { return mh.hm().Size() }