Fix Prysm Deposit Formatting (#3394)

* proofs with proper size

* getting to the root of the problem, no pun intended

* add regression test and fix proofs

* debugging the receipt root

* debug

* fixed spec tests

* fixed up proofs!

* tests all pass
This commit is contained in:
Raul Jordan
2019-09-03 12:47:47 -05:00
committed by GitHub
parent 90b2a880c6
commit 8ce8717676
2 changed files with 82 additions and 40 deletions

View File

@@ -2,6 +2,7 @@ package trieutil
import (
"bytes"
"encoding/binary"
"errors"
"fmt"
@@ -60,7 +61,9 @@ func (m *MerkleTrie) Items() [][]byte {
// Root returns the top-most, Merkle root of the trie.
func (m *MerkleTrie) Root() [32]byte {
return bytesutil.ToBytes32(m.branches[len(m.branches)-1][0])
enc := [32]byte{}
binary.LittleEndian.PutUint64(enc[:], uint64(len(m.originalItems)))
return hashutil.Hash(append(m.branches[len(m.branches)-1][0], enc[:]...))
}
// MerkleProof computes a proof from a trie's branches using a Merkle index.
@@ -70,15 +73,19 @@ func (m *MerkleTrie) MerkleProof(index int) ([][]byte, error) {
if index >= len(leaves) {
return nil, fmt.Errorf("merkle index out of range in trie, max range: %d, received: %d", len(leaves), index)
}
proof := make([][]byte, m.depth)
proof := make([][]byte, m.depth+1)
for i := uint(0); i < m.depth; i++ {
subIndex := (merkleIndex / (1 << i)) ^ 1
if subIndex < uint(len(m.branches[i])) {
proof[i] = m.branches[i][subIndex]
item := bytesutil.ToBytes32(m.branches[i][subIndex])
proof[i] = item[:]
} else {
proof[i] = zeroHashes[i]
}
}
enc := [32]byte{}
binary.LittleEndian.PutUint64(enc[:], uint64(len(m.originalItems)))
proof[len(proof)-1] = enc[:]
return proof, nil
}
@@ -99,23 +106,28 @@ func (m *MerkleTrie) HashTreeRoot() [32]byte {
// VerifyMerkleProof verifies a Merkle branch against a root of a trie.
func VerifyMerkleProof(root []byte, item []byte, merkleIndex int, proof [][]byte) bool {
node := item
branchIndices := branchIndices(merkleIndex, len(proof))
node := bytesutil.ToBytes32(item)
for i := 0; i < len(proof); i++ {
if branchIndices[i]%2 == 0 {
parentHash := hashutil.Hash(append(node[:], proof[i]...))
node = parentHash[:]
} else {
isLeft := merkleIndex / (1 << uint64(i))
if isLeft%2 != 0 {
parentHash := hashutil.Hash(append(proof[i], node[:]...))
node = parentHash[:]
node = parentHash
} else {
parentHash := hashutil.Hash(append(node[:], proof[i]...))
node = parentHash
}
}
return bytes.Equal(root, node)
return bytes.Equal(root, node[:])
}
func calcTreeFromLeaves(leaves [][]byte, depth int) [][][]byte {
layers := make([][][]byte, depth+1)
layers[0] = leaves
transformedLeaves := make([][]byte, len(leaves))
for i := range leaves {
arr := bytesutil.ToBytes32(leaves[i])
transformedLeaves[i] = arr[:]
}
layers[0] = transformedLeaves
for i := 0; i < depth; i++ {
if len(layers[i])%2 == 1 {
layers[i] = append(layers[i], zeroHashes[i])
@@ -130,17 +142,6 @@ func calcTreeFromLeaves(leaves [][]byte, depth int) [][][]byte {
return layers
}
func branchIndices(merkleIndex int, depth int) []int {
indices := make([]int, depth)
idx := merkleIndex
indices[0] = idx
for i := 1; i < depth; i++ {
idx /= 2
indices[i] = idx
}
return indices
}
func (m *MerkleTrie) updateTrie() error {
trie, err := GenerateTrieFromItems(m.originalItems, int(m.depth))
if err != nil {

View File

@@ -2,6 +2,7 @@ package trieutil
import (
"math/big"
"reflect"
"strconv"
"testing"
@@ -13,13 +14,49 @@ import (
"github.com/prysmaticlabs/prysm/shared/params"
)
func TestMerkleTrie_BranchIndices(t *testing.T) {
indices := branchIndices(1024, 3 /* depth */)
expected := []int{1024, 512, 256}
for i := 0; i < len(indices); i++ {
if expected[i] != indices[i] {
t.Errorf("Expected %d, received %d", expected[i], indices[i])
}
func TestMarshalDepositWithProof(t *testing.T) {
items := [][]byte{
[]byte("A"),
[]byte("BB"),
[]byte("CCC"),
[]byte("DDDD"),
[]byte("EEEEE"),
[]byte("FFFFFF"),
[]byte("GGGGGGG"),
}
m, err := GenerateTrieFromItems(items, 32)
if err != nil {
t.Fatalf("Could not generate Merkle trie from items: %v", err)
}
proof, err := m.MerkleProof(2)
if err != nil {
t.Fatalf("Could not generate Merkle proof: %v", err)
}
if len(proof) != 33 {
t.Errorf("Received len %d, wanted 33", len(proof))
}
someRoot := [32]byte{1, 2, 3, 4}
someSig := [96]byte{1, 2, 3, 4}
someKey := [48]byte{1, 2, 3, 4}
dep := &ethpb.Deposit{
Proof: proof,
Data: &ethpb.Deposit_Data{
PublicKey: someKey[:],
WithdrawalCredentials: someRoot[:],
Amount: 32,
Signature: someSig[:],
},
}
enc, err := ssz.Marshal(dep)
if err != nil {
t.Fatal(err)
}
dec := &ethpb.Deposit{}
if err := ssz.Unmarshal(enc, &dec); err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(dec, dep) {
t.Errorf("Wanted %v, received %v", dep, dec)
}
}
@@ -72,31 +109,35 @@ func TestGenerateTrieFromItems_NoItemsProvided(t *testing.T) {
func TestMerkleTrie_VerifyMerkleProof(t *testing.T) {
items := [][]byte{
[]byte("A"),
[]byte("BB"),
[]byte("CCC"),
[]byte("DDDD"),
[]byte("EEEEE"),
[]byte("FFFFFF"),
[]byte("GGGGGGG"),
[]byte("B"),
[]byte("C"),
[]byte("D"),
[]byte("E"),
[]byte("F"),
[]byte("G"),
[]byte("H"),
}
m, err := GenerateTrieFromItems(items, 32)
if err != nil {
t.Fatalf("Could not generate Merkle trie from items: %v", err)
}
proof, err := m.MerkleProof(2)
proof, err := m.MerkleProof(0)
if err != nil {
t.Fatalf("Could not generate Merkle proof: %v", err)
}
if len(proof) != 33 {
t.Errorf("Received len %d, wanted 33", len(proof))
}
root := m.Root()
if ok := VerifyMerkleProof(root[:], items[2], 2, proof); !ok {
t.Error("Merkle proof did not verify")
if ok := VerifyMerkleProof(root[:], items[0], 0, proof); !ok {
t.Error("First Merkle proof did not verify")
}
proof, err = m.MerkleProof(3)
if err != nil {
t.Fatalf("Could not generate Merkle proof: %v", err)
}
if ok := VerifyMerkleProof(root[:], items[3], 3, proof); !ok {
t.Error("Merkle proof did not verify")
t.Error("Second Merkle proof did not verify")
}
if ok := VerifyMerkleProof(root[:], []byte("buzz"), 3, proof); ok {
t.Error("Item not in tree should fail to verify")