mirror of
https://gitlab.com/pulsechaincom/prysm-pulse.git
synced 2025-01-03 00:27:38 +00:00
Eip4881: Tests (#11754)
This commit is contained in:
parent
cc764c346b
commit
8aec170f9b
15
WORKSPACE
15
WORKSPACE
@ -190,6 +190,21 @@ filegroup(
|
|||||||
url = "https://github.com/eth-clients/slashing-protection-interchange-tests/archive/b8413ca42dc92308019d0d4db52c87e9e125c4e9.tar.gz",
|
url = "https://github.com/eth-clients/slashing-protection-interchange-tests/archive/b8413ca42dc92308019d0d4db52c87e9e125c4e9.tar.gz",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
http_archive(
|
||||||
|
name = "eip4881_spec_tests",
|
||||||
|
build_file_content = """
|
||||||
|
filegroup(
|
||||||
|
name = "test_data",
|
||||||
|
srcs = glob([
|
||||||
|
"**/*.yaml",
|
||||||
|
]),
|
||||||
|
visibility = ["//visibility:public"],
|
||||||
|
)
|
||||||
|
""",
|
||||||
|
sha256 = "89cb659498c0d196fc9f957f8b849b2e1a5c041c3b2b3ae5432ac5c26944297e",
|
||||||
|
url = "https://github.com/ethereum/EIPs/archive/5480440fe51742ed23342b68cf106cefd427e39d.tar.gz",
|
||||||
|
)
|
||||||
|
|
||||||
consensus_spec_version = "v1.3.0-rc.3"
|
consensus_spec_version = "v1.3.0-rc.3"
|
||||||
|
|
||||||
bls_test_version = "v0.1.1"
|
bls_test_version = "v0.1.1"
|
||||||
|
24
beacon-chain/cache/depositsnapshot/BUILD.bazel
vendored
24
beacon-chain/cache/depositsnapshot/BUILD.bazel
vendored
@ -1,4 +1,4 @@
|
|||||||
load("@prysm//tools/go:def.bzl", "go_library")
|
load("@prysm//tools/go:def.bzl", "go_library", "go_test")
|
||||||
|
|
||||||
go_library(
|
go_library(
|
||||||
name = "go_default_library",
|
name = "go_default_library",
|
||||||
@ -19,3 +19,25 @@ go_library(
|
|||||||
"@com_github_pkg_errors//:go_default_library",
|
"@com_github_pkg_errors//:go_default_library",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
go_test(
|
||||||
|
name = "go_default_test",
|
||||||
|
srcs = [
|
||||||
|
"deposit_tree_snapshot_test.go",
|
||||||
|
"merkle_tree_test.go",
|
||||||
|
"spec_test.go",
|
||||||
|
],
|
||||||
|
data = [
|
||||||
|
"@eip4881_spec_tests//:test_data",
|
||||||
|
],
|
||||||
|
embed = [":go_default_library"],
|
||||||
|
deps = [
|
||||||
|
"//io/file:go_default_library",
|
||||||
|
"//proto/eth/v1:go_default_library",
|
||||||
|
"//testing/assert:go_default_library",
|
||||||
|
"//testing/require:go_default_library",
|
||||||
|
"@com_github_pkg_errors//:go_default_library",
|
||||||
|
"@in_gopkg_yaml_v3//:go_default_library",
|
||||||
|
"@io_bazel_rules_go//go/tools/bazel:go_default_library",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
@ -23,8 +23,6 @@ var (
|
|||||||
ErrInvalidIndex = errors.New("index should be greater than finalizedDeposits - 1")
|
ErrInvalidIndex = errors.New("index should be greater than finalizedDeposits - 1")
|
||||||
// ErrNoDeposits occurs when the number of deposits is 0.
|
// ErrNoDeposits occurs when the number of deposits is 0.
|
||||||
ErrNoDeposits = errors.New("number of deposits should be greater than 0")
|
ErrNoDeposits = errors.New("number of deposits should be greater than 0")
|
||||||
// ErrNoFinalizedDeposits occurs when the number of finalized deposits is 0.
|
|
||||||
ErrNoFinalizedDeposits = errors.New("number of finalized deposits should be greater than 0")
|
|
||||||
// ErrTooManyDeposits occurs when the number of deposits exceeds the capacity of the tree.
|
// ErrTooManyDeposits occurs when the number of deposits exceeds the capacity of the tree.
|
||||||
ErrTooManyDeposits = errors.New("number of deposits should not be greater than the capacity of the tree")
|
ErrTooManyDeposits = errors.New("number of deposits should not be greater than the capacity of the tree")
|
||||||
)
|
)
|
||||||
@ -62,7 +60,7 @@ func (d *DepositTree) getSnapshot() (DepositTreeSnapshot, error) {
|
|||||||
return DepositTreeSnapshot{}, ErrEmptyExecutionBlock
|
return DepositTreeSnapshot{}, ErrEmptyExecutionBlock
|
||||||
}
|
}
|
||||||
var finalized [][32]byte
|
var finalized [][32]byte
|
||||||
depositCount, _ := d.tree.GetFinalized(finalized)
|
depositCount, finalized := d.tree.GetFinalized(finalized)
|
||||||
return fromTreeParts(finalized, depositCount, d.finalizedExecutionBlock)
|
return fromTreeParts(finalized, depositCount, d.finalizedExecutionBlock)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -119,9 +117,6 @@ func (d *DepositTree) getProof(index uint64) ([32]byte, [][32]byte, error) {
|
|||||||
return [32]byte{}, nil, ErrInvalidMixInLength
|
return [32]byte{}, nil, ErrInvalidMixInLength
|
||||||
}
|
}
|
||||||
finalizedDeposits, _ := d.tree.GetFinalized([][32]byte{})
|
finalizedDeposits, _ := d.tree.GetFinalized([][32]byte{})
|
||||||
if finalizedDeposits == 0 {
|
|
||||||
return [32]byte{}, nil, ErrNoFinalizedDeposits
|
|
||||||
}
|
|
||||||
if finalizedDeposits != 0 {
|
if finalizedDeposits != 0 {
|
||||||
finalizedDeposits = finalizedDeposits - 1
|
finalizedDeposits = finalizedDeposits - 1
|
||||||
}
|
}
|
||||||
|
@ -40,7 +40,7 @@ func (ds *DepositTreeSnapshot) CalculateRoot() ([32]byte, error) {
|
|||||||
}
|
}
|
||||||
size >>= 1
|
size >>= 1
|
||||||
}
|
}
|
||||||
return sha256.Sum256(append(root[:], bytesutil.Uint64ToBytesLittleEndian(ds.depositCount)...)), nil
|
return sha256.Sum256(append(root[:], bytesutil.Uint64ToBytesLittleEndian32(ds.depositCount)...)), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// fromTreeParts constructs the deposit tree from pre-existing data.
|
// fromTreeParts constructs the deposit tree from pre-existing data.
|
||||||
|
54
beacon-chain/cache/depositsnapshot/deposit_tree_snapshot_test.go
vendored
Normal file
54
beacon-chain/cache/depositsnapshot/deposit_tree_snapshot_test.go
vendored
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
package depositsnapshot
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/prysmaticlabs/prysm/v3/testing/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestDepositTreeSnapshot_CalculateRoot(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
finalized int
|
||||||
|
depositCount uint64
|
||||||
|
want [32]byte
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "empty",
|
||||||
|
finalized: 0,
|
||||||
|
depositCount: 0,
|
||||||
|
want: [32]byte{215, 10, 35, 71, 49, 40, 92, 104, 4, 194, 164, 245, 103, 17, 221, 184, 200, 44, 153, 116, 15, 32, 120, 84, 137, 16, 40, 175, 52, 226, 126, 94},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "1 Finalized",
|
||||||
|
finalized: 1,
|
||||||
|
depositCount: 2,
|
||||||
|
want: [32]byte{36, 118, 154, 57, 217, 109, 145, 116, 238, 1, 207, 59, 187, 28, 69, 187, 70, 55, 153, 180, 15, 150, 37, 72, 140, 36, 109, 154, 212, 202, 47, 59},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "many finalised",
|
||||||
|
finalized: 6,
|
||||||
|
depositCount: 20,
|
||||||
|
want: [32]byte{210, 63, 57, 119, 12, 5, 3, 25, 139, 20, 244, 59, 114, 119, 35, 88, 222, 88, 122, 106, 239, 20, 45, 140, 99, 92, 222, 166, 133, 159, 128, 72},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
var finalized [][32]byte
|
||||||
|
for i := 0; i < tt.finalized; i++ {
|
||||||
|
finalized = append(finalized, hexString(t, fmt.Sprintf("%064d", i)))
|
||||||
|
}
|
||||||
|
ds := &DepositTreeSnapshot{
|
||||||
|
finalized: finalized,
|
||||||
|
depositCount: tt.depositCount,
|
||||||
|
}
|
||||||
|
root, err := ds.CalculateRoot()
|
||||||
|
require.NoError(t, err)
|
||||||
|
if got := root; !reflect.DeepEqual(got, tt.want) {
|
||||||
|
require.DeepEqual(t, tt.want, got)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
141
beacon-chain/cache/depositsnapshot/merkle_tree_test.go
vendored
Normal file
141
beacon-chain/cache/depositsnapshot/merkle_tree_test.go
vendored
Normal file
@ -0,0 +1,141 @@
|
|||||||
|
package depositsnapshot
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/hex"
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/prysmaticlabs/prysm/v3/testing/assert"
|
||||||
|
"github.com/prysmaticlabs/prysm/v3/testing/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func hexString(t *testing.T, hexStr string) [32]byte {
|
||||||
|
t.Helper()
|
||||||
|
b, err := hex.DecodeString(hexStr)
|
||||||
|
require.NoError(t, err)
|
||||||
|
if len(b) != 32 {
|
||||||
|
assert.Equal(t, 32, len(b), "bad hash length, expected 32")
|
||||||
|
}
|
||||||
|
x := (*[32]byte)(b)
|
||||||
|
return *x
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_create(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
leaves [][32]byte
|
||||||
|
depth uint64
|
||||||
|
want MerkleTreeNode
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "empty tree",
|
||||||
|
leaves: nil,
|
||||||
|
depth: 0,
|
||||||
|
want: &ZeroNode{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "zero depth",
|
||||||
|
leaves: [][32]byte{hexString(t, fmt.Sprintf("%064d", 0))},
|
||||||
|
depth: 0,
|
||||||
|
want: &LeafNode{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "depth of 1",
|
||||||
|
leaves: [][32]byte{hexString(t, fmt.Sprintf("%064d", 0))},
|
||||||
|
depth: 1,
|
||||||
|
want: &InnerNode{&LeafNode{}, &ZeroNode{}},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
if got := create(tt.leaves, tt.depth); !reflect.DeepEqual(got, tt.want) {
|
||||||
|
require.DeepEqual(t, tt.want, got)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_fromSnapshotParts(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
finalized [][32]byte
|
||||||
|
deposits uint64
|
||||||
|
level uint64
|
||||||
|
want MerkleTreeNode
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "empty",
|
||||||
|
finalized: nil,
|
||||||
|
deposits: 0,
|
||||||
|
level: 0,
|
||||||
|
want: &ZeroNode{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "single finalized node",
|
||||||
|
finalized: [][32]byte{hexString(t, fmt.Sprintf("%064d", 0))},
|
||||||
|
deposits: 1,
|
||||||
|
level: 0,
|
||||||
|
want: &FinalizedNode{
|
||||||
|
depositCount: 1,
|
||||||
|
hash: [32]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "multiple deposits and 1 Finalized",
|
||||||
|
finalized: [][32]byte{hexString(t, fmt.Sprintf("%064d", 0))},
|
||||||
|
deposits: 2,
|
||||||
|
level: 4,
|
||||||
|
want: &InnerNode{
|
||||||
|
left: &InnerNode{&InnerNode{&FinalizedNode{depositCount: 2, hash: hexString(t, fmt.Sprintf("%064d", 0))}, &ZeroNode{1}}, &ZeroNode{2}},
|
||||||
|
right: &ZeroNode{3},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
tree, err := fromSnapshotParts(tt.finalized, tt.deposits, tt.level)
|
||||||
|
require.NoError(t, err)
|
||||||
|
if got := tree; !reflect.DeepEqual(got, tt.want) {
|
||||||
|
require.DeepEqual(t, tt.want, got)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_generateProof(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
leaves uint64
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "1 leaf",
|
||||||
|
leaves: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "4 leaves",
|
||||||
|
leaves: 4,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "10 leaves",
|
||||||
|
leaves: 10,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
testCases, err := readTestCases()
|
||||||
|
require.NoError(t, err)
|
||||||
|
tree := New()
|
||||||
|
for _, c := range testCases[:tt.leaves] {
|
||||||
|
err = tree.pushLeaf(c.DepositDataRoot)
|
||||||
|
require.NoError(t, err)
|
||||||
|
}
|
||||||
|
for i := uint64(0); i < tt.leaves; i++ {
|
||||||
|
leaf, proof := generateProof(tree.tree, i, DepositContractDepth)
|
||||||
|
require.Equal(t, leaf, testCases[i].DepositDataRoot)
|
||||||
|
calcRoot := merkleRootFromBranch(leaf, proof, i)
|
||||||
|
require.Equal(t, tree.tree.GetRoot(), calcRoot)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
355
beacon-chain/cache/depositsnapshot/spec_test.go
vendored
Normal file
355
beacon-chain/cache/depositsnapshot/spec_test.go
vendored
Normal file
@ -0,0 +1,355 @@
|
|||||||
|
package depositsnapshot
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/sha256"
|
||||||
|
"encoding/hex"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/bazelbuild/rules_go/go/tools/bazel"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
"github.com/prysmaticlabs/prysm/v3/io/file"
|
||||||
|
eth "github.com/prysmaticlabs/prysm/v3/proto/eth/v1"
|
||||||
|
"github.com/prysmaticlabs/prysm/v3/testing/require"
|
||||||
|
"gopkg.in/yaml.v3"
|
||||||
|
)
|
||||||
|
|
||||||
|
type testCase struct {
|
||||||
|
DepositData depositData `yaml:"deposit_data"`
|
||||||
|
DepositDataRoot [32]byte `yaml:"deposit_data_root"`
|
||||||
|
Eth1Data *eth1Data `yaml:"eth1_data"`
|
||||||
|
BlockHeight uint64 `yaml:"block_height"`
|
||||||
|
Snapshot snapshot `yaml:"snapshot"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tc *testCase) UnmarshalYAML(value *yaml.Node) error {
|
||||||
|
raw := struct {
|
||||||
|
DepositData depositData `yaml:"deposit_data"`
|
||||||
|
DepositDataRoot string `yaml:"deposit_data_root"`
|
||||||
|
Eth1Data *eth1Data `yaml:"eth1_data"`
|
||||||
|
BlockHeight string `yaml:"block_height"`
|
||||||
|
Snapshot snapshot `yaml:"snapshot"`
|
||||||
|
}{}
|
||||||
|
err := value.Decode(&raw)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
tc.DepositDataRoot, err = hexStringToByteArray(raw.DepositDataRoot)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
tc.DepositData = raw.DepositData
|
||||||
|
tc.Eth1Data = raw.Eth1Data
|
||||||
|
tc.BlockHeight, err = stringToUint64(raw.BlockHeight)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
tc.Snapshot = raw.Snapshot
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type depositData struct {
|
||||||
|
Pubkey []byte `yaml:"pubkey"`
|
||||||
|
WithdrawalCredentials []byte `yaml:"withdrawal_credentials"`
|
||||||
|
Amount uint64 `yaml:"amount"`
|
||||||
|
Signature []byte `yaml:"signature"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (dd *depositData) UnmarshalYAML(value *yaml.Node) error {
|
||||||
|
raw := struct {
|
||||||
|
Pubkey string `yaml:"pubkey"`
|
||||||
|
WithdrawalCredentials string `yaml:"withdrawal_credentials"`
|
||||||
|
Amount string `yaml:"amount"`
|
||||||
|
Signature string `yaml:"signature"`
|
||||||
|
}{}
|
||||||
|
err := value.Decode(&raw)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
dd.Pubkey, err = hexStringToBytes(raw.Pubkey)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
dd.WithdrawalCredentials, err = hexStringToBytes(raw.WithdrawalCredentials)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
dd.Amount, err = strconv.ParseUint(raw.Amount, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
dd.Signature, err = hexStringToBytes(raw.Signature)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type eth1Data struct {
|
||||||
|
DepositRoot [32]byte `yaml:"deposit_root"`
|
||||||
|
DepositCount uint64 `yaml:"deposit_count"`
|
||||||
|
BlockHash [32]byte `yaml:"block_hash"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ed *eth1Data) UnmarshalYAML(value *yaml.Node) error {
|
||||||
|
raw := struct {
|
||||||
|
DepositRoot string `yaml:"deposit_root"`
|
||||||
|
DepositCount string `yaml:"deposit_count"`
|
||||||
|
BlockHash string `yaml:"block_hash"`
|
||||||
|
}{}
|
||||||
|
err := value.Decode(&raw)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
ed.DepositRoot, err = hexStringToByteArray(raw.DepositRoot)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
ed.DepositCount, err = stringToUint64(raw.DepositCount)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
ed.BlockHash, err = hexStringToByteArray(raw.BlockHash)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type snapshot struct {
|
||||||
|
DepositTreeSnapshot
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sd *snapshot) UnmarshalYAML(value *yaml.Node) error {
|
||||||
|
raw := struct {
|
||||||
|
Finalized []string `yaml:"finalized"`
|
||||||
|
DepositRoot string `yaml:"deposit_root"`
|
||||||
|
DepositCount string `yaml:"deposit_count"`
|
||||||
|
ExecutionBlockHash string `yaml:"execution_block_hash"`
|
||||||
|
ExecutionBlockHeight string `yaml:"execution_block_height"`
|
||||||
|
}{}
|
||||||
|
err := value.Decode(&raw)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
sd.finalized = make([][32]byte, len(raw.Finalized))
|
||||||
|
for i, finalized := range raw.Finalized {
|
||||||
|
sd.finalized[i], err = hexStringToByteArray(finalized)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sd.depositRoot, err = hexStringToByteArray(raw.DepositRoot)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
sd.depositCount, err = stringToUint64(raw.DepositCount)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
sd.executionBlock.Hash, err = hexStringToByteArray(raw.ExecutionBlockHash)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
sd.executionBlock.Depth, err = stringToUint64(raw.ExecutionBlockHeight)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func readTestCases() ([]testCase, error) {
|
||||||
|
testFolders, err := bazel.ListRunfiles()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for _, ff := range testFolders {
|
||||||
|
if strings.Contains(ff.ShortPath, "eip4881_spec_tests") &&
|
||||||
|
strings.Contains(ff.ShortPath, "eip-4881/test_cases.yaml") {
|
||||||
|
enc, err := file.ReadFileAsBytes(ff.Path)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var testCases []testCase
|
||||||
|
err = yaml.Unmarshal(enc, &testCases)
|
||||||
|
if err != nil {
|
||||||
|
return []testCase{}, err
|
||||||
|
}
|
||||||
|
return testCases, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, errors.New("spec test file not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRead(t *testing.T) {
|
||||||
|
tcs, err := readTestCases()
|
||||||
|
require.NoError(t, err)
|
||||||
|
for _, tc := range tcs {
|
||||||
|
t.Log(tc)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func hexStringToByteArray(s string) (b [32]byte, err error) {
|
||||||
|
var raw []byte
|
||||||
|
raw, err = hexStringToBytes(s)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if len(raw) != 32 {
|
||||||
|
err = errors.New("invalid hex string length")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
copy(b[:], raw[:32])
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func hexStringToBytes(s string) (b []byte, err error) {
|
||||||
|
b, err = hex.DecodeString(strings.TrimPrefix(s, "0x"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func stringToUint64(s string) (uint64, error) {
|
||||||
|
value, err := strconv.ParseUint(s, 10, 32)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return value, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func merkleRootFromBranch(leaf [32]byte, branch [][32]byte, index uint64) [32]byte {
|
||||||
|
root := leaf
|
||||||
|
for i, l := range branch {
|
||||||
|
ithBit := (index >> i) & 0x1
|
||||||
|
if ithBit == 1 {
|
||||||
|
root = sha256.Sum256(append(l[:], root[:]...))
|
||||||
|
} else {
|
||||||
|
root = sha256.Sum256(append(root[:], l[:]...))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return root
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkProof(t *testing.T, tree *DepositTree, index uint64) {
|
||||||
|
leaf, proof, err := tree.getProof(index)
|
||||||
|
require.NoError(t, err)
|
||||||
|
calcRoot := merkleRootFromBranch(leaf, proof, index)
|
||||||
|
require.Equal(t, tree.getRoot(), calcRoot)
|
||||||
|
}
|
||||||
|
|
||||||
|
func compareProof(t *testing.T, tree1, tree2 *DepositTree, index uint64) {
|
||||||
|
require.Equal(t, tree1.getRoot(), tree2.getRoot())
|
||||||
|
checkProof(t, tree1, index)
|
||||||
|
checkProof(t, tree2, index)
|
||||||
|
}
|
||||||
|
|
||||||
|
func cloneFromSnapshot(t *testing.T, snapshot DepositTreeSnapshot, testCases []testCase) *DepositTree {
|
||||||
|
cp, err := fromSnapshot(snapshot)
|
||||||
|
require.NoError(t, err)
|
||||||
|
for _, c := range testCases {
|
||||||
|
err = cp.pushLeaf(c.DepositDataRoot)
|
||||||
|
require.NoError(t, err)
|
||||||
|
}
|
||||||
|
return &cp
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDepositCases(t *testing.T) {
|
||||||
|
tree := New()
|
||||||
|
testCases, err := readTestCases()
|
||||||
|
require.NoError(t, err)
|
||||||
|
for _, c := range testCases {
|
||||||
|
err = tree.pushLeaf(c.DepositDataRoot)
|
||||||
|
require.NoError(t, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFinalization(t *testing.T) {
|
||||||
|
tree := New()
|
||||||
|
testCases, err := readTestCases()
|
||||||
|
require.NoError(t, err)
|
||||||
|
for _, c := range testCases[:128] {
|
||||||
|
err = tree.pushLeaf(c.DepositDataRoot)
|
||||||
|
require.NoError(t, err)
|
||||||
|
}
|
||||||
|
originalRoot := tree.getRoot()
|
||||||
|
require.DeepEqual(t, testCases[127].Eth1Data.DepositRoot, originalRoot)
|
||||||
|
err = tree.finalize(ð.Eth1Data{
|
||||||
|
DepositRoot: testCases[100].Eth1Data.DepositRoot[:],
|
||||||
|
DepositCount: testCases[100].Eth1Data.DepositCount,
|
||||||
|
BlockHash: testCases[100].Eth1Data.BlockHash[:],
|
||||||
|
}, testCases[100].BlockHeight)
|
||||||
|
require.NoError(t, err)
|
||||||
|
// ensure finalization doesn't change root
|
||||||
|
require.Equal(t, tree.getRoot(), originalRoot)
|
||||||
|
snapshotData, err := tree.getSnapshot()
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.DeepEqual(t, testCases[100].Snapshot.DepositTreeSnapshot, snapshotData)
|
||||||
|
// create a copy of the tree from a snapshot by replaying
|
||||||
|
// the deposits after the finalized deposit
|
||||||
|
cp := cloneFromSnapshot(t, snapshotData, testCases[101:128])
|
||||||
|
// ensure original and copy have the same root
|
||||||
|
require.Equal(t, tree.getRoot(), cp.getRoot())
|
||||||
|
// finalize original again to check double finalization
|
||||||
|
err = tree.finalize(ð.Eth1Data{
|
||||||
|
DepositRoot: testCases[105].Eth1Data.DepositRoot[:],
|
||||||
|
DepositCount: testCases[105].Eth1Data.DepositCount,
|
||||||
|
BlockHash: testCases[105].Eth1Data.BlockHash[:],
|
||||||
|
}, testCases[105].BlockHeight)
|
||||||
|
require.NoError(t, err)
|
||||||
|
// root should still be the same
|
||||||
|
require.Equal(t, originalRoot, tree.getRoot())
|
||||||
|
// create a copy of the tree by taking a snapshot again
|
||||||
|
snapshotData, err = tree.getSnapshot()
|
||||||
|
require.NoError(t, err)
|
||||||
|
cp = cloneFromSnapshot(t, snapshotData, testCases[106:128])
|
||||||
|
// create a copy of the tree by replaying ALL deposits from nothing
|
||||||
|
fullTreeCopy := New()
|
||||||
|
for _, c := range testCases[:128] {
|
||||||
|
err = fullTreeCopy.pushLeaf(c.DepositDataRoot)
|
||||||
|
require.NoError(t, err)
|
||||||
|
}
|
||||||
|
for i := 106; i < 128; i++ {
|
||||||
|
compareProof(t, tree, cp, uint64(i))
|
||||||
|
compareProof(t, tree, fullTreeCopy, uint64(i))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSnapshotCases(t *testing.T) {
|
||||||
|
tree := New()
|
||||||
|
testCases, err := readTestCases()
|
||||||
|
require.NoError(t, err)
|
||||||
|
for _, c := range testCases {
|
||||||
|
err = tree.pushLeaf(c.DepositDataRoot)
|
||||||
|
require.NoError(t, err)
|
||||||
|
}
|
||||||
|
for _, c := range testCases {
|
||||||
|
err = tree.finalize(ð.Eth1Data{
|
||||||
|
DepositRoot: c.Eth1Data.DepositRoot[:],
|
||||||
|
DepositCount: c.Eth1Data.DepositCount,
|
||||||
|
BlockHash: c.Eth1Data.BlockHash[:],
|
||||||
|
}, c.BlockHeight)
|
||||||
|
require.NoError(t, err)
|
||||||
|
s, err := tree.getSnapshot()
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.DeepEqual(t, c.Snapshot.DepositTreeSnapshot, s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEmptyTreeSnapshot(t *testing.T) {
|
||||||
|
_, err := New().getSnapshot()
|
||||||
|
require.ErrorContains(t, "empty execution block", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestInvalidSnapshot(t *testing.T) {
|
||||||
|
invalidSnapshot := DepositTreeSnapshot{
|
||||||
|
finalized: nil,
|
||||||
|
depositRoot: Zerohashes[0],
|
||||||
|
depositCount: 0,
|
||||||
|
executionBlock: executionBlock{
|
||||||
|
Hash: Zerohashes[0],
|
||||||
|
Depth: 0,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
_, err := fromSnapshot(invalidSnapshot)
|
||||||
|
require.ErrorContains(t, "snapshot root is invalid", err)
|
||||||
|
}
|
2
go.mod
2
go.mod
@ -91,6 +91,7 @@ require (
|
|||||||
google.golang.org/protobuf v1.28.1
|
google.golang.org/protobuf v1.28.1
|
||||||
gopkg.in/d4l3k/messagediff.v1 v1.2.1
|
gopkg.in/d4l3k/messagediff.v1 v1.2.1
|
||||||
gopkg.in/yaml.v2 v2.4.0
|
gopkg.in/yaml.v2 v2.4.0
|
||||||
|
gopkg.in/yaml.v3 v3.0.1
|
||||||
k8s.io/client-go v0.18.3
|
k8s.io/client-go v0.18.3
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -230,7 +231,6 @@ require (
|
|||||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||||
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce // indirect
|
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce // indirect
|
||||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
|
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
|
||||||
k8s.io/apimachinery v0.18.3 // indirect
|
k8s.io/apimachinery v0.18.3 // indirect
|
||||||
k8s.io/klog v1.0.0 // indirect
|
k8s.io/klog v1.0.0 // indirect
|
||||||
lukechampine.com/blake3 v1.1.7 // indirect
|
lukechampine.com/blake3 v1.1.7 // indirect
|
||||||
|
Loading…
Reference in New Issue
Block a user