mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-01-09 21:38:05 -05:00
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:
@@ -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 {
|
||||
|
||||
@@ -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 := ðpb.Deposit{
|
||||
Proof: proof,
|
||||
Data: ðpb.Deposit_Data{
|
||||
PublicKey: someKey[:],
|
||||
WithdrawalCredentials: someRoot[:],
|
||||
Amount: 32,
|
||||
Signature: someSig[:],
|
||||
},
|
||||
}
|
||||
enc, err := ssz.Marshal(dep)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
dec := ðpb.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")
|
||||
|
||||
Reference in New Issue
Block a user