1
0
Fork 0
mirror of https://github.com/vbatts/merkle.git synced 2024-11-27 16:55:39 +00:00

stream: Write() is mostly finished

This commit is contained in:
Vincent Batts 2015-03-26 18:24:34 -04:00
parent 68f4bcde5d
commit 257ed6dfad
2 changed files with 72 additions and 15 deletions

View file

@ -21,14 +21,13 @@ func NewHash(hm HashMaker, merkleBlockLength int) hash.Hash {
// that will validate nodes as the new bytes are written. If a new written // that will validate nodes as the new bytes are written. If a new written
// block fails checksum, then return an error on the io.Writer // block fails checksum, then return an error on the io.Writer
// 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() lastBlock []byte // as needed, for Sum()
lastBlockLen int lastBlockLen int
//partialLastBlock bool partialLastNode bool // true when Sum() has appended a Node for a partial block
} }
// 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.
@ -40,10 +39,23 @@ 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 {
if b != nil && (len(b)+mh.lastBlockLen) > mh.blockSize {
// write a full node
}
n, err := NewNodeHashBlock(mh.hm, curBlock)
if err != nil {
// XXX might need to stash again the prior lastBlock and first little chunk
return numWritten, err
}
mh.tree.Nodes = append(mh.tree.Nodes, n)
numWritten += offset
// TODO check if len(mh.lastBlock) < blockSize // TODO check if len(mh.lastBlock) < blockSize
sum, err := mh.tree.Root().Checksum() sum, err := mh.tree.Root().Checksum()
if err != nil { if err != nil {
log.Println(err) // XXX i hate to swallow an error here, but the `Sum() []byte` signature :-\
log.Printf("[ERROR]: %s", err)
} }
return sum return sum
} }
@ -63,7 +75,8 @@ func (mh *merkleHash) Write(b []byte) (int, error) {
offset int = 0 offset int = 0
) )
if mh.lastBlock != nil && mh.lastBlockLen > 0 { if mh.lastBlock != nil && mh.lastBlockLen > 0 {
numBytes = copy(curBlock[:], mh.lastBlock[:]) // XXX off by one?
numBytes = copy(curBlock[:], mh.lastBlock[:mh.lastBlockLen])
// not adding to numWritten, since these blocks were accounted for in a // not adding to numWritten, since these blocks were accounted for in a
// prior Write() // prior Write()
@ -71,8 +84,7 @@ func (mh *merkleHash) Write(b []byte) (int, error) {
offset = copy(curBlock[numBytes:], b[:(mh.blockSize-numBytes)]) offset = copy(curBlock[numBytes:], b[:(mh.blockSize-numBytes)])
n, err := NewNodeHashBlock(mh.hm, curBlock) n, err := NewNodeHashBlock(mh.hm, curBlock)
if err != nil { if err != nil {
// XXX might need to stash again the prior lastBlock and first little // XXX might need to stash again the prior lastBlock and first little chunk
// chunk
return numWritten, err return numWritten, err
} }
mh.tree.Nodes = append(mh.tree.Nodes, n) mh.tree.Nodes = append(mh.tree.Nodes, n)
@ -81,12 +93,21 @@ func (mh *merkleHash) Write(b []byte) (int, error) {
numBytes = (len(b) - offset) numBytes = (len(b) - offset)
for i := 0; i < numBytes/mh.blockSize; i++ { for i := 0; i < numBytes/mh.blockSize; i++ {
// TODO Node for curBlock //fmt.Printf("%s", b[offset:offset+mh.blockSize])
numWritten += copy(curBlock, b[offset:offset+mh.blockSize])
n, err := NewNodeHashBlock(mh.hm, curBlock)
if err != nil {
// XXX might need to stash again the prior lastBlock and first little chunk
return numWritten, err
}
mh.tree.Nodes = append(mh.tree.Nodes, n)
offset = offset + mh.blockSize
} }
// TODO stash (numBytes % mh.blockSize) in mh.lastBlock mh.lastBlockLen = numBytes % mh.blockSize
// XXX off by one?
numWritten += copy(mh.lastBlock[:], b[(len(b)-mh.lastBlockLen):])
// TODO if len(mh.lastBlock) < blockSize, then set that before returning
return numWritten, nil return numWritten, nil
} }

View file

@ -1,6 +1,42 @@
package merkle package merkle
import "testing" import (
"bytes"
"io"
"testing"
)
func TestMerkleHashWriter(t *testing.T) { func TestMerkleHashWriter(t *testing.T) {
msg := "the quick brown fox jumps over the lazy dog"
h := NewHash(DefaultHashMaker, 10)
i, err := io.Copy(h, bytes.NewBufferString(msg))
if err != nil {
t.Fatal(err)
}
if i != int64(len(msg)) {
t.Fatalf("expected to write %d, only wrote %d", len(msg), i)
}
var (
mh *merkleHash
ok bool
)
if mh, ok = h.(*merkleHash); !ok {
t.Fatalf("expected to get merkleHash, but got %#t", h)
}
// We're left with a partial lastBlock
expectedNum := 4
if len(mh.tree.Nodes) != expectedNum {
t.Errorf("expected %d nodes, got %d", expectedNum, len(mh.tree.Nodes))
}
// Next test Sum()
// count blocks again, we should get 5 nodes now
// Test Sum() again, ensure same sum
// Write more. This should pop the last node, and use the lastBlock.
} }