Skip to content

Commit

Permalink
Replace PrefixedData type (only used in tests) in favour of a type alias
Browse files Browse the repository at this point in the history
  • Loading branch information
liamsi committed Mar 19, 2021
1 parent e0a317a commit 901d0bd
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 90 deletions.
38 changes: 11 additions & 27 deletions namespace/data.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,16 @@
package namespace

// PrefixedData simply represents a slice of bytes which consists of
// a namespace.ID and raw data.
// The user has to guarantee that the bytes are valid namespace prefixed data.
// Go's type system does not allow enforcing the structure we want:
// [namespaceID, rawData ...], especially as this type does not expect any
// particular size for the namespace.
type PrefixedData []byte

// PrefixedData8 like PrefixedData is just a slice of bytes.
// It assumes that the slice it represents is at least 8 bytes.
// This assumption is not enforced by the type system though.
type PrefixedData8 []byte

func (d PrefixedData8) NamespaceID() ID {
Expand All @@ -9,30 +20,3 @@ func (d PrefixedData8) NamespaceID() ID {
func (d PrefixedData8) Data() []byte {
return d[8:]
}

type PrefixedData struct {
namespaceLen IDSize
prefixedData []byte
}

func (n PrefixedData) NamespaceID() ID {
return n.prefixedData[:n.namespaceLen]
}

func (n PrefixedData) Data() []byte {
return n.prefixedData[n.namespaceLen:]
}

func NewPrefixedData(namespaceLen IDSize, prefixedData []byte) PrefixedData {
return PrefixedData{
namespaceLen: namespaceLen,
prefixedData: prefixedData,
}
}

func PrefixedDataFrom(nID ID, data []byte) PrefixedData {
return PrefixedData{
namespaceLen: nID.Size(),
prefixedData: append(nID, data...),
}
}
119 changes: 60 additions & 59 deletions nmt_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,20 +15,39 @@ import (
"github.com/lazyledger/nmt/namespace"
)

type namespaceDataPair struct {
ID namespace.ID
Data []byte
}

func newNamespaceDataPair(id namespace.ID, data []byte) namespaceDataPair {
return namespaceDataPair{
ID: id,
Data: data,
}
}

func newNamespaceDataPairRaw(nidSize int, data []byte) namespaceDataPair {
return namespaceDataPair{
ID: data[:nidSize],
Data: data[nidSize:],
}
}

func ExampleNamespacedMerkleTree() {
// the tree will use this namespace size
nidSize := 1
// the leaves that will be pushed
data := []namespace.PrefixedData{
namespace.PrefixedDataFrom(namespace.ID{0}, []byte("leaf_0")),
namespace.PrefixedDataFrom(namespace.ID{0}, []byte("leaf_1")),
namespace.PrefixedDataFrom(namespace.ID{1}, []byte("leaf_2")),
namespace.PrefixedDataFrom(namespace.ID{1}, []byte("leaf_3"))}
data := []namespaceDataPair{
newNamespaceDataPair(namespace.ID{0}, []byte("leaf_0")),
newNamespaceDataPair(namespace.ID{0}, []byte("leaf_1")),
newNamespaceDataPair(namespace.ID{1}, []byte("leaf_2")),
newNamespaceDataPair(namespace.ID{1}, []byte("leaf_3"))}
// Init a tree with the namespace size as well as
// the underlying hash function:
tree := New(sha256.New(), NamespaceIDSize(nidSize))
for _, d := range data {
if err := tree.Push(d.NamespaceID(), d.Data()); err != nil {
if err := tree.Push(d.ID, d.Data); err != nil {
panic("unexpected error")
}
}
Expand Down Expand Up @@ -67,49 +86,30 @@ func ExampleNamespacedMerkleTree() {
// Successfully verified namespace: 00
}

func TestFromNamespaceAndData(t *testing.T) {
tests := []struct {
name string
namespace []byte
data []byte
want namespace.PrefixedData
}{
0: {"simple case", []byte("namespace1"), []byte("data1"), namespace.NewPrefixedData(10, append([]byte("namespace1"), []byte("data1")...))},
1: {"simpler case", []byte("1"), []byte("d"), namespace.NewPrefixedData(1, append([]byte("1"), []byte("d")...))},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := namespace.PrefixedDataFrom(tt.namespace, tt.data); !reflect.DeepEqual(got, tt.want) {
t.Errorf("PrefixedDataFrom() = %v, want %v", got, tt.want)
}
})
}
}

func TestNamespacedMerkleTree_Push(t *testing.T) {
tests := []struct {
name string
data namespace.PrefixedData
data namespaceDataPair
wantErr bool
}{
{"1st push: always OK", namespace.PrefixedDataFrom([]byte{0, 0, 0}, []byte("dummy data")), false},
{"push with same namespace: OK", namespace.PrefixedDataFrom([]byte{0, 0, 0}, []byte("dummy data")), false},
{"push with greater namespace: OK", namespace.PrefixedDataFrom([]byte{0, 0, 1}, []byte("dummy data")), false},
{"push with smaller namespace: Err", namespace.PrefixedDataFrom([]byte{0, 0, 0}, []byte("dummy data")), true},
{"push with same namespace: Ok", namespace.PrefixedDataFrom([]byte{0, 0, 1}, []byte("dummy data")), false},
{"push with greater namespace: Ok", namespace.PrefixedDataFrom([]byte{1, 0, 0}, []byte("dummy data")), false},
{"push with smaller namespace: Err", namespace.PrefixedDataFrom([]byte{0, 0, 1}, []byte("dummy data")), true},
{"push with smaller namespace: Err", namespace.PrefixedDataFrom([]byte{0, 0, 0}, []byte("dummy data")), true},
{"push with smaller namespace: Err", namespace.PrefixedDataFrom([]byte{0, 1, 0}, []byte("dummy data")), true},
{"push with same as last namespace: OK", namespace.PrefixedDataFrom([]byte{1, 0, 0}, []byte("dummy data")), false},
{"push with greater as last namespace: OK", namespace.PrefixedDataFrom([]byte{1, 1, 0}, []byte("dummy data")), false},
{"1st push: always OK", newNamespaceDataPair([]byte{0, 0, 0}, []byte("dummy data")), false},
{"push with same namespace: OK", newNamespaceDataPair([]byte{0, 0, 0}, []byte("dummy data")), false},
{"push with greater namespace: OK", newNamespaceDataPair([]byte{0, 0, 1}, []byte("dummy data")), false},
{"push with smaller namespace: Err", newNamespaceDataPair([]byte{0, 0, 0}, []byte("dummy data")), true},
{"push with same namespace: Ok", newNamespaceDataPair([]byte{0, 0, 1}, []byte("dummy data")), false},
{"push with greater namespace: Ok", newNamespaceDataPair([]byte{1, 0, 0}, []byte("dummy data")), false},
{"push with smaller namespace: Err", newNamespaceDataPair([]byte{0, 0, 1}, []byte("dummy data")), true},
{"push with smaller namespace: Err", newNamespaceDataPair([]byte{0, 0, 0}, []byte("dummy data")), true},
{"push with smaller namespace: Err", newNamespaceDataPair([]byte{0, 1, 0}, []byte("dummy data")), true},
{"push with same as last namespace: OK", newNamespaceDataPair([]byte{1, 0, 0}, []byte("dummy data")), false},
{"push with greater as last namespace: OK", newNamespaceDataPair([]byte{1, 1, 0}, []byte("dummy data")), false},
// note this tests for another kind of error: ErrMismatchedNamespaceSize
{"push with wrong namespace size: Err", namespace.PrefixedDataFrom([]byte{1, 1, 0, 0}, []byte("dummy data")), true},
{"push with wrong namespace size: Err", newNamespaceDataPair([]byte{1, 1, 0, 0}, []byte("dummy data")), true},
}
n := New(sha256.New(), NamespaceIDSize(3))
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if err := n.Push(tt.data.NamespaceID(), tt.data.Data()); (err != nil) != tt.wantErr {
if err := n.Push(tt.data.ID, tt.data.Data); (err != nil) != tt.wantErr {
t.Errorf("Push() error = %v, wantErr %v", err, tt.wantErr)
}
})
Expand All @@ -132,23 +132,23 @@ func TestNamespacedMerkleTreeRoot(t *testing.T) {
tests := []struct {
name string
nidLen int
pushedData []namespace.PrefixedData
pushedData []namespaceDataPair
wantMinNs namespace.ID
wantMaxNs namespace.ID
wantRoot []byte
}{
// default empty root according to base case:
// https://github.com/lazyledger/lazyledger-specs/blob/master/specs/data_structures.md#namespace-merkle-tree
{"Empty", 3, nil, zeroNs, zeroNs, emptyRoot},
{"One leaf", 3, []namespace.PrefixedData{namespace.PrefixedDataFrom(zeroNs, leaf)}, zeroNs, zeroNs, leafHash},
{"Two leaves", 3, []namespace.PrefixedData{namespace.PrefixedDataFrom(zeroNs, leaf), namespace.PrefixedDataFrom(zeroNs, leaf)}, zeroNs, zeroNs, twoZeroLeafsRoot},
{"Two leaves diff namespaces", 3, []namespace.PrefixedData{namespace.PrefixedDataFrom(zeroNs, leaf), namespace.PrefixedDataFrom(onesNS, leaf)}, zeroNs, onesNS, diffNSLeafsRoot},
{"One leaf", 3, []namespaceDataPair{newNamespaceDataPair(zeroNs, leaf)}, zeroNs, zeroNs, leafHash},
{"Two leaves", 3, []namespaceDataPair{newNamespaceDataPair(zeroNs, leaf), newNamespaceDataPair(zeroNs, leaf)}, zeroNs, zeroNs, twoZeroLeafsRoot},
{"Two leaves diff namespaces", 3, []namespaceDataPair{newNamespaceDataPair(zeroNs, leaf), newNamespaceDataPair(onesNS, leaf)}, zeroNs, onesNS, diffNSLeafsRoot},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
n := New(sha256.New(), NamespaceIDSize(tt.nidLen))
for _, d := range tt.pushedData {
if err := n.Push(d.NamespaceID(), d.Data()); err != nil {
if err := n.Push(d.ID, d.Data); err != nil {
t.Errorf("Push() error = %v, expected no error", err)
}
}
Expand All @@ -171,7 +171,7 @@ func TestNamespacedMerkleTree_ProveNamespace_Ranges_And_Verify(t *testing.T) {
tests := []struct {
name string
nidLen int
pushData []namespace.PrefixedData
pushData []namespaceDataPair
proveNID namespace.ID
wantProofStart int
wantProofEnd int
Expand Down Expand Up @@ -219,12 +219,12 @@ func TestNamespacedMerkleTree_ProveNamespace_Ranges_And_Verify(t *testing.T) {
// In the cases (nID < minNID) or (maxNID < nID) we do not generate any proof
// and the (minNS, maxNs, root) should be indication enough that nID is not in that range.
{"4 leaves, not found and nID < minNID", 2,
[]namespace.PrefixedData{namespace.NewPrefixedData(2, []byte("01_data")), namespace.NewPrefixedData(2, []byte("01_data")), namespace.NewPrefixedData(2, []byte("01_data")), namespace.NewPrefixedData(2, []byte("11_data"))},
[]namespaceDataPair{newNamespaceDataPairRaw(2, []byte("01_data")), newNamespaceDataPairRaw(2, []byte("01_data")), newNamespaceDataPairRaw(2, []byte("01_data")), newNamespaceDataPairRaw(2, []byte("11_data"))},
[]byte("00"),
0, 0,
false},
{"4 leaves, not found and nID > maxNID ", 2,
[]namespace.PrefixedData{namespace.NewPrefixedData(2, []byte("00_data")), namespace.NewPrefixedData(2, []byte("00_data")), namespace.NewPrefixedData(2, []byte("01_data")), namespace.NewPrefixedData(2, []byte("01_data"))},
[]namespaceDataPair{newNamespaceDataPairRaw(2, []byte("00_data")), newNamespaceDataPairRaw(2, []byte("00_data")), newNamespaceDataPairRaw(2, []byte("01_data")), newNamespaceDataPairRaw(2, []byte("01_data"))},
[]byte("11"),
0, 0,
false},
Expand All @@ -233,7 +233,7 @@ func TestNamespacedMerkleTree_ProveNamespace_Ranges_And_Verify(t *testing.T) {
t.Run(tt.name, func(t *testing.T) {
n := New(sha256.New(), NamespaceIDSize(tt.nidLen))
for _, d := range tt.pushData {
err := n.Push(d.NamespaceID(), d.Data())
err := n.Push(d.ID, d.Data)
if err != nil {
t.Fatalf("invalid test case: %v, error on Push(): %v", tt.name, err)
}
Expand Down Expand Up @@ -270,7 +270,7 @@ func TestNamespacedMerkleTree_ProveNamespace_Ranges_And_Verify(t *testing.T) {
if err != nil {
t.Fatalf("unexpected error on Prove(): %v", err)
}
gotChecksOut := gotSingleProof.VerifyInclusion(sha256.New(), data.NamespaceID(), data.Data(), n.Root())
gotChecksOut := gotSingleProof.VerifyInclusion(sha256.New(), data.ID, data.Data, n.Root())
if !gotChecksOut {
t.Errorf("Proof.VerifyInclusion() gotChecksOut: %v, want: true", gotChecksOut)
}
Expand Down Expand Up @@ -511,7 +511,7 @@ func TestNamespacedMerkleTree_ProveErrors(t *testing.T) {
name string
nidLen int
index int
pushData []namespace.PrefixedData
pushData []namespaceDataPair
wantErr bool
wantPanic bool
}{
Expand All @@ -522,7 +522,7 @@ func TestNamespacedMerkleTree_ProveErrors(t *testing.T) {
t.Run(tt.name, func(t *testing.T) {
n := New(sha256.New(), NamespaceIDSize(tt.nidLen), InitialCapacity(len(tt.pushData)))
for _, d := range tt.pushData {
err := n.Push(d.NamespaceID(), d.Data())
err := n.Push(d.ID, d.Data)
if err != nil {
t.Fatalf("invalid test case: %v, error on Push(): %v", tt.name, err)
}
Expand Down Expand Up @@ -557,7 +557,7 @@ func TestNamespacedMerkleTree_calculateAbsenceIndex_Panic(t *testing.T) {
tests := []struct {
name string
nID namespace.ID
pushData []namespace.PrefixedData
pushData []namespaceDataPair
}{
{"((0,0) == nID < minNID == (0,1))", []byte{0, 0}, generateLeafData(nidLen, 1, 3, []byte{})},
{"((0,3) == nID > maxNID == (0,2))", []byte{0, 3}, generateLeafData(nidLen, 1, 3, []byte{})},
Expand Down Expand Up @@ -621,23 +621,24 @@ func shouldPanic(t *testing.T, f func()) {
t.Errorf("should have panicked")
}

func makeLeafData(ns []byte, data []byte) namespace.PrefixedData {
// TODO remove
func makeLeafData(ns []byte, data []byte) namespaceDataPair {
if len(ns) > math.MaxUint8 {
panic("namespace too large")
}
return namespace.NewPrefixedData(namespace.IDSize(len(ns)), append(ns, data...))
return newNamespaceDataPair(ns, data)
}

// generates a consecutive range of leaf data
// starting from namespace zero+start till zero+end,
// where zero := 0*nsLen interpreted Uvarint
func generateLeafData(nsLen uint8, nsStartIdx, nsEndIdx int, data []byte) []namespace.PrefixedData {
func generateLeafData(nsLen uint8, nsStartIdx, nsEndIdx int, data []byte) []namespaceDataPair {
if nsEndIdx >= math.MaxUint8*int(nsLen) {
panic(fmt.Sprintf("invalid nsEndIdx: %v, has to be < %v", nsEndIdx, 2<<(nsLen-1)))
}

startNS := bytes.Repeat([]byte{0x0}, int(nsLen))
res := make([]namespace.PrefixedData, 0, nsEndIdx-nsStartIdx)
res := make([]namespaceDataPair, 0, nsEndIdx-nsStartIdx)
for i := nsStartIdx; i < nsEndIdx; i++ {
curNs := append([]byte(nil), startNS...)
curNsUint, err := binary.ReadUvarint(bytes.NewReader(startNS))
Expand All @@ -648,14 +649,14 @@ func generateLeafData(nsLen uint8, nsStartIdx, nsEndIdx int, data []byte) []name
nsUnpadded := make([]byte, 10)
n := binary.PutUvarint(nsUnpadded, curNsUint)
copy(curNs[len(startNS)-n:], nsUnpadded[:n])
res = append(res, namespace.NewPrefixedData(namespace.IDSize(nsLen), append(curNs, data...)))
res = append(res, newNamespaceDataPair(curNs, data))
}
return res
}

// repeats the given namespace data num times
func repeat(data []namespace.PrefixedData, num int) []namespace.PrefixedData {
res := make([]namespace.PrefixedData, 0, num*len(data))
func repeat(data []namespaceDataPair, num int) []namespaceDataPair {
res := make([]namespaceDataPair, 0, num*len(data))
for i := 0; i < num; i++ {
res = append(res, data...)
}
Expand Down
8 changes: 4 additions & 4 deletions proof_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,12 @@ func TestProof_VerifyNamespace_False(t *testing.T) {
const testNidLen = 3

n := New(sha256.New(), NamespaceIDSize(testNidLen))
data := append(append([]namespace.PrefixedData{
namespace.PrefixedDataFrom([]byte{0, 0, 0}, []byte("first leaf"))},
data := append(append([]namespaceDataPair{
newNamespaceDataPair([]byte{0, 0, 0}, []byte("first leaf"))},
generateLeafData(testNidLen, 0, 9, []byte("data"))...,
), namespace.PrefixedDataFrom([]byte{0, 0, 8}, []byte("last leaf")))
), newNamespaceDataPair([]byte{0, 0, 8}, []byte("last leaf")))
for _, d := range data {
err := n.Push(d.NamespaceID(), d.Data())
err := n.Push(d.ID, d.Data)
if err != nil {
t.Fatalf("invalid test setup: error on Push(): %v", err)
}
Expand Down

0 comments on commit 901d0bd

Please sign in to comment.