From b3a17f3f229bf4864f045479777eef81314ad9be Mon Sep 17 00:00:00 2001 From: Yash Patil <40046473+ypatil12@users.noreply.github.com> Date: Tue, 4 Feb 2025 17:16:28 -0500 Subject: [PATCH] test: update pipeline & test runner to run mekong + deneb tests --- .github/workflows/pipeline.yml | 7 ++ .gitignore | 4 +- eigen_pod_proofs_test.go | 19 ++- go.mod | 1 + go.sum | 2 + onchain_test.go | 216 ++++++++++++++++++--------------- 6 files changed, 148 insertions(+), 101 deletions(-) diff --git a/.github/workflows/pipeline.yml b/.github/workflows/pipeline.yml index a1101859..3b442f70 100644 --- a/.github/workflows/pipeline.yml +++ b/.github/workflows/pipeline.yml @@ -58,10 +58,17 @@ jobs: - name: Download blockchain data run: | + # Download Deneb state curl -o data/deneb_holesky_beacon_state_2227472.ssz.zip https://dviu8zszosyat.cloudfront.net/deneb_holesky_beacon_state_2227472.ssz.zip (cd data && unzip deneb_holesky_beacon_state_2227472.ssz.zip) + # Download Electra State + curl -o data/electra_mekong_beacon_state_654719.ssz.zip https://d1w8rcimizlk6a.cloudfront.net/electra_mekong_beacon_state_654719.ssz.zip + (cd data && unzip electra_mekong_beacon_state_654719.ssz.zip) + - name: Run tests + env: + RPC_URL: ${{ secrets.RPC_URL }} run: | go test -v ./... goreleaser: diff --git a/.gitignore b/.gitignore index ac417b10..31960bed 100644 --- a/.gitignore +++ b/.gitignore @@ -19,4 +19,6 @@ test **/.DS_Store -*.ssz \ No newline at end of file +*.ssz + +.env \ No newline at end of file diff --git a/eigen_pod_proofs_test.go b/eigen_pod_proofs_test.go index 07938d57..c5c84200 100644 --- a/eigen_pod_proofs_test.go +++ b/eigen_pod_proofs_test.go @@ -1,6 +1,7 @@ package eigenpodproofs_test import ( + "os" "testing" eigenpodproofs "github.com/Layr-Labs/eigenpod-proofs-generation" @@ -11,10 +12,9 @@ import ( "github.com/attestantio/go-eth2-client/spec/phase0" gethcommon "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/ethclient" + "github.com/joho/godotenv" ) -const RPC_URL = "https://rpc.mekong.ethpandaops.io" - var BEACON_CHAIN_PROOFS_WRAPPER_ADDRESS = gethcommon.HexToAddress("0x874Be4b0CaC8D3F6286Eee6E6196553aabA8Cb85") var ( @@ -49,8 +49,17 @@ func loadBeaconState(headerPath, statePath string, chainID uint64) error { } func TestMain(m *testing.M) { - var err error - ethClient, err := ethclient.Dial(RPC_URL) + // Load .env file + if err := godotenv.Load(); err != nil { + panic("Error loading .env file") + } + + rpcURL := os.Getenv("RPC_URL") + if rpcURL == "" { + panic("RPC_URL must be set in .env file") + } + + ethClient, err := ethclient.Dial(rpcURL) if err != nil { panic(err) } @@ -60,7 +69,7 @@ func TestMain(m *testing.M) { panic(err) } - // Run tests twice - once for each network + // Run tests for each hard fork type if err := loadBeaconState( "data/electra_mekong_beacon_headers_654719.json", "data/electra_mekong_beacon_state_654719.ssz", diff --git a/go.mod b/go.mod index 176bc192..82389a88 100644 --- a/go.mod +++ b/go.mod @@ -45,6 +45,7 @@ require ( github.com/gorilla/websocket v1.5.3 // indirect github.com/holiman/uint256 v1.3.1 // indirect github.com/huandu/go-clone v1.6.0 // indirect + github.com/joho/godotenv v1.5.1 // indirect github.com/klauspost/cpuid/v2 v2.2.7 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect diff --git a/go.sum b/go.sum index 31ec8a9d..a5c50832 100644 --- a/go.sum +++ b/go.sum @@ -126,6 +126,8 @@ github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7Bd github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= github.com/jbrower95/multicall-go v0.0.0-20241012224745-7e9c19976cb5 h1:MbF9mcEhOK8A1lphvcfh5Tg7Y2p4iUAtw2+yz3jUa94= github.com/jbrower95/multicall-go v0.0.0-20241012224745-7e9c19976cb5/go.mod h1:cl6hJrk69g0EyKPgNySQbJE1nj29t2q7Pu0as27uC04= +github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= +github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/klauspost/compress v1.16.0 h1:iULayQNOReoYUe+1qtKOqw9CwJv3aNQu8ivo7lw1HU4= github.com/klauspost/compress v1.16.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM= diff --git a/onchain_test.go b/onchain_test.go index cfc0be49..b0913795 100644 --- a/onchain_test.go +++ b/onchain_test.go @@ -1,97 +1,123 @@ package eigenpodproofs_test -// func TestValidatorContainersProofOnChain(t *testing.T) { -// validators, err := beaconState.Validators() -// if err != nil { -// t.Fatal(err) -// } - -// validatorIndices := []uint64{} -// for i := int(0); i < len(validators); i += 100000000 { -// validatorIndices = append(validatorIndices, uint64(i)) -// } - -// verifyValidatorFieldsCallParams, err := epp.ProveValidatorContainers(beaconHeader, beaconState, validatorIndices) -// if err != nil { -// t.Fatal(err) -// } - -// blockRoot, err := beaconHeader.HashTreeRoot() -// if err != nil { -// t.Fatal(err) -// } - -// err = beaconChainProofsWrapper.VerifyStateRoot( -// &bind.CallOpts{}, -// blockRoot, -// BeaconChainProofsWrapper.BeaconChainProofsStateRootProof{ -// BeaconStateRoot: verifyValidatorFieldsCallParams.StateRootProof.BeaconStateRoot, -// Proof: verifyValidatorFieldsCallParams.StateRootProof.Proof.ToByteSlice(), -// }, -// ) -// assert.Nil(t, err) - -// for i := 0; i < len(verifyValidatorFieldsCallParams.ValidatorFields); i++ { -// validatorFields := [][32]byte{} -// for _, field := range verifyValidatorFieldsCallParams.ValidatorFields[i] { -// validatorFields = append(validatorFields, field) -// } - -// err = beaconChainProofsWrapper.VerifyValidatorFields( -// &bind.CallOpts{}, -// uint64(0), -// verifyValidatorFieldsCallParams.StateRootProof.BeaconStateRoot, -// validatorFields, -// verifyValidatorFieldsCallParams.ValidatorFieldsProofs[i].ToByteSlice(), -// new(big.Int).SetUint64(verifyValidatorFieldsCallParams.ValidatorIndices[i]), -// ) -// assert.Nil(t, err) -// } -// } - -// func TestValidatorBalancesProofOnChain(t *testing.T) { -// validators, err := beaconState.Validators() -// if err != nil { -// t.Fatal(err) -// } - -// validatorIndices := []uint64{} -// for i := int(0); i < len(validators); i += 100000000 { -// validatorIndices = append(validatorIndices, uint64(i)) -// } - -// verifyCheckpointProofsCallParams, err := epp.ProveCheckpointProofs(beaconHeader, beaconState, validatorIndices) -// if err != nil { -// t.Fatal(err) -// } - -// blockRoot, err := beaconHeader.HashTreeRoot() -// if err != nil { -// t.Fatal(err) -// } - -// err = beaconChainProofsWrapper.VerifyBalanceContainer( -// &bind.CallOpts{}, -// uint64(0), -// blockRoot, -// BeaconChainProofsWrapper.BeaconChainProofsBalanceContainerProof{ -// BalanceContainerRoot: verifyCheckpointProofsCallParams.ValidatorBalancesRootProof.ValidatorBalancesRoot, -// Proof: verifyCheckpointProofsCallParams.ValidatorBalancesRootProof.Proof.ToByteSlice(), -// }, -// ) -// assert.Nil(t, err) - -// for i := 0; i < len(verifyCheckpointProofsCallParams.BalanceProofs); i++ { -// _, err = beaconChainProofsWrapper.VerifyValidatorBalance( -// &bind.CallOpts{}, -// verifyCheckpointProofsCallParams.ValidatorBalancesRootProof.ValidatorBalancesRoot, -// new(big.Int).SetUint64(validatorIndices[i]), -// BeaconChainProofsWrapper.BeaconChainProofsBalanceProof{ -// PubkeyHash: verifyCheckpointProofsCallParams.BalanceProofs[i].PubkeyHash, -// BalanceRoot: verifyCheckpointProofsCallParams.BalanceProofs[i].BalanceRoot, -// Proof: verifyCheckpointProofsCallParams.BalanceProofs[i].Proof.ToByteSlice(), -// }, -// ) -// assert.Nil(t, err) -// } -// } +import ( + "math/big" + "testing" + + BeaconChainProofsWrapper "github.com/Layr-Labs/eigenpod-proofs-generation/bindings/BeaconChainProofsWrapper" + "github.com/attestantio/go-eth2-client/spec" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/stretchr/testify/assert" +) + +func TestValidatorContainersProofOnChain(t *testing.T) { + validators, err := beaconState.Validators() + if err != nil { + t.Fatal(err) + } + + validatorIndices := []uint64{} + for i := int(0); i < len(validators); i += 100000 { + validatorIndices = append(validatorIndices, uint64(i)) + } + + verifyValidatorFieldsCallParams, err := epp.ProveValidatorContainers(beaconHeader, beaconState, validatorIndices) + if err != nil { + t.Fatal(err) + } + + blockRoot, err := beaconHeader.HashTreeRoot() + if err != nil { + t.Fatal(err) + } + + err = beaconChainProofsWrapper.VerifyStateRoot( + &bind.CallOpts{}, + blockRoot, + BeaconChainProofsWrapper.BeaconChainProofsStateRootProof{ + BeaconStateRoot: verifyValidatorFieldsCallParams.StateRootProof.BeaconStateRoot, + Proof: verifyValidatorFieldsCallParams.StateRootProof.Proof.ToByteSlice(), + }, + ) + assert.Nil(t, err) + + // Update the proof timestamp depending on the beacon state version + var proofTimestamp uint64 + if beaconState.Version == spec.DataVersionElectra { + proofTimestamp = uint64(1730822401) // 1 second after mekong genesis + } else { + proofTimestamp = uint64(0) + } + + for i := 0; i < len(verifyValidatorFieldsCallParams.ValidatorFields); i++ { + validatorFields := [][32]byte{} + for _, field := range verifyValidatorFieldsCallParams.ValidatorFields[i] { + validatorFields = append(validatorFields, field) + } + + err = beaconChainProofsWrapper.VerifyValidatorFields( + &bind.CallOpts{}, + proofTimestamp, + verifyValidatorFieldsCallParams.StateRootProof.BeaconStateRoot, + validatorFields, + verifyValidatorFieldsCallParams.ValidatorFieldsProofs[i].ToByteSlice(), + new(big.Int).SetUint64(verifyValidatorFieldsCallParams.ValidatorIndices[i]), + ) + assert.Nil(t, err) + } +} + +func TestValidatorBalancesProofOnChain(t *testing.T) { + validators, err := beaconState.Validators() + if err != nil { + t.Fatal(err) + } + + validatorIndices := []uint64{} + for i := int(0); i < len(validators); i += 100000 { + validatorIndices = append(validatorIndices, uint64(i)) + } + + verifyCheckpointProofsCallParams, err := epp.ProveCheckpointProofs(beaconHeader, beaconState, validatorIndices) + if err != nil { + t.Fatal(err) + } + + blockRoot, err := beaconHeader.HashTreeRoot() + if err != nil { + t.Fatal(err) + } + + // Update the proof timestamp depending on the beacon state version + var proofTimestamp uint64 + if beaconState.Version == spec.DataVersionElectra { + proofTimestamp = uint64(1730822401) // 1 second after mekong genesis + } else { + proofTimestamp = uint64(0) + } + + err = beaconChainProofsWrapper.VerifyBalanceContainer( + &bind.CallOpts{}, + proofTimestamp, + blockRoot, + BeaconChainProofsWrapper.BeaconChainProofsBalanceContainerProof{ + BalanceContainerRoot: verifyCheckpointProofsCallParams.ValidatorBalancesRootProof.ValidatorBalancesRoot, + Proof: verifyCheckpointProofsCallParams.ValidatorBalancesRootProof.Proof.ToByteSlice(), + }, + ) + assert.Nil(t, err) + + for i := 0; i < len(verifyCheckpointProofsCallParams.BalanceProofs); i++ { + _, err = beaconChainProofsWrapper.VerifyValidatorBalance( + &bind.CallOpts{}, + verifyCheckpointProofsCallParams.ValidatorBalancesRootProof.ValidatorBalancesRoot, + new(big.Int).SetUint64(validatorIndices[i]), + BeaconChainProofsWrapper.BeaconChainProofsBalanceProof{ + PubkeyHash: verifyCheckpointProofsCallParams.BalanceProofs[i].PubkeyHash, + BalanceRoot: verifyCheckpointProofsCallParams.BalanceProofs[i].BalanceRoot, + Proof: verifyCheckpointProofsCallParams.BalanceProofs[i].Proof.ToByteSlice(), + }, + ) + assert.Nil(t, err) + } +}