package merkle import ( "encoding/hex" "testing" ) // The roots below were computed by an independent implementation (Python's hashlib) over // transaction ids that are each 32 copies of their index, so they pin the pairing rule at every // block size instead of only the powers of two. var vectors = []struct { count int root string }{ {1, "0000000000000000000000000000000000000000000000000000000000000000"}, {2, "705ede9d42476fc3e5a978b042ce790a193678f46d19f47ec4ab46539c47b76d"}, {3, "d6384640762f797ede7e7f13839222f9452272809932cc6089f701331df4552d"}, {4, "ac41efca4951b1260054e1155fd8f6c3f42a5b521f1161b20f3c053d3159816c"}, {5, "c855157c6d4dda84ba48e08dd32cc7ba1672665610f19d0f8899aee59209e2de"}, {7, "6063cac3fc7219cdbe4552783852c347919ea72795730214f8e841d31922cf75"}, } // TestRootMatchesAnIndependentImplementation: the pairing rule, at every count. func TestRootMatchesAnIndependentImplementation(t *testing.T) { for _, vector := range vectors { txids := make([][32]byte, vector.count) for index := range txids { for byteIndex := range txids[index] { txids[index][byteIndex] = byte(index) } } root, err := Root(txids) if err != nil { t.Fatal(err) } if got := hex.EncodeToString(root[:]); got != vector.root { t.Fatalf("%d transactions: the root is %s, want %s", vector.count, got, vector.root) } } } // TestOddCountsPairTheLastWithItself: the case a naive implementation gets wrong. func TestOddCountsPairTheLastWithItself(t *testing.T) { three := make([][32]byte, 3) for index := range three { for byteIndex := range three[index] { three[index][byteIndex] = byte(index) } } root, err := Root(three) if err != nil { t.Fatal(err) } if root == [32]byte{} { t.Fatal("a three-transaction block has no root") } // Three transactions must not hash the way two do. two, err := Root(three[:2]) if err != nil { t.Fatal(err) } if root == two { t.Fatal("three transactions produced two transactions' root") } } // TestNoTransactionsIsAnError: a block with no coinbase is not a block. func TestNoTransactionsIsAnError(t *testing.T) { if _, err := Root(nil); err != ErrNoTransactions { t.Fatalf("an empty block: %v", err) } }