From cafb9a322a69cc84627ebb4960accee91f8d3b13 Mon Sep 17 00:00:00 2001 From: SiddyJ Date: Fri, 9 Feb 2024 11:08:37 -0800 Subject: [PATCH] added first test --- bindings/BeaconChainProofs.go | 284 ++++++++++++++++++++++++++++++++++ build/BeaconChainProofs.abi | 138 +++++++++++++++++ build/Endian.abi | 1 + build/Merkle.abi | 1 + merkle_util_test.go | 20 +-- onchain_test.go | 77 --------- onchain_tests/onchain_test.go | 157 +++++++++++++++++++ proof_utils.go | 19 +++ 8 files changed, 610 insertions(+), 87 deletions(-) create mode 100644 bindings/BeaconChainProofs.go create mode 100644 build/BeaconChainProofs.abi create mode 100644 build/Endian.abi create mode 100644 build/Merkle.abi delete mode 100644 onchain_test.go create mode 100644 onchain_tests/onchain_test.go diff --git a/bindings/BeaconChainProofs.go b/bindings/BeaconChainProofs.go new file mode 100644 index 00000000..4acd4fcb --- /dev/null +++ b/bindings/BeaconChainProofs.go @@ -0,0 +1,284 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package contractBeaconChainProofs + +import ( + "errors" + "math/big" + "strings" + + ethereum "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/event" +) + +// Reference imports to suppress errors if they are not otherwise used. +var ( + _ = errors.New + _ = big.NewInt + _ = strings.NewReader + _ = ethereum.NotFound + _ = bind.Bind + _ = common.Big1 + _ = types.BloomLookup + _ = event.NewSubscription + _ = abi.ConvertType +) + +// BeaconChainProofsWithdrawalProof is an auto generated low-level Go binding around an user-defined struct. +type BeaconChainProofsWithdrawalProof struct { + WithdrawalProof []byte + SlotProof []byte + ExecutionPayloadProof []byte + TimestampProof []byte + HistoricalSummaryBlockRootProof []byte + BlockRootIndex uint64 + HistoricalSummaryIndex uint64 + WithdrawalIndex uint64 + BlockRoot [32]byte + SlotRoot [32]byte + TimestampRoot [32]byte + ExecutionPayloadRoot [32]byte +} + +// BeaconChainProofsMetaData contains all meta data concerning the BeaconChainProofs contract. +var BeaconChainProofsMetaData = &bind.MetaData{ + ABI: "[{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"latestBlockRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"beaconStateRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes\",\"name\":\"stateRootProof\",\"type\":\"bytes\"}],\"name\":\"verifyStateRootAgainstLatestBlockRoot\",\"outputs\":[],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"beaconStateRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32[]\",\"name\":\"validatorFields\",\"type\":\"bytes32[]\"},{\"internalType\":\"bytes\",\"name\":\"validatorFieldsProof\",\"type\":\"bytes\"},{\"internalType\":\"uint40\",\"name\":\"validatorIndex\",\"type\":\"uint40\"}],\"name\":\"verifyValidatorFields\",\"outputs\":[],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"beaconStateRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32[]\",\"name\":\"withdrawalFields\",\"type\":\"bytes32[]\"},{\"components\":[{\"internalType\":\"bytes\",\"name\":\"withdrawalProof\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"slotProof\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"executionPayloadProof\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"timestampProof\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"historicalSummaryBlockRootProof\",\"type\":\"bytes\"},{\"internalType\":\"uint64\",\"name\":\"blockRootIndex\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"historicalSummaryIndex\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"withdrawalIndex\",\"type\":\"uint64\"},{\"internalType\":\"bytes32\",\"name\":\"blockRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"slotRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"timestampRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"executionPayloadRoot\",\"type\":\"bytes32\"}],\"internalType\":\"structBeaconChainProofs.WithdrawalProof\",\"name\":\"withdrawalProof\",\"type\":\"tuple\"}],\"name\":\"verifyWithdrawal\",\"outputs\":[],\"stateMutability\":\"view\",\"type\":\"function\"}]", +} + +// BeaconChainProofsABI is the input ABI used to generate the binding from. +// Deprecated: Use BeaconChainProofsMetaData.ABI instead. +var BeaconChainProofsABI = BeaconChainProofsMetaData.ABI + +// BeaconChainProofs is an auto generated Go binding around an Ethereum contract. +type BeaconChainProofs struct { + BeaconChainProofsCaller // Read-only binding to the contract + BeaconChainProofsTransactor // Write-only binding to the contract + BeaconChainProofsFilterer // Log filterer for contract events +} + +// BeaconChainProofsCaller is an auto generated read-only Go binding around an Ethereum contract. +type BeaconChainProofsCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// BeaconChainProofsTransactor is an auto generated write-only Go binding around an Ethereum contract. +type BeaconChainProofsTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// BeaconChainProofsFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type BeaconChainProofsFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// BeaconChainProofsSession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type BeaconChainProofsSession struct { + Contract *BeaconChainProofs // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// BeaconChainProofsCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type BeaconChainProofsCallerSession struct { + Contract *BeaconChainProofsCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// BeaconChainProofsTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type BeaconChainProofsTransactorSession struct { + Contract *BeaconChainProofsTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// BeaconChainProofsRaw is an auto generated low-level Go binding around an Ethereum contract. +type BeaconChainProofsRaw struct { + Contract *BeaconChainProofs // Generic contract binding to access the raw methods on +} + +// BeaconChainProofsCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type BeaconChainProofsCallerRaw struct { + Contract *BeaconChainProofsCaller // Generic read-only contract binding to access the raw methods on +} + +// BeaconChainProofsTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type BeaconChainProofsTransactorRaw struct { + Contract *BeaconChainProofsTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewBeaconChainProofs creates a new instance of BeaconChainProofs, bound to a specific deployed contract. +func NewBeaconChainProofs(address common.Address, backend bind.ContractBackend) (*BeaconChainProofs, error) { + contract, err := bindBeaconChainProofs(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &BeaconChainProofs{BeaconChainProofsCaller: BeaconChainProofsCaller{contract: contract}, BeaconChainProofsTransactor: BeaconChainProofsTransactor{contract: contract}, BeaconChainProofsFilterer: BeaconChainProofsFilterer{contract: contract}}, nil +} + +// NewBeaconChainProofsCaller creates a new read-only instance of BeaconChainProofs, bound to a specific deployed contract. +func NewBeaconChainProofsCaller(address common.Address, caller bind.ContractCaller) (*BeaconChainProofsCaller, error) { + contract, err := bindBeaconChainProofs(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &BeaconChainProofsCaller{contract: contract}, nil +} + +// NewBeaconChainProofsTransactor creates a new write-only instance of BeaconChainProofs, bound to a specific deployed contract. +func NewBeaconChainProofsTransactor(address common.Address, transactor bind.ContractTransactor) (*BeaconChainProofsTransactor, error) { + contract, err := bindBeaconChainProofs(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &BeaconChainProofsTransactor{contract: contract}, nil +} + +// NewBeaconChainProofsFilterer creates a new log filterer instance of BeaconChainProofs, bound to a specific deployed contract. +func NewBeaconChainProofsFilterer(address common.Address, filterer bind.ContractFilterer) (*BeaconChainProofsFilterer, error) { + contract, err := bindBeaconChainProofs(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &BeaconChainProofsFilterer{contract: contract}, nil +} + +// bindBeaconChainProofs binds a generic wrapper to an already deployed contract. +func bindBeaconChainProofs(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := BeaconChainProofsMetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_BeaconChainProofs *BeaconChainProofsRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _BeaconChainProofs.Contract.BeaconChainProofsCaller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_BeaconChainProofs *BeaconChainProofsRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _BeaconChainProofs.Contract.BeaconChainProofsTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_BeaconChainProofs *BeaconChainProofsRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _BeaconChainProofs.Contract.BeaconChainProofsTransactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_BeaconChainProofs *BeaconChainProofsCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _BeaconChainProofs.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_BeaconChainProofs *BeaconChainProofsTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _BeaconChainProofs.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_BeaconChainProofs *BeaconChainProofsTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _BeaconChainProofs.Contract.contract.Transact(opts, method, params...) +} + +// VerifyStateRootAgainstLatestBlockRoot is a free data retrieval call binding the contract method 0x9cdee1f8. +// +// Solidity: function verifyStateRootAgainstLatestBlockRoot(bytes32 latestBlockRoot, bytes32 beaconStateRoot, bytes stateRootProof) view returns() +func (_BeaconChainProofs *BeaconChainProofsCaller) VerifyStateRootAgainstLatestBlockRoot(opts *bind.CallOpts, latestBlockRoot [32]byte, beaconStateRoot [32]byte, stateRootProof []byte) error { + var out []interface{} + err := _BeaconChainProofs.contract.Call(opts, &out, "verifyStateRootAgainstLatestBlockRoot", latestBlockRoot, beaconStateRoot, stateRootProof) + + if err != nil { + return err + } + + return err + +} + +// VerifyStateRootAgainstLatestBlockRoot is a free data retrieval call binding the contract method 0x9cdee1f8. +// +// Solidity: function verifyStateRootAgainstLatestBlockRoot(bytes32 latestBlockRoot, bytes32 beaconStateRoot, bytes stateRootProof) view returns() +func (_BeaconChainProofs *BeaconChainProofsSession) VerifyStateRootAgainstLatestBlockRoot(latestBlockRoot [32]byte, beaconStateRoot [32]byte, stateRootProof []byte) error { + return _BeaconChainProofs.Contract.VerifyStateRootAgainstLatestBlockRoot(&_BeaconChainProofs.CallOpts, latestBlockRoot, beaconStateRoot, stateRootProof) +} + +// VerifyStateRootAgainstLatestBlockRoot is a free data retrieval call binding the contract method 0x9cdee1f8. +// +// Solidity: function verifyStateRootAgainstLatestBlockRoot(bytes32 latestBlockRoot, bytes32 beaconStateRoot, bytes stateRootProof) view returns() +func (_BeaconChainProofs *BeaconChainProofsCallerSession) VerifyStateRootAgainstLatestBlockRoot(latestBlockRoot [32]byte, beaconStateRoot [32]byte, stateRootProof []byte) error { + return _BeaconChainProofs.Contract.VerifyStateRootAgainstLatestBlockRoot(&_BeaconChainProofs.CallOpts, latestBlockRoot, beaconStateRoot, stateRootProof) +} + +// VerifyValidatorFields is a free data retrieval call binding the contract method 0x256f222b. +// +// Solidity: function verifyValidatorFields(bytes32 beaconStateRoot, bytes32[] validatorFields, bytes validatorFieldsProof, uint40 validatorIndex) view returns() +func (_BeaconChainProofs *BeaconChainProofsCaller) VerifyValidatorFields(opts *bind.CallOpts, beaconStateRoot [32]byte, validatorFields [][32]byte, validatorFieldsProof []byte, validatorIndex *big.Int) error { + var out []interface{} + err := _BeaconChainProofs.contract.Call(opts, &out, "verifyValidatorFields", beaconStateRoot, validatorFields, validatorFieldsProof, validatorIndex) + + if err != nil { + return err + } + + return err + +} + +// VerifyValidatorFields is a free data retrieval call binding the contract method 0x256f222b. +// +// Solidity: function verifyValidatorFields(bytes32 beaconStateRoot, bytes32[] validatorFields, bytes validatorFieldsProof, uint40 validatorIndex) view returns() +func (_BeaconChainProofs *BeaconChainProofsSession) VerifyValidatorFields(beaconStateRoot [32]byte, validatorFields [][32]byte, validatorFieldsProof []byte, validatorIndex *big.Int) error { + return _BeaconChainProofs.Contract.VerifyValidatorFields(&_BeaconChainProofs.CallOpts, beaconStateRoot, validatorFields, validatorFieldsProof, validatorIndex) +} + +// VerifyValidatorFields is a free data retrieval call binding the contract method 0x256f222b. +// +// Solidity: function verifyValidatorFields(bytes32 beaconStateRoot, bytes32[] validatorFields, bytes validatorFieldsProof, uint40 validatorIndex) view returns() +func (_BeaconChainProofs *BeaconChainProofsCallerSession) VerifyValidatorFields(beaconStateRoot [32]byte, validatorFields [][32]byte, validatorFieldsProof []byte, validatorIndex *big.Int) error { + return _BeaconChainProofs.Contract.VerifyValidatorFields(&_BeaconChainProofs.CallOpts, beaconStateRoot, validatorFields, validatorFieldsProof, validatorIndex) +} + +// VerifyWithdrawal is a free data retrieval call binding the contract method 0xbf03617a. +// +// Solidity: function verifyWithdrawal(bytes32 beaconStateRoot, bytes32[] withdrawalFields, (bytes,bytes,bytes,bytes,bytes,uint64,uint64,uint64,bytes32,bytes32,bytes32,bytes32) withdrawalProof) view returns() +func (_BeaconChainProofs *BeaconChainProofsCaller) VerifyWithdrawal(opts *bind.CallOpts, beaconStateRoot [32]byte, withdrawalFields [][32]byte, withdrawalProof BeaconChainProofsWithdrawalProof) error { + var out []interface{} + err := _BeaconChainProofs.contract.Call(opts, &out, "verifyWithdrawal", beaconStateRoot, withdrawalFields, withdrawalProof) + + if err != nil { + return err + } + + return err + +} + +// VerifyWithdrawal is a free data retrieval call binding the contract method 0xbf03617a. +// +// Solidity: function verifyWithdrawal(bytes32 beaconStateRoot, bytes32[] withdrawalFields, (bytes,bytes,bytes,bytes,bytes,uint64,uint64,uint64,bytes32,bytes32,bytes32,bytes32) withdrawalProof) view returns() +func (_BeaconChainProofs *BeaconChainProofsSession) VerifyWithdrawal(beaconStateRoot [32]byte, withdrawalFields [][32]byte, withdrawalProof BeaconChainProofsWithdrawalProof) error { + return _BeaconChainProofs.Contract.VerifyWithdrawal(&_BeaconChainProofs.CallOpts, beaconStateRoot, withdrawalFields, withdrawalProof) +} + +// VerifyWithdrawal is a free data retrieval call binding the contract method 0xbf03617a. +// +// Solidity: function verifyWithdrawal(bytes32 beaconStateRoot, bytes32[] withdrawalFields, (bytes,bytes,bytes,bytes,bytes,uint64,uint64,uint64,bytes32,bytes32,bytes32,bytes32) withdrawalProof) view returns() +func (_BeaconChainProofs *BeaconChainProofsCallerSession) VerifyWithdrawal(beaconStateRoot [32]byte, withdrawalFields [][32]byte, withdrawalProof BeaconChainProofsWithdrawalProof) error { + return _BeaconChainProofs.Contract.VerifyWithdrawal(&_BeaconChainProofs.CallOpts, beaconStateRoot, withdrawalFields, withdrawalProof) +} diff --git a/build/BeaconChainProofs.abi b/build/BeaconChainProofs.abi new file mode 100644 index 00000000..fc664fd4 --- /dev/null +++ b/build/BeaconChainProofs.abi @@ -0,0 +1,138 @@ +[ + { + "inputs": [ + { + "internalType": "bytes32", + "name": "latestBlockRoot", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "beaconStateRoot", + "type": "bytes32" + }, + { + "internalType": "bytes", + "name": "stateRootProof", + "type": "bytes" + } + ], + "name": "verifyStateRootAgainstLatestBlockRoot", + "outputs": [], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "beaconStateRoot", + "type": "bytes32" + }, + { + "internalType": "bytes32[]", + "name": "validatorFields", + "type": "bytes32[]" + }, + { + "internalType": "bytes", + "name": "validatorFieldsProof", + "type": "bytes" + }, + { + "internalType": "uint40", + "name": "validatorIndex", + "type": "uint40" + } + ], + "name": "verifyValidatorFields", + "outputs": [], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "beaconStateRoot", + "type": "bytes32" + }, + { + "internalType": "bytes32[]", + "name": "withdrawalFields", + "type": "bytes32[]" + }, + { + "components": [ + { + "internalType": "bytes", + "name": "withdrawalProof", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "slotProof", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "executionPayloadProof", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "timestampProof", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "historicalSummaryBlockRootProof", + "type": "bytes" + }, + { + "internalType": "uint64", + "name": "blockRootIndex", + "type": "uint64" + }, + { + "internalType": "uint64", + "name": "historicalSummaryIndex", + "type": "uint64" + }, + { + "internalType": "uint64", + "name": "withdrawalIndex", + "type": "uint64" + }, + { + "internalType": "bytes32", + "name": "blockRoot", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "slotRoot", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "timestampRoot", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "executionPayloadRoot", + "type": "bytes32" + } + ], + "internalType": "struct BeaconChainProofs.WithdrawalProof", + "name": "withdrawalProof", + "type": "tuple" + } + ], + "name": "verifyWithdrawal", + "outputs": [], + "stateMutability": "view", + "type": "function" + } +] \ No newline at end of file diff --git a/build/Endian.abi b/build/Endian.abi new file mode 100644 index 00000000..0637a088 --- /dev/null +++ b/build/Endian.abi @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/build/Merkle.abi b/build/Merkle.abi new file mode 100644 index 00000000..0637a088 --- /dev/null +++ b/build/Merkle.abi @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/merkle_util_test.go b/merkle_util_test.go index 3092e81f..bc76e537 100644 --- a/merkle_util_test.go +++ b/merkle_util_test.go @@ -70,7 +70,7 @@ func setupSuite() { //ParseCapellaBeaconState(stateFile) - stateJSON, err := parseJSONFile(stateFile) + stateJSON, err := ParseJSONFile(stateFile) if err != nil { fmt.Println("error with JSON parsing beacon state") } @@ -140,7 +140,7 @@ func TestProveWithdrawals(t *testing.T) { return } - historicalSummaryStateJSON, err := parseJSONFile("data/deneb_goerli_slot_7421952.json") + historicalSummaryStateJSON, err := ParseJSONFile("data/deneb_goerli_slot_7421952.json") if err != nil { fmt.Println("error parsing historicalSummaryState JSON") } @@ -289,7 +289,7 @@ func TestProveBeaconTopLevelRootAgainstBeaconState(t *testing.T) { func TestGetHistoricalSummariesBlockRootsProofProof(t *testing.T) { //curl -H "Accept: application/json" https://data.spiceai.io/goerli/beacon/eth/v2/debug/beacon/states/7431952 -o deneb_goerli_slot_7431952.json --header 'X-API-Key: 343035|8b6ddd9b31f54c07b3fc18282b30f61c' - currentBeaconStateJSON, err := parseJSONFile("data/deneb_goerli_slot_7431952.json") + currentBeaconStateJSON, err := ParseJSONFile("data/deneb_goerli_slot_7431952.json") if err != nil { fmt.Println("error parsing currentBeaconStateJSON") @@ -298,7 +298,7 @@ func TestGetHistoricalSummariesBlockRootsProofProof(t *testing.T) { //this is not the beacon state of the slot containing the old withdrawal we want to prove but rather // its the state that was merkleized to create a historical summary containing the slot that has that withdrawal //, ie, 7421952 mod 8192 = 0 and 7421952 - 7421951 < 8192 - oldBeaconStateJSON, err := parseJSONFile("data/deneb_goerli_slot_7421952.json") + oldBeaconStateJSON, err := ParseJSONFile("data/deneb_goerli_slot_7421952.json") if err != nil { fmt.Println("error parsing oldBeaconStateJSON") } @@ -352,7 +352,7 @@ func TestGetHistoricalSummariesBlockRootsProofProof(t *testing.T) { func TestGetHistoricalSummariesBlockRootsProofProofCapellaAgainstDeneb(t *testing.T) { //curl -H "Accept: application/json" https://data.spiceai.io/goerli/beacon/eth/v2/debug/beacon/states/7431952 -o deneb_goerli_slot_7431952.json --header 'X-API-Key: 343035|8b6ddd9b31f54c07b3fc18282b30f61c' - currentBeaconStateJSON, err := parseJSONFile("data/deneb_goerli_slot_7431952.json") + currentBeaconStateJSON, err := ParseJSONFile("data/deneb_goerli_slot_7431952.json") if err != nil { fmt.Println("error parsing currentBeaconStateJSON") @@ -360,7 +360,7 @@ func TestGetHistoricalSummariesBlockRootsProofProofCapellaAgainstDeneb(t *testin //this is not the beacon state of the slot containing the old withdrawal we want to proof but rather // its the state that was merklized to create a historical summary containing the slot that has that withdrawal, ie, 7421952 mod 8192 = 0 - oldBeaconStateJSON, err := parseJSONFileCapella("data/goerli_slot_6397952.json") + oldBeaconStateJSON, err := ParseJSONFileCapella("data/goerli_slot_6397952.json") if err != nil { fmt.Println("error parsing oldBeaconStateJSON", err) } @@ -544,7 +544,7 @@ func TestStateRootAgainstLatestBlockHeaderProof(t *testing.T) { // this is the state where the latest block header from the oracle was taken. This is the next slot after // the state we want to prove things about (remember latestBlockHeader.state_root = previous slot's state root) - // oracleStateJSON, err := parseJSONFile("data/historical_summary_proof/goerli_slot_6399999.json") + // oracleStateJSON, err := ParseJSONFile("data/historical_summary_proof/goerli_slot_6399999.json") // var oracleState deneb.BeaconState // ParseCapellaBeaconStateFromJSON(*oracleStateJSON, &oracleState) @@ -555,7 +555,7 @@ func TestStateRootAgainstLatestBlockHeaderProof(t *testing.T) { } //the state from the prev slot which contains shit we wanna prove about - stateToProveJSON, err := parseJSONFile("data/deneb_goerli_slot_7413760.json") + stateToProveJSON, err := ParseJSONFile("data/deneb_goerli_slot_7413760.json") if err != nil { fmt.Println("error with parsing JSON state file", err) } @@ -782,7 +782,7 @@ type Proofs struct { WithdrawalFields []string `json:"WithdrawalFields"` } -func parseJSONFile(filePath string) (*beaconStateJSONDeneb, error) { +func ParseJSONFile(filePath string) (*beaconStateJSONDeneb, error) { data, err := os.ReadFile(filePath) if err != nil { @@ -801,7 +801,7 @@ func parseJSONFile(filePath string) (*beaconStateJSONDeneb, error) { return &actualData, nil } -func parseJSONFileCapella(filePath string) (*beaconStateJSONCapella, error) { +func ParseJSONFileCapella(filePath string) (*beaconStateJSONCapella, error) { data, err := os.ReadFile(filePath) if err != nil { diff --git a/onchain_test.go b/onchain_test.go deleted file mode 100644 index 236fb2e4..00000000 --- a/onchain_test.go +++ /dev/null @@ -1,77 +0,0 @@ -package eigenpodproofs_test - -import ( - "context" - "log" - "math/big" - "os" - "testing" - - eigenpodproofs "github.com/Layr-Labs/eigenpod-proofs-generation" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/ethclient" -) - -var ( - chainClient *eigenpodproofs.ChainClient - ctx context.Context - contractAddress common.Address -) - -func TestMain(m *testing.M) { - // Setup - log.Println("Setting up suite") - setupSuite() - - // Run tests - code := m.Run() - - // Teardown - log.Println("Tearing down suite") - teardownSuite() - - // Exit with test result code - os.Exit(code) -} - -func setupSuite() { - RPC := "https://rpc.ankr.com/eth_goerli" - PrivateKey := "c5871389c9221e91d776f355c852f374156bf7799f3f63a361e12d0cb075a479" - - ethClient, err := ethclient.Dial(RPC) - if err != nil { - log.Panicf("failed to connect to the Ethereum client: %s", err) - } - - chainClient, err = eigenpodproofs.NewChainClient(ethClient, PrivateKey) - if err != nil { - log.Panicf("failed to create chain client: %s", err) - } - ctx = context.Background() - contractAddress = common.HexToAddress("0xd42a10709f0cc83855Af9B9fFeAa40dcE56D8fF6") - -} - -func teardownSuite() { - -} - -func TestValidatorContainersProofOnChain(t *testing.T) { - var transaction *types.Transaction - - txData := &types.DynamicFeeTx{ - ChainID: big.NewInt(5), - Nonce: uint64(32), - GasTipCap: big.NewInt(2e9), - GasFeeCap: big.NewInt(100e9), - Gas: uint64(3000000), - To: &contractAddress, // The address of the contract - Value: big.NewInt(0), // Value sent with the transaction (0 for a call) - Data: data, - } - - chainClient.EstimateGasPriceAndLimitAndSendTx(ctx, transacton, "prove validator fields") -} - -func generateValidatorFieldsProofTransaction() diff --git a/onchain_tests/onchain_test.go b/onchain_tests/onchain_test.go new file mode 100644 index 00000000..50a25f2c --- /dev/null +++ b/onchain_tests/onchain_test.go @@ -0,0 +1,157 @@ +package onchain_tests + +import ( + "context" + "fmt" + "log" + "math/big" + "os" + "testing" + + eigenpodproofs "github.com/Layr-Labs/eigenpod-proofs-generation" + beacon "github.com/Layr-Labs/eigenpod-proofs-generation/beacon" + contractBeaconChainProofs "github.com/Layr-Labs/eigenpod-proofs-generation/bindings" + "github.com/attestantio/go-eth2-client/spec/deneb" + "github.com/attestantio/go-eth2-client/spec/phase0" + "github.com/stretchr/testify/assert" + + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/ethclient" +) + +var ( + chainClient *eigenpodproofs.ChainClient + ctx context.Context + contractAddress common.Address + beaconChainProofs *contractBeaconChainProofs.BeaconChainProofs + oracleState deneb.BeaconState + oracleBlockHeader phase0.BeaconBlockHeader + blockHeader phase0.BeaconBlockHeader + blockHeaderIndex uint64 + block deneb.BeaconBlock + validatorIndex phase0.ValidatorIndex + beaconBlockHeaderToVerifyIndex uint64 + executionPayload deneb.ExecutionPayload + epp *eigenpodproofs.EigenPodProofs + executionPayloadFieldRoots []phase0.Root +) + +const GOERLI_CHAIN_ID = uint64(5) +const VALIDATOR_INDEX = uint64(61336) + +func TestMain(m *testing.M) { + // Setup + log.Println("Setting up suite") + setupSuite() + + // Run tests + code := m.Run() + + // Teardown + log.Println("Tearing down suite") + teardownSuite() + + // Exit with test result code + os.Exit(code) +} + +func setupSuite() { + RPC := "https://rpc.ankr.com/eth_goerli" + PrivateKey := "c5871389c9221e91d776f355c852f374156bf7799f3f63a361e12d0cb075a479" + + ethClient, err := ethclient.Dial(RPC) + if err != nil { + log.Panicf("failed to connect to the Ethereum client: %s", err) + } + + chainClient, err = eigenpodproofs.NewChainClient(ethClient, PrivateKey) + if err != nil { + log.Panicf("failed to create chain client: %s", err) + } + ctx = context.Background() + contractAddress = common.HexToAddress("0xd42a10709f0cc83855Af9B9fFeAa40dcE56D8fF6") + beaconChainProofs, err = contractBeaconChainProofs.NewBeaconChainProofs(contractAddress, chainClient) + if err != nil { + log.Panicf("failed to create contract instance: %s", err) + } + + log.Println("Setting up suite") + stateFile := "../data/deneb_goerli_slot_7413760.json" + oracleHeaderFile := "../data/deneb_goerli_block_header_7413760.json" + headerFile := "../data/deneb_goerli_block_header_7426113.json" + bodyFile := "../data/deneb_goerli_block_7426113.json" + + stateJSON, err := eigenpodproofs.ParseJSONFileDeneb(stateFile) + if err != nil { + fmt.Println("error with JSON parsing beacon state") + } + eigenpodproofs.ParseDenebBeaconStateFromJSON(*stateJSON, &oracleState) + + blockHeader, err = eigenpodproofs.ExtractBlockHeader(headerFile) + if err != nil { + fmt.Println("error with block header", err) + } + + oracleBlockHeader, err = eigenpodproofs.ExtractBlockHeader(oracleHeaderFile) + if err != nil { + fmt.Println("error with oracle block header", err) + } + + block, err = eigenpodproofs.ExtractBlock(bodyFile) + if err != nil { + fmt.Println("error with block body", err) + } + + executionPayload = *block.Body.ExecutionPayload + + blockHeaderIndex = uint64(blockHeader.Slot) % beacon.SlotsPerHistoricalRoot + + epp, err = eigenpodproofs.NewEigenPodProofs(GOERLI_CHAIN_ID, 1000) + if err != nil { + fmt.Println("error in NewEigenPodProofs", err) + } + + executionPayloadFieldRoots, _ = beacon.ComputeExecutionPayloadFieldRootsDeneb(block.Body.ExecutionPayload) +} + +func teardownSuite() { + +} + +func TestValidatorContainersProofOnChain(t *testing.T) { + + versionedOracleState, err := beacon.CreateVersionedState(&oracleState) + if err != nil { + fmt.Println("error", err) + return + } + + verifyValidatorFieldsCallParams, err := epp.ProveValidatorContainers(&oracleBlockHeader, &versionedOracleState, []uint64{VALIDATOR_INDEX}) + if err != nil { + fmt.Println("error", err) + } + + validatorFieldsProof := verifyValidatorFieldsCallParams.ValidatorFieldsProofs[0].ToByteSlice() + validatorIndex := new(big.Int).SetUint64(verifyValidatorFieldsCallParams.ValidatorIndices[0]) + versionedOracleStateRoot, err := versionedOracleState.Deneb.HashTreeRoot() + var validatorFields [][32]byte + + for _, field := range verifyValidatorFieldsCallParams.ValidatorFields[0] { + validatorFields = append(validatorFields, field) + } + + err = beaconChainProofs.VerifyValidatorFields( + &bind.CallOpts{}, + versionedOracleStateRoot, + validatorFields, + validatorFieldsProof, + validatorIndex, + ) + if err != nil { + fmt.Println("error", err) + } + assert.Nil(t, err) +} + +// func generateValidatorFieldsProofTransaction() diff --git a/proof_utils.go b/proof_utils.go index 944a4869..d7bd41ff 100644 --- a/proof_utils.go +++ b/proof_utils.go @@ -146,6 +146,25 @@ type InputDataBlock struct { Finalized bool `json:"finalized"` } +func ParseJSONFileDeneb(filePath string) (*beaconStateJSONDeneb, error) { + data, err := os.ReadFile(filePath) + + if err != nil { + fmt.Println("error with reading file") + return nil, err + } + + var beaconState beaconStateVersionDeneb + err = json.Unmarshal(data, &beaconState) + if err != nil { + fmt.Println("error with beaconState JSON unmarshalling") + return nil, err + } + + actualData := beaconState.Data + return &actualData, nil +} + func ConvertBytesToStrings(b [][32]byte) []string { var s []string for _, v := range b {