From dfbdf083e215ad8379b331c461da23a62a3f6eb2 Mon Sep 17 00:00:00 2001
From: Juan Batiz-Benet <juan@benet.ai>
Date: Fri, 4 Jul 2014 16:55:03 -0700
Subject: [PATCH] merkledag objects

---
 merkledag/coding.go         |  12 +
 merkledag/merkledag.go      |  35 +-
 merkledag/merkledag_test.go |  48 +++
 merkledag/node.pb.go        | 802 ++++++++++++++++++++++++++++++++++++
 merkledag/nodepb_test.go    | 472 +++++++++++++++++++++
 5 files changed, 1366 insertions(+), 3 deletions(-)
 create mode 100644 merkledag/merkledag_test.go
 create mode 100644 merkledag/node.pb.go
 create mode 100644 merkledag/nodepb_test.go

diff --git a/merkledag/coding.go b/merkledag/coding.go
index 7eac3d2da..76763ec42 100644
--- a/merkledag/coding.go
+++ b/merkledag/coding.go
@@ -59,3 +59,15 @@ func (n *Node) getPBNode() *PBNode {
 	pbn.Data = n.Data
 	return pbn
 }
+
+func (n *Node) Encoded(force bool) ([]byte, error) {
+	if n.encoded == nil || force {
+		var err error
+		n.encoded, err = n.Marshal()
+		if err != nil {
+			return []byte{}, err
+		}
+	}
+
+	return n.encoded, nil
+}
diff --git a/merkledag/merkledag.go b/merkledag/merkledag.go
index 0dc814140..46e41575e 100644
--- a/merkledag/merkledag.go
+++ b/merkledag/merkledag.go
@@ -9,6 +9,9 @@ import (
 type Node struct {
 	Links []*Link
 	Data  []byte
+
+	// cache encoded/marshaled value
+	encoded []byte
 }
 
 // An IPFS Merkle DAG Link
@@ -23,17 +26,43 @@ type Link struct {
 	Hash mh.Multihash
 }
 
-type EncodedNode []byte
+func (n *Node) AddNodeLink(name string, that *Node) error {
+	s, err := that.Size()
+	if err != nil {
+		return err
+	}
+
+	h, err := that.Multihash()
+	if err != nil {
+		return err
+	}
+
+	n.Links = append(n.Links, &Link{
+		Name: name,
+		Size: s,
+		Hash: h,
+	})
+	return nil
+}
 
 func (n *Node) Size() (uint64, error) {
-	d, err := n.Marshal()
+	b, err := n.Encoded(false)
 	if err != nil {
 		return 0, err
 	}
 
-	s := uint64(len(d))
+	s := uint64(len(b))
 	for _, l := range n.Links {
 		s += l.Size
 	}
 	return s, nil
 }
+
+func (n *Node) Multihash() (mh.Multihash, error) {
+	b, err := n.Encoded(false)
+	if err != nil {
+		return nil, err
+	}
+
+	return mh.Sum(b, mh.SHA2_256, -1)
+}
diff --git a/merkledag/merkledag_test.go b/merkledag/merkledag_test.go
new file mode 100644
index 000000000..fd261c1f5
--- /dev/null
+++ b/merkledag/merkledag_test.go
@@ -0,0 +1,48 @@
+package merkledag
+
+import (
+	"fmt"
+	// mh "github.com/jbenet/go-multihash"
+	"testing"
+)
+
+func TestNode(t *testing.T) {
+
+	n1 := &Node{Data: []byte("beep")}
+	n2 := &Node{Data: []byte("boop")}
+	n3 := &Node{Data: []byte("beep boop")}
+	if err := n3.AddNodeLink("beep-link", n1); err != nil {
+		t.Error(err)
+	}
+	if err := n3.AddNodeLink("boop-link", n2); err != nil {
+		t.Error(err)
+	}
+
+	printn := func(name string, n *Node) {
+		fmt.Println(">", name)
+		fmt.Println("data:", string(n.Data))
+
+		fmt.Println("links:")
+		for _, l := range n.Links {
+			fmt.Println("-", l.Name, l.Size, l.Hash)
+		}
+
+		e, err := n.Encoded(false)
+		if err != nil {
+			t.Error(err)
+		} else {
+			fmt.Println("encoded:", e)
+		}
+
+		h, err := n.Multihash()
+		if err != nil {
+			t.Error(err)
+		} else {
+			fmt.Println("hash:", h)
+		}
+	}
+
+	printn("beep", n1)
+	printn("boop", n2)
+	printn("beep boop", n3)
+}
diff --git a/merkledag/node.pb.go b/merkledag/node.pb.go
new file mode 100644
index 000000000..e6442e4d1
--- /dev/null
+++ b/merkledag/node.pb.go
@@ -0,0 +1,802 @@
+// Code generated by protoc-gen-gogo.
+// source: node.proto
+// DO NOT EDIT!
+
+/*
+	Package merkledag is a generated protocol buffer package.
+
+	It is generated from these files:
+		node.proto
+
+	It has these top-level messages:
+		PBLink
+		PBNode
+*/
+package merkledag
+
+import proto "code.google.com/p/gogoprotobuf/proto"
+import json "encoding/json"
+import math "math"
+
+// discarding unused import gogoproto "code.google.com/p/gogoprotobuf/gogoproto/gogo.pb"
+
+import io "io"
+import code_google_com_p_gogoprotobuf_proto "code.google.com/p/gogoprotobuf/proto"
+
+import fmt "fmt"
+import strings "strings"
+import reflect "reflect"
+
+import fmt1 "fmt"
+import strings1 "strings"
+import code_google_com_p_gogoprotobuf_proto1 "code.google.com/p/gogoprotobuf/proto"
+import sort "sort"
+import strconv "strconv"
+import reflect1 "reflect"
+
+import fmt2 "fmt"
+import bytes "bytes"
+
+// Reference proto, json, and math imports to suppress error if they are not otherwise used.
+var _ = proto.Marshal
+var _ = &json.SyntaxError{}
+var _ = math.Inf
+
+// An IPFS MerkleDAG Link
+type PBLink struct {
+	// multihash of the target object
+	Hash []byte `protobuf:"bytes,1,opt" json:"Hash,omitempty"`
+	// utf string name. should be unique per object
+	Name *string `protobuf:"bytes,2,opt" json:"Name,omitempty"`
+	// cumulative size of target object
+	Tsize            *uint64 `protobuf:"varint,3,opt" json:"Tsize,omitempty"`
+	XXX_unrecognized []byte  `json:"-"`
+}
+
+func (m *PBLink) Reset()      { *m = PBLink{} }
+func (*PBLink) ProtoMessage() {}
+
+func (m *PBLink) GetHash() []byte {
+	if m != nil {
+		return m.Hash
+	}
+	return nil
+}
+
+func (m *PBLink) GetName() string {
+	if m != nil && m.Name != nil {
+		return *m.Name
+	}
+	return ""
+}
+
+func (m *PBLink) GetTsize() uint64 {
+	if m != nil && m.Tsize != nil {
+		return *m.Tsize
+	}
+	return 0
+}
+
+// An IPFS MerkleDAG Node
+type PBNode struct {
+	// refs to other objects
+	Links []*PBLink `protobuf:"bytes,2,rep" json:"Links,omitempty"`
+	// opaque user data
+	Data             []byte `protobuf:"bytes,1,opt" json:"Data,omitempty"`
+	XXX_unrecognized []byte `json:"-"`
+}
+
+func (m *PBNode) Reset()      { *m = PBNode{} }
+func (*PBNode) ProtoMessage() {}
+
+func (m *PBNode) GetLinks() []*PBLink {
+	if m != nil {
+		return m.Links
+	}
+	return nil
+}
+
+func (m *PBNode) GetData() []byte {
+	if m != nil {
+		return m.Data
+	}
+	return nil
+}
+
+func init() {
+}
+func (m *PBLink) Unmarshal(data []byte) error {
+	l := len(data)
+	index := 0
+	for index < l {
+		var wire uint64
+		for shift := uint(0); ; shift += 7 {
+			if index >= l {
+				return io.ErrUnexpectedEOF
+			}
+			b := data[index]
+			index++
+			wire |= (uint64(b) & 0x7F) << shift
+			if b < 0x80 {
+				break
+			}
+		}
+		fieldNum := int32(wire >> 3)
+		wireType := int(wire & 0x7)
+		switch fieldNum {
+		case 1:
+			if wireType != 2 {
+				return code_google_com_p_gogoprotobuf_proto.ErrWrongType
+			}
+			var byteLen int
+			for shift := uint(0); ; shift += 7 {
+				if index >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := data[index]
+				index++
+				byteLen |= (int(b) & 0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			postIndex := index + byteLen
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			m.Hash = append(m.Hash, data[index:postIndex]...)
+			index = postIndex
+		case 2:
+			if wireType != 2 {
+				return code_google_com_p_gogoprotobuf_proto.ErrWrongType
+			}
+			var stringLen uint64
+			for shift := uint(0); ; shift += 7 {
+				if index >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := data[index]
+				index++
+				stringLen |= (uint64(b) & 0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			postIndex := index + int(stringLen)
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			s := string(data[index:postIndex])
+			m.Name = &s
+			index = postIndex
+		case 3:
+			if wireType != 0 {
+				return code_google_com_p_gogoprotobuf_proto.ErrWrongType
+			}
+			var v uint64
+			for shift := uint(0); ; shift += 7 {
+				if index >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := data[index]
+				index++
+				v |= (uint64(b) & 0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			m.Tsize = &v
+		default:
+			var sizeOfWire int
+			for {
+				sizeOfWire++
+				wire >>= 7
+				if wire == 0 {
+					break
+				}
+			}
+			index -= sizeOfWire
+			skippy, err := code_google_com_p_gogoprotobuf_proto.Skip(data[index:])
+			if err != nil {
+				return err
+			}
+			if (index + skippy) > l {
+				return io.ErrUnexpectedEOF
+			}
+			m.XXX_unrecognized = append(m.XXX_unrecognized, data[index:index+skippy]...)
+			index += skippy
+		}
+	}
+	return nil
+}
+func (m *PBNode) Unmarshal(data []byte) error {
+	l := len(data)
+	index := 0
+	for index < l {
+		var wire uint64
+		for shift := uint(0); ; shift += 7 {
+			if index >= l {
+				return io.ErrUnexpectedEOF
+			}
+			b := data[index]
+			index++
+			wire |= (uint64(b) & 0x7F) << shift
+			if b < 0x80 {
+				break
+			}
+		}
+		fieldNum := int32(wire >> 3)
+		wireType := int(wire & 0x7)
+		switch fieldNum {
+		case 2:
+			if wireType != 2 {
+				return code_google_com_p_gogoprotobuf_proto.ErrWrongType
+			}
+			var msglen int
+			for shift := uint(0); ; shift += 7 {
+				if index >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := data[index]
+				index++
+				msglen |= (int(b) & 0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			postIndex := index + msglen
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			m.Links = append(m.Links, &PBLink{})
+			m.Links[len(m.Links)-1].Unmarshal(data[index:postIndex])
+			index = postIndex
+		case 1:
+			if wireType != 2 {
+				return code_google_com_p_gogoprotobuf_proto.ErrWrongType
+			}
+			var byteLen int
+			for shift := uint(0); ; shift += 7 {
+				if index >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := data[index]
+				index++
+				byteLen |= (int(b) & 0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			postIndex := index + byteLen
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			m.Data = append(m.Data, data[index:postIndex]...)
+			index = postIndex
+		default:
+			var sizeOfWire int
+			for {
+				sizeOfWire++
+				wire >>= 7
+				if wire == 0 {
+					break
+				}
+			}
+			index -= sizeOfWire
+			skippy, err := code_google_com_p_gogoprotobuf_proto.Skip(data[index:])
+			if err != nil {
+				return err
+			}
+			if (index + skippy) > l {
+				return io.ErrUnexpectedEOF
+			}
+			m.XXX_unrecognized = append(m.XXX_unrecognized, data[index:index+skippy]...)
+			index += skippy
+		}
+	}
+	return nil
+}
+func (this *PBLink) String() string {
+	if this == nil {
+		return "nil"
+	}
+	s := strings.Join([]string{`&PBLink{`,
+		`Hash:` + valueToStringNode(this.Hash) + `,`,
+		`Name:` + valueToStringNode(this.Name) + `,`,
+		`Tsize:` + valueToStringNode(this.Tsize) + `,`,
+		`XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`,
+		`}`,
+	}, "")
+	return s
+}
+func (this *PBNode) String() string {
+	if this == nil {
+		return "nil"
+	}
+	s := strings.Join([]string{`&PBNode{`,
+		`Links:` + strings.Replace(fmt.Sprintf("%v", this.Links), "PBLink", "PBLink", 1) + `,`,
+		`Data:` + valueToStringNode(this.Data) + `,`,
+		`XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`,
+		`}`,
+	}, "")
+	return s
+}
+func valueToStringNode(v interface{}) string {
+	rv := reflect.ValueOf(v)
+	if rv.IsNil() {
+		return "nil"
+	}
+	pv := reflect.Indirect(rv).Interface()
+	return fmt.Sprintf("*%v", pv)
+}
+func (m *PBLink) Size() (n int) {
+	var l int
+	_ = l
+	if m.Hash != nil {
+		l = len(m.Hash)
+		n += 1 + l + sovNode(uint64(l))
+	}
+	if m.Name != nil {
+		l = len(*m.Name)
+		n += 1 + l + sovNode(uint64(l))
+	}
+	if m.Tsize != nil {
+		n += 1 + sovNode(uint64(*m.Tsize))
+	}
+	if m.XXX_unrecognized != nil {
+		n += len(m.XXX_unrecognized)
+	}
+	return n
+}
+func (m *PBNode) Size() (n int) {
+	var l int
+	_ = l
+	if len(m.Links) > 0 {
+		for _, e := range m.Links {
+			l = e.Size()
+			n += 1 + l + sovNode(uint64(l))
+		}
+	}
+	if m.Data != nil {
+		l = len(m.Data)
+		n += 1 + l + sovNode(uint64(l))
+	}
+	if m.XXX_unrecognized != nil {
+		n += len(m.XXX_unrecognized)
+	}
+	return n
+}
+
+func sovNode(x uint64) (n int) {
+	for {
+		n++
+		x >>= 7
+		if x == 0 {
+			break
+		}
+	}
+	return n
+}
+func sozNode(x uint64) (n int) {
+	return sovNode(uint64((x << 1) ^ uint64((int64(x) >> 63))))
+}
+func NewPopulatedPBLink(r randyNode, easy bool) *PBLink {
+	this := &PBLink{}
+	if r.Intn(10) != 0 {
+		v1 := r.Intn(100)
+		this.Hash = make([]byte, v1)
+		for i := 0; i < v1; i++ {
+			this.Hash[i] = byte(r.Intn(256))
+		}
+	}
+	if r.Intn(10) != 0 {
+		v2 := randStringNode(r)
+		this.Name = &v2
+	}
+	if r.Intn(10) != 0 {
+		v3 := uint64(r.Uint32())
+		this.Tsize = &v3
+	}
+	if !easy && r.Intn(10) != 0 {
+		this.XXX_unrecognized = randUnrecognizedNode(r, 4)
+	}
+	return this
+}
+
+func NewPopulatedPBNode(r randyNode, easy bool) *PBNode {
+	this := &PBNode{}
+	if r.Intn(10) != 0 {
+		v4 := r.Intn(10)
+		this.Links = make([]*PBLink, v4)
+		for i := 0; i < v4; i++ {
+			this.Links[i] = NewPopulatedPBLink(r, easy)
+		}
+	}
+	if r.Intn(10) != 0 {
+		v5 := r.Intn(100)
+		this.Data = make([]byte, v5)
+		for i := 0; i < v5; i++ {
+			this.Data[i] = byte(r.Intn(256))
+		}
+	}
+	if !easy && r.Intn(10) != 0 {
+		this.XXX_unrecognized = randUnrecognizedNode(r, 3)
+	}
+	return this
+}
+
+type randyNode interface {
+	Float32() float32
+	Float64() float64
+	Int63() int64
+	Int31() int32
+	Uint32() uint32
+	Intn(n int) int
+}
+
+func randUTF8RuneNode(r randyNode) rune {
+	res := rune(r.Uint32() % 1112064)
+	if 55296 <= res {
+		res += 2047
+	}
+	return res
+}
+func randStringNode(r randyNode) string {
+	v6 := r.Intn(100)
+	tmps := make([]rune, v6)
+	for i := 0; i < v6; i++ {
+		tmps[i] = randUTF8RuneNode(r)
+	}
+	return string(tmps)
+}
+func randUnrecognizedNode(r randyNode, maxFieldNumber int) (data []byte) {
+	l := r.Intn(5)
+	for i := 0; i < l; i++ {
+		wire := r.Intn(4)
+		if wire == 3 {
+			wire = 5
+		}
+		fieldNumber := maxFieldNumber + r.Intn(100)
+		data = randFieldNode(data, r, fieldNumber, wire)
+	}
+	return data
+}
+func randFieldNode(data []byte, r randyNode, fieldNumber int, wire int) []byte {
+	key := uint32(fieldNumber)<<3 | uint32(wire)
+	switch wire {
+	case 0:
+		data = encodeVarintPopulateNode(data, uint64(key))
+		v7 := r.Int63()
+		if r.Intn(2) == 0 {
+			v7 *= -1
+		}
+		data = encodeVarintPopulateNode(data, uint64(v7))
+	case 1:
+		data = encodeVarintPopulateNode(data, uint64(key))
+		data = append(data, byte(r.Intn(256)), byte(r.Intn(256)), byte(r.Intn(256)), byte(r.Intn(256)), byte(r.Intn(256)), byte(r.Intn(256)), byte(r.Intn(256)), byte(r.Intn(256)))
+	case 2:
+		data = encodeVarintPopulateNode(data, uint64(key))
+		ll := r.Intn(100)
+		data = encodeVarintPopulateNode(data, uint64(ll))
+		for j := 0; j < ll; j++ {
+			data = append(data, byte(r.Intn(256)))
+		}
+	default:
+		data = encodeVarintPopulateNode(data, uint64(key))
+		data = append(data, byte(r.Intn(256)), byte(r.Intn(256)), byte(r.Intn(256)), byte(r.Intn(256)))
+	}
+	return data
+}
+func encodeVarintPopulateNode(data []byte, v uint64) []byte {
+	for v >= 1<<7 {
+		data = append(data, uint8(uint64(v)&0x7f|0x80))
+		v >>= 7
+	}
+	data = append(data, uint8(v))
+	return data
+}
+func (m *PBLink) Marshal() (data []byte, err error) {
+	size := m.Size()
+	data = make([]byte, size)
+	n, err := m.MarshalTo(data)
+	if err != nil {
+		return nil, err
+	}
+	return data[:n], nil
+}
+
+func (m *PBLink) MarshalTo(data []byte) (n int, err error) {
+	var i int
+	_ = i
+	var l int
+	_ = l
+	if m.Hash != nil {
+		data[i] = 0xa
+		i++
+		i = encodeVarintNode(data, i, uint64(len(m.Hash)))
+		i += copy(data[i:], m.Hash)
+	}
+	if m.Name != nil {
+		data[i] = 0x12
+		i++
+		i = encodeVarintNode(data, i, uint64(len(*m.Name)))
+		i += copy(data[i:], *m.Name)
+	}
+	if m.Tsize != nil {
+		data[i] = 0x18
+		i++
+		i = encodeVarintNode(data, i, uint64(*m.Tsize))
+	}
+	if m.XXX_unrecognized != nil {
+		i += copy(data[i:], m.XXX_unrecognized)
+	}
+	return i, nil
+}
+func (m *PBNode) Marshal() (data []byte, err error) {
+	size := m.Size()
+	data = make([]byte, size)
+	n, err := m.MarshalTo(data)
+	if err != nil {
+		return nil, err
+	}
+	return data[:n], nil
+}
+
+func (m *PBNode) MarshalTo(data []byte) (n int, err error) {
+	var i int
+	_ = i
+	var l int
+	_ = l
+	if len(m.Links) > 0 {
+		for _, msg := range m.Links {
+			data[i] = 0x12
+			i++
+			i = encodeVarintNode(data, i, uint64(msg.Size()))
+			n, err := msg.MarshalTo(data[i:])
+			if err != nil {
+				return 0, err
+			}
+			i += n
+		}
+	}
+	if m.Data != nil {
+		data[i] = 0xa
+		i++
+		i = encodeVarintNode(data, i, uint64(len(m.Data)))
+		i += copy(data[i:], m.Data)
+	}
+	if m.XXX_unrecognized != nil {
+		i += copy(data[i:], m.XXX_unrecognized)
+	}
+	return i, nil
+}
+func encodeFixed64Node(data []byte, offset int, v uint64) int {
+	data[offset] = uint8(v)
+	data[offset+1] = uint8(v >> 8)
+	data[offset+2] = uint8(v >> 16)
+	data[offset+3] = uint8(v >> 24)
+	data[offset+4] = uint8(v >> 32)
+	data[offset+5] = uint8(v >> 40)
+	data[offset+6] = uint8(v >> 48)
+	data[offset+7] = uint8(v >> 56)
+	return offset + 8
+}
+func encodeFixed32Node(data []byte, offset int, v uint32) int {
+	data[offset] = uint8(v)
+	data[offset+1] = uint8(v >> 8)
+	data[offset+2] = uint8(v >> 16)
+	data[offset+3] = uint8(v >> 24)
+	return offset + 4
+}
+func encodeVarintNode(data []byte, offset int, v uint64) int {
+	for v >= 1<<7 {
+		data[offset] = uint8(v&0x7f | 0x80)
+		v >>= 7
+		offset++
+	}
+	data[offset] = uint8(v)
+	return offset + 1
+}
+func (this *PBLink) GoString() string {
+	if this == nil {
+		return "nil"
+	}
+	s := strings1.Join([]string{`&merkledag.PBLink{` + `Hash:` + valueToGoStringNode(this.Hash, "byte"), `Name:` + valueToGoStringNode(this.Name, "string"), `Tsize:` + valueToGoStringNode(this.Tsize, "uint64"), `XXX_unrecognized:` + fmt1.Sprintf("%#v", this.XXX_unrecognized) + `}`}, ", ")
+	return s
+}
+func (this *PBNode) GoString() string {
+	if this == nil {
+		return "nil"
+	}
+	s := strings1.Join([]string{`&merkledag.PBNode{` + `Links:` + fmt1.Sprintf("%#v", this.Links), `Data:` + valueToGoStringNode(this.Data, "byte"), `XXX_unrecognized:` + fmt1.Sprintf("%#v", this.XXX_unrecognized) + `}`}, ", ")
+	return s
+}
+func valueToGoStringNode(v interface{}, typ string) string {
+	rv := reflect1.ValueOf(v)
+	if rv.IsNil() {
+		return "nil"
+	}
+	pv := reflect1.Indirect(rv).Interface()
+	return fmt1.Sprintf("func(v %v) *%v { return &v } ( %#v )", typ, typ, pv)
+}
+func extensionToGoStringNode(e map[int32]code_google_com_p_gogoprotobuf_proto1.Extension) string {
+	if e == nil {
+		return "nil"
+	}
+	s := "map[int32]proto.Extension{"
+	keys := make([]int, 0, len(e))
+	for k := range e {
+		keys = append(keys, int(k))
+	}
+	sort.Ints(keys)
+	ss := []string{}
+	for _, k := range keys {
+		ss = append(ss, strconv.Itoa(k)+": "+e[int32(k)].GoString())
+	}
+	s += strings1.Join(ss, ",") + "}"
+	return s
+}
+func (this *PBLink) VerboseEqual(that interface{}) error {
+	if that == nil {
+		if this == nil {
+			return nil
+		}
+		return fmt2.Errorf("that == nil && this != nil")
+	}
+
+	that1, ok := that.(*PBLink)
+	if !ok {
+		return fmt2.Errorf("that is not of type *PBLink")
+	}
+	if that1 == nil {
+		if this == nil {
+			return nil
+		}
+		return fmt2.Errorf("that is type *PBLink but is nil && this != nil")
+	} else if this == nil {
+		return fmt2.Errorf("that is type *PBLinkbut is not nil && this == nil")
+	}
+	if !bytes.Equal(this.Hash, that1.Hash) {
+		return fmt2.Errorf("Hash this(%v) Not Equal that(%v)", this.Hash, that1.Hash)
+	}
+	if this.Name != nil && that1.Name != nil {
+		if *this.Name != *that1.Name {
+			return fmt2.Errorf("Name this(%v) Not Equal that(%v)", *this.Name, *that1.Name)
+		}
+	} else if this.Name != nil {
+		return fmt2.Errorf("this.Name == nil && that.Name != nil")
+	} else if that1.Name != nil {
+		return fmt2.Errorf("Name this(%v) Not Equal that(%v)", this.Name, that1.Name)
+	}
+	if this.Tsize != nil && that1.Tsize != nil {
+		if *this.Tsize != *that1.Tsize {
+			return fmt2.Errorf("Tsize this(%v) Not Equal that(%v)", *this.Tsize, *that1.Tsize)
+		}
+	} else if this.Tsize != nil {
+		return fmt2.Errorf("this.Tsize == nil && that.Tsize != nil")
+	} else if that1.Tsize != nil {
+		return fmt2.Errorf("Tsize this(%v) Not Equal that(%v)", this.Tsize, that1.Tsize)
+	}
+	if !bytes.Equal(this.XXX_unrecognized, that1.XXX_unrecognized) {
+		return fmt2.Errorf("XXX_unrecognized this(%v) Not Equal that(%v)", this.XXX_unrecognized, that1.XXX_unrecognized)
+	}
+	return nil
+}
+func (this *PBLink) Equal(that interface{}) bool {
+	if that == nil {
+		if this == nil {
+			return true
+		}
+		return false
+	}
+
+	that1, ok := that.(*PBLink)
+	if !ok {
+		return false
+	}
+	if that1 == nil {
+		if this == nil {
+			return true
+		}
+		return false
+	} else if this == nil {
+		return false
+	}
+	if !bytes.Equal(this.Hash, that1.Hash) {
+		return false
+	}
+	if this.Name != nil && that1.Name != nil {
+		if *this.Name != *that1.Name {
+			return false
+		}
+	} else if this.Name != nil {
+		return false
+	} else if that1.Name != nil {
+		return false
+	}
+	if this.Tsize != nil && that1.Tsize != nil {
+		if *this.Tsize != *that1.Tsize {
+			return false
+		}
+	} else if this.Tsize != nil {
+		return false
+	} else if that1.Tsize != nil {
+		return false
+	}
+	if !bytes.Equal(this.XXX_unrecognized, that1.XXX_unrecognized) {
+		return false
+	}
+	return true
+}
+func (this *PBNode) VerboseEqual(that interface{}) error {
+	if that == nil {
+		if this == nil {
+			return nil
+		}
+		return fmt2.Errorf("that == nil && this != nil")
+	}
+
+	that1, ok := that.(*PBNode)
+	if !ok {
+		return fmt2.Errorf("that is not of type *PBNode")
+	}
+	if that1 == nil {
+		if this == nil {
+			return nil
+		}
+		return fmt2.Errorf("that is type *PBNode but is nil && this != nil")
+	} else if this == nil {
+		return fmt2.Errorf("that is type *PBNodebut is not nil && this == nil")
+	}
+	if len(this.Links) != len(that1.Links) {
+		return fmt2.Errorf("Links this(%v) Not Equal that(%v)", len(this.Links), len(that1.Links))
+	}
+	for i := range this.Links {
+		if !this.Links[i].Equal(that1.Links[i]) {
+			return fmt2.Errorf("Links this[%v](%v) Not Equal that[%v](%v)", i, this.Links[i], i, that1.Links[i])
+		}
+	}
+	if !bytes.Equal(this.Data, that1.Data) {
+		return fmt2.Errorf("Data this(%v) Not Equal that(%v)", this.Data, that1.Data)
+	}
+	if !bytes.Equal(this.XXX_unrecognized, that1.XXX_unrecognized) {
+		return fmt2.Errorf("XXX_unrecognized this(%v) Not Equal that(%v)", this.XXX_unrecognized, that1.XXX_unrecognized)
+	}
+	return nil
+}
+func (this *PBNode) Equal(that interface{}) bool {
+	if that == nil {
+		if this == nil {
+			return true
+		}
+		return false
+	}
+
+	that1, ok := that.(*PBNode)
+	if !ok {
+		return false
+	}
+	if that1 == nil {
+		if this == nil {
+			return true
+		}
+		return false
+	} else if this == nil {
+		return false
+	}
+	if len(this.Links) != len(that1.Links) {
+		return false
+	}
+	for i := range this.Links {
+		if !this.Links[i].Equal(that1.Links[i]) {
+			return false
+		}
+	}
+	if !bytes.Equal(this.Data, that1.Data) {
+		return false
+	}
+	if !bytes.Equal(this.XXX_unrecognized, that1.XXX_unrecognized) {
+		return false
+	}
+	return true
+}
diff --git a/merkledag/nodepb_test.go b/merkledag/nodepb_test.go
new file mode 100644
index 000000000..b7ef81c3d
--- /dev/null
+++ b/merkledag/nodepb_test.go
@@ -0,0 +1,472 @@
+// Code generated by protoc-gen-gogo.
+// source: node.proto
+// DO NOT EDIT!
+
+/*
+Package merkledag is a generated protocol buffer package.
+
+It is generated from these files:
+	node.proto
+
+It has these top-level messages:
+	PBLink
+	PBNode
+*/
+package merkledag
+
+import testing "testing"
+import math_rand "math/rand"
+import time "time"
+import code_google_com_p_gogoprotobuf_proto "code.google.com/p/gogoprotobuf/proto"
+import testing1 "testing"
+import math_rand1 "math/rand"
+import time1 "time"
+import encoding_json "encoding/json"
+import testing2 "testing"
+import math_rand2 "math/rand"
+import time2 "time"
+import code_google_com_p_gogoprotobuf_proto1 "code.google.com/p/gogoprotobuf/proto"
+import math_rand3 "math/rand"
+import time3 "time"
+import testing3 "testing"
+import fmt "fmt"
+import math_rand4 "math/rand"
+import time4 "time"
+import testing4 "testing"
+import code_google_com_p_gogoprotobuf_proto2 "code.google.com/p/gogoprotobuf/proto"
+import math_rand5 "math/rand"
+import time5 "time"
+import testing5 "testing"
+import fmt1 "fmt"
+import go_parser "go/parser"
+import math_rand6 "math/rand"
+import time6 "time"
+import testing6 "testing"
+import code_google_com_p_gogoprotobuf_proto3 "code.google.com/p/gogoprotobuf/proto"
+
+func TestPBLinkProto(t *testing.T) {
+	popr := math_rand.New(math_rand.NewSource(time.Now().UnixNano()))
+	p := NewPopulatedPBLink(popr, false)
+	data, err := code_google_com_p_gogoprotobuf_proto.Marshal(p)
+	if err != nil {
+		panic(err)
+	}
+	msg := &PBLink{}
+	if err := code_google_com_p_gogoprotobuf_proto.Unmarshal(data, msg); err != nil {
+		panic(err)
+	}
+	for i := range data {
+		data[i] = byte(popr.Intn(256))
+	}
+	if err := p.VerboseEqual(msg); err != nil {
+		t.Fatalf("%#v !VerboseProto %#v, since %v", msg, p, err)
+	}
+	if !p.Equal(msg) {
+		t.Fatalf("%#v !Proto %#v", msg, p)
+	}
+}
+
+func TestPBLinkMarshalTo(t *testing.T) {
+	popr := math_rand.New(math_rand.NewSource(time.Now().UnixNano()))
+	p := NewPopulatedPBLink(popr, false)
+	size := p.Size()
+	data := make([]byte, size)
+	for i := range data {
+		data[i] = byte(popr.Intn(256))
+	}
+	_, err := p.MarshalTo(data)
+	if err != nil {
+		panic(err)
+	}
+	msg := &PBLink{}
+	if err := code_google_com_p_gogoprotobuf_proto.Unmarshal(data, msg); err != nil {
+		panic(err)
+	}
+	for i := range data {
+		data[i] = byte(popr.Intn(256))
+	}
+	if err := p.VerboseEqual(msg); err != nil {
+		t.Fatalf("%#v !VerboseProto %#v, since %v", msg, p, err)
+	}
+	if !p.Equal(msg) {
+		t.Fatalf("%#v !Proto %#v", msg, p)
+	}
+}
+
+func BenchmarkPBLinkProtoMarshal(b *testing.B) {
+	popr := math_rand.New(math_rand.NewSource(616))
+	total := 0
+	pops := make([]*PBLink, 10000)
+	for i := 0; i < 10000; i++ {
+		pops[i] = NewPopulatedPBLink(popr, false)
+	}
+	b.ResetTimer()
+	for i := 0; i < b.N; i++ {
+		data, err := code_google_com_p_gogoprotobuf_proto.Marshal(pops[i%10000])
+		if err != nil {
+			panic(err)
+		}
+		total += len(data)
+	}
+	b.SetBytes(int64(total / b.N))
+}
+
+func BenchmarkPBLinkProtoUnmarshal(b *testing.B) {
+	popr := math_rand.New(math_rand.NewSource(616))
+	total := 0
+	datas := make([][]byte, 10000)
+	for i := 0; i < 10000; i++ {
+		data, err := code_google_com_p_gogoprotobuf_proto.Marshal(NewPopulatedPBLink(popr, false))
+		if err != nil {
+			panic(err)
+		}
+		datas[i] = data
+	}
+	msg := &PBLink{}
+	b.ResetTimer()
+	for i := 0; i < b.N; i++ {
+		total += len(datas[i%10000])
+		if err := code_google_com_p_gogoprotobuf_proto.Unmarshal(datas[i%10000], msg); err != nil {
+			panic(err)
+		}
+	}
+	b.SetBytes(int64(total / b.N))
+}
+
+func TestPBNodeProto(t *testing.T) {
+	popr := math_rand.New(math_rand.NewSource(time.Now().UnixNano()))
+	p := NewPopulatedPBNode(popr, false)
+	data, err := code_google_com_p_gogoprotobuf_proto.Marshal(p)
+	if err != nil {
+		panic(err)
+	}
+	msg := &PBNode{}
+	if err := code_google_com_p_gogoprotobuf_proto.Unmarshal(data, msg); err != nil {
+		panic(err)
+	}
+	for i := range data {
+		data[i] = byte(popr.Intn(256))
+	}
+	if err := p.VerboseEqual(msg); err != nil {
+		t.Fatalf("%#v !VerboseProto %#v, since %v", msg, p, err)
+	}
+	if !p.Equal(msg) {
+		t.Fatalf("%#v !Proto %#v", msg, p)
+	}
+}
+
+func TestPBNodeMarshalTo(t *testing.T) {
+	popr := math_rand.New(math_rand.NewSource(time.Now().UnixNano()))
+	p := NewPopulatedPBNode(popr, false)
+	size := p.Size()
+	data := make([]byte, size)
+	for i := range data {
+		data[i] = byte(popr.Intn(256))
+	}
+	_, err := p.MarshalTo(data)
+	if err != nil {
+		panic(err)
+	}
+	msg := &PBNode{}
+	if err := code_google_com_p_gogoprotobuf_proto.Unmarshal(data, msg); err != nil {
+		panic(err)
+	}
+	for i := range data {
+		data[i] = byte(popr.Intn(256))
+	}
+	if err := p.VerboseEqual(msg); err != nil {
+		t.Fatalf("%#v !VerboseProto %#v, since %v", msg, p, err)
+	}
+	if !p.Equal(msg) {
+		t.Fatalf("%#v !Proto %#v", msg, p)
+	}
+}
+
+func BenchmarkPBNodeProtoMarshal(b *testing.B) {
+	popr := math_rand.New(math_rand.NewSource(616))
+	total := 0
+	pops := make([]*PBNode, 10000)
+	for i := 0; i < 10000; i++ {
+		pops[i] = NewPopulatedPBNode(popr, false)
+	}
+	b.ResetTimer()
+	for i := 0; i < b.N; i++ {
+		data, err := code_google_com_p_gogoprotobuf_proto.Marshal(pops[i%10000])
+		if err != nil {
+			panic(err)
+		}
+		total += len(data)
+	}
+	b.SetBytes(int64(total / b.N))
+}
+
+func BenchmarkPBNodeProtoUnmarshal(b *testing.B) {
+	popr := math_rand.New(math_rand.NewSource(616))
+	total := 0
+	datas := make([][]byte, 10000)
+	for i := 0; i < 10000; i++ {
+		data, err := code_google_com_p_gogoprotobuf_proto.Marshal(NewPopulatedPBNode(popr, false))
+		if err != nil {
+			panic(err)
+		}
+		datas[i] = data
+	}
+	msg := &PBNode{}
+	b.ResetTimer()
+	for i := 0; i < b.N; i++ {
+		total += len(datas[i%10000])
+		if err := code_google_com_p_gogoprotobuf_proto.Unmarshal(datas[i%10000], msg); err != nil {
+			panic(err)
+		}
+	}
+	b.SetBytes(int64(total / b.N))
+}
+
+func TestPBLinkJSON(t *testing1.T) {
+	popr := math_rand1.New(math_rand1.NewSource(time1.Now().UnixNano()))
+	p := NewPopulatedPBLink(popr, true)
+	jsondata, err := encoding_json.Marshal(p)
+	if err != nil {
+		panic(err)
+	}
+	msg := &PBLink{}
+	err = encoding_json.Unmarshal(jsondata, msg)
+	if err != nil {
+		panic(err)
+	}
+	if err := p.VerboseEqual(msg); err != nil {
+		t.Fatalf("%#v !VerboseProto %#v, since %v", msg, p, err)
+	}
+	if !p.Equal(msg) {
+		t.Fatalf("%#v !Json Equal %#v", msg, p)
+	}
+}
+func TestPBNodeJSON(t *testing1.T) {
+	popr := math_rand1.New(math_rand1.NewSource(time1.Now().UnixNano()))
+	p := NewPopulatedPBNode(popr, true)
+	jsondata, err := encoding_json.Marshal(p)
+	if err != nil {
+		panic(err)
+	}
+	msg := &PBNode{}
+	err = encoding_json.Unmarshal(jsondata, msg)
+	if err != nil {
+		panic(err)
+	}
+	if err := p.VerboseEqual(msg); err != nil {
+		t.Fatalf("%#v !VerboseProto %#v, since %v", msg, p, err)
+	}
+	if !p.Equal(msg) {
+		t.Fatalf("%#v !Json Equal %#v", msg, p)
+	}
+}
+func TestPBLinkProtoText(t *testing2.T) {
+	popr := math_rand2.New(math_rand2.NewSource(time2.Now().UnixNano()))
+	p := NewPopulatedPBLink(popr, true)
+	data := code_google_com_p_gogoprotobuf_proto1.MarshalTextString(p)
+	msg := &PBLink{}
+	if err := code_google_com_p_gogoprotobuf_proto1.UnmarshalText(data, msg); err != nil {
+		panic(err)
+	}
+	if err := p.VerboseEqual(msg); err != nil {
+		t.Fatalf("%#v !VerboseProto %#v, since %v", msg, p, err)
+	}
+	if !p.Equal(msg) {
+		t.Fatalf("%#v !Proto %#v", msg, p)
+	}
+}
+
+func TestPBLinkProtoCompactText(t *testing2.T) {
+	popr := math_rand2.New(math_rand2.NewSource(time2.Now().UnixNano()))
+	p := NewPopulatedPBLink(popr, true)
+	data := code_google_com_p_gogoprotobuf_proto1.CompactTextString(p)
+	msg := &PBLink{}
+	if err := code_google_com_p_gogoprotobuf_proto1.UnmarshalText(data, msg); err != nil {
+		panic(err)
+	}
+	if err := p.VerboseEqual(msg); err != nil {
+		t.Fatalf("%#v !VerboseProto %#v, since %v", msg, p, err)
+	}
+	if !p.Equal(msg) {
+		t.Fatalf("%#v !Proto %#v", msg, p)
+	}
+}
+
+func TestPBNodeProtoText(t *testing2.T) {
+	popr := math_rand2.New(math_rand2.NewSource(time2.Now().UnixNano()))
+	p := NewPopulatedPBNode(popr, true)
+	data := code_google_com_p_gogoprotobuf_proto1.MarshalTextString(p)
+	msg := &PBNode{}
+	if err := code_google_com_p_gogoprotobuf_proto1.UnmarshalText(data, msg); err != nil {
+		panic(err)
+	}
+	if err := p.VerboseEqual(msg); err != nil {
+		t.Fatalf("%#v !VerboseProto %#v, since %v", msg, p, err)
+	}
+	if !p.Equal(msg) {
+		t.Fatalf("%#v !Proto %#v", msg, p)
+	}
+}
+
+func TestPBNodeProtoCompactText(t *testing2.T) {
+	popr := math_rand2.New(math_rand2.NewSource(time2.Now().UnixNano()))
+	p := NewPopulatedPBNode(popr, true)
+	data := code_google_com_p_gogoprotobuf_proto1.CompactTextString(p)
+	msg := &PBNode{}
+	if err := code_google_com_p_gogoprotobuf_proto1.UnmarshalText(data, msg); err != nil {
+		panic(err)
+	}
+	if err := p.VerboseEqual(msg); err != nil {
+		t.Fatalf("%#v !VerboseProto %#v, since %v", msg, p, err)
+	}
+	if !p.Equal(msg) {
+		t.Fatalf("%#v !Proto %#v", msg, p)
+	}
+}
+
+func TestPBLinkStringer(t *testing3.T) {
+	popr := math_rand3.New(math_rand3.NewSource(time3.Now().UnixNano()))
+	p := NewPopulatedPBLink(popr, false)
+	s1 := p.String()
+	s2 := fmt.Sprintf("%v", p)
+	if s1 != s2 {
+		t.Fatalf("String want %v got %v", s1, s2)
+	}
+}
+func TestPBNodeStringer(t *testing3.T) {
+	popr := math_rand3.New(math_rand3.NewSource(time3.Now().UnixNano()))
+	p := NewPopulatedPBNode(popr, false)
+	s1 := p.String()
+	s2 := fmt.Sprintf("%v", p)
+	if s1 != s2 {
+		t.Fatalf("String want %v got %v", s1, s2)
+	}
+}
+func TestPBLinkSize(t *testing4.T) {
+	popr := math_rand4.New(math_rand4.NewSource(time4.Now().UnixNano()))
+	p := NewPopulatedPBLink(popr, true)
+	size2 := code_google_com_p_gogoprotobuf_proto2.Size(p)
+	data, err := code_google_com_p_gogoprotobuf_proto2.Marshal(p)
+	if err != nil {
+		panic(err)
+	}
+	size := p.Size()
+	if len(data) != size {
+		t.Fatalf("size %v != marshalled size %v", size, len(data))
+	}
+	if size2 != size {
+		t.Fatalf("size %v != before marshal proto.Size %v", size, size2)
+	}
+	size3 := code_google_com_p_gogoprotobuf_proto2.Size(p)
+	if size3 != size {
+		t.Fatalf("size %v != after marshal proto.Size %v", size, size3)
+	}
+}
+
+func BenchmarkPBLinkSize(b *testing4.B) {
+	popr := math_rand4.New(math_rand4.NewSource(616))
+	total := 0
+	pops := make([]*PBLink, 1000)
+	for i := 0; i < 1000; i++ {
+		pops[i] = NewPopulatedPBLink(popr, false)
+	}
+	b.ResetTimer()
+	for i := 0; i < b.N; i++ {
+		total += pops[i%1000].Size()
+	}
+	b.SetBytes(int64(total / b.N))
+}
+
+func TestPBNodeSize(t *testing4.T) {
+	popr := math_rand4.New(math_rand4.NewSource(time4.Now().UnixNano()))
+	p := NewPopulatedPBNode(popr, true)
+	size2 := code_google_com_p_gogoprotobuf_proto2.Size(p)
+	data, err := code_google_com_p_gogoprotobuf_proto2.Marshal(p)
+	if err != nil {
+		panic(err)
+	}
+	size := p.Size()
+	if len(data) != size {
+		t.Fatalf("size %v != marshalled size %v", size, len(data))
+	}
+	if size2 != size {
+		t.Fatalf("size %v != before marshal proto.Size %v", size, size2)
+	}
+	size3 := code_google_com_p_gogoprotobuf_proto2.Size(p)
+	if size3 != size {
+		t.Fatalf("size %v != after marshal proto.Size %v", size, size3)
+	}
+}
+
+func BenchmarkPBNodeSize(b *testing4.B) {
+	popr := math_rand4.New(math_rand4.NewSource(616))
+	total := 0
+	pops := make([]*PBNode, 1000)
+	for i := 0; i < 1000; i++ {
+		pops[i] = NewPopulatedPBNode(popr, false)
+	}
+	b.ResetTimer()
+	for i := 0; i < b.N; i++ {
+		total += pops[i%1000].Size()
+	}
+	b.SetBytes(int64(total / b.N))
+}
+
+func TestPBLinkGoString(t *testing5.T) {
+	popr := math_rand5.New(math_rand5.NewSource(time5.Now().UnixNano()))
+	p := NewPopulatedPBLink(popr, false)
+	s1 := p.GoString()
+	s2 := fmt1.Sprintf("%#v", p)
+	if s1 != s2 {
+		t.Fatalf("GoString want %v got %v", s1, s2)
+	}
+	_, err := go_parser.ParseExpr(s1)
+	if err != nil {
+		panic(err)
+	}
+}
+func TestPBNodeGoString(t *testing5.T) {
+	popr := math_rand5.New(math_rand5.NewSource(time5.Now().UnixNano()))
+	p := NewPopulatedPBNode(popr, false)
+	s1 := p.GoString()
+	s2 := fmt1.Sprintf("%#v", p)
+	if s1 != s2 {
+		t.Fatalf("GoString want %v got %v", s1, s2)
+	}
+	_, err := go_parser.ParseExpr(s1)
+	if err != nil {
+		panic(err)
+	}
+}
+func TestPBLinkVerboseEqual(t *testing6.T) {
+	popr := math_rand6.New(math_rand6.NewSource(time6.Now().UnixNano()))
+	p := NewPopulatedPBLink(popr, false)
+	data, err := code_google_com_p_gogoprotobuf_proto3.Marshal(p)
+	if err != nil {
+		panic(err)
+	}
+	msg := &PBLink{}
+	if err := code_google_com_p_gogoprotobuf_proto3.Unmarshal(data, msg); err != nil {
+		panic(err)
+	}
+	if err := p.VerboseEqual(msg); err != nil {
+		t.Fatalf("%#v !VerboseEqual %#v, since %v", msg, p, err)
+	}
+}
+func TestPBNodeVerboseEqual(t *testing6.T) {
+	popr := math_rand6.New(math_rand6.NewSource(time6.Now().UnixNano()))
+	p := NewPopulatedPBNode(popr, false)
+	data, err := code_google_com_p_gogoprotobuf_proto3.Marshal(p)
+	if err != nil {
+		panic(err)
+	}
+	msg := &PBNode{}
+	if err := code_google_com_p_gogoprotobuf_proto3.Unmarshal(data, msg); err != nil {
+		panic(err)
+	}
+	if err := p.VerboseEqual(msg); err != nil {
+		t.Fatalf("%#v !VerboseEqual %#v, since %v", msg, p, err)
+	}
+}
+
+//These tests are generated by code.google.com/p/gogoprotobuf/plugin/testgen
-- 
GitLab