From 8d75e81ecce9edef0f2388fe07d7a24046cc28bd Mon Sep 17 00:00:00 2001 From: Madhur Shrimal Date: Wed, 22 Jan 2025 13:42:17 -0800 Subject: [PATCH] initial commit --- .github/workflows/tests.yml | 19 + .gitignore | 5 + .gitmodules | 12 + LICENSE | 120 +++ Makefile | 29 + README.md | 7 + aggregator/aggregator.go | 127 +++ aggregator/aggregator_test.go | 90 +++ aggregator/gen.go | 3 + .../mocks/operator_requester.go | 58 ++ .../operator_requester/operator_requester.go | 56 ++ api/proto/buf.gen.yaml | 23 + api/proto/buf.yaml | 1 + api/proto/node.proto | 19 + api/service/v1/node.pb.go | 232 ++++++ api/service/v1/node.pb.gw.go | 154 ++++ api/service/v1/node_grpc.pb.go | 121 +++ api/swagger/grpc.swagger.yaml | 69 ++ common/hash.go | 17 + e2e/e2e_test.go | 154 ++++ e2e/even_loving.go | 31 + example/README.md | 51 ++ example/aggregator/eth_call.go | 254 ++++++ example/contracts/.github/workflows/test.yml | 43 + example/contracts/.gitignore | 14 + example/contracts/README.md | 66 ++ .../MinimalCertificateVerifier/binding.go | 758 ++++++++++++++++++ example/contracts/compile.sh | 31 + example/contracts/foundry.toml | 7 + example/contracts/lib/eigenlayer-middleware | 1 + example/contracts/lib/forge-std | 1 + example/contracts/lib/openzeppelin-contracts | 1 + .../lib/openzeppelin-contracts-upgradeable | 1 + example/contracts/remappings.txt | 6 + example/contracts/script/DeployAVS.s.sol | 257 ++++++ example/contracts/script/input/testnet.json | 7 + .../script/output/avs_deploy_output.json | 14 + .../src/MinimalCertificateVerifier.sol | 66 ++ .../contracts/src/MinimalServiceManager.sol | 29 + example/node/cmd/main.go | 59 ++ example/node/eth_call.go | 71 ++ example/scripts/acquire_and_deposit_steth.sh | 31 + example/scripts/init_operators.sh | 46 ++ example/scripts/initialize-operator.sh | 155 ++++ example/scripts/operator.yaml | 10 + example/scripts/register.go | 180 +++++ example/scripts/register_operator_avs.sh | 58 ++ example/scripts/start_aggregator.sh | 51 ++ example/scripts/start_nodes.sh | 80 ++ example/utils/deployment.go | 70 ++ example/utils/eth_call.go | 44 + example/utils/flags.go | 32 + example/utils/utils.go | 46 ++ go.mod | 115 +++ go.sum | 379 +++++++++ node/server/server.go | 72 ++ node/service/certify.go | 44 + 57 files changed, 4497 insertions(+) create mode 100644 .github/workflows/tests.yml create mode 100644 .gitignore create mode 100644 .gitmodules create mode 100644 LICENSE create mode 100644 Makefile create mode 100644 README.md create mode 100644 aggregator/aggregator.go create mode 100644 aggregator/aggregator_test.go create mode 100644 aggregator/gen.go create mode 100644 aggregator/operator_requester/mocks/operator_requester.go create mode 100644 aggregator/operator_requester/operator_requester.go create mode 100644 api/proto/buf.gen.yaml create mode 100644 api/proto/buf.yaml create mode 100644 api/proto/node.proto create mode 100644 api/service/v1/node.pb.go create mode 100644 api/service/v1/node.pb.gw.go create mode 100644 api/service/v1/node_grpc.pb.go create mode 100644 api/swagger/grpc.swagger.yaml create mode 100644 common/hash.go create mode 100644 e2e/e2e_test.go create mode 100644 e2e/even_loving.go create mode 100644 example/README.md create mode 100644 example/aggregator/eth_call.go create mode 100644 example/contracts/.github/workflows/test.yml create mode 100644 example/contracts/.gitignore create mode 100644 example/contracts/README.md create mode 100644 example/contracts/bindings/MinimalCertificateVerifier/binding.go create mode 100755 example/contracts/compile.sh create mode 100644 example/contracts/foundry.toml create mode 160000 example/contracts/lib/eigenlayer-middleware create mode 160000 example/contracts/lib/forge-std create mode 160000 example/contracts/lib/openzeppelin-contracts create mode 160000 example/contracts/lib/openzeppelin-contracts-upgradeable create mode 100644 example/contracts/remappings.txt create mode 100644 example/contracts/script/DeployAVS.s.sol create mode 100644 example/contracts/script/input/testnet.json create mode 100644 example/contracts/script/output/avs_deploy_output.json create mode 100644 example/contracts/src/MinimalCertificateVerifier.sol create mode 100644 example/contracts/src/MinimalServiceManager.sol create mode 100644 example/node/cmd/main.go create mode 100644 example/node/eth_call.go create mode 100755 example/scripts/acquire_and_deposit_steth.sh create mode 100755 example/scripts/init_operators.sh create mode 100755 example/scripts/initialize-operator.sh create mode 100644 example/scripts/operator.yaml create mode 100644 example/scripts/register.go create mode 100755 example/scripts/register_operator_avs.sh create mode 100755 example/scripts/start_aggregator.sh create mode 100755 example/scripts/start_nodes.sh create mode 100644 example/utils/deployment.go create mode 100644 example/utils/eth_call.go create mode 100644 example/utils/flags.go create mode 100644 example/utils/utils.go create mode 100644 go.mod create mode 100644 go.sum create mode 100644 node/server/server.go create mode 100644 node/service/certify.go diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 0000000..ca622d1 --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,19 @@ +name: tests + +on: + push: + branches: + - master + pull_request: + +jobs: + Test: + name: Unit Test + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-go@v4 + with: + go-version: '1.22' + - name: Unit Test + run: make tests \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..982a5b2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +bin/ + +.env + +**/operators/ \ No newline at end of file diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..3e1bf2c --- /dev/null +++ b/.gitmodules @@ -0,0 +1,12 @@ +[submodule "example/contracts/lib/forge-std"] + path = example/contracts/lib/forge-std + url = https://github.com/foundry-rs/forge-std +[submodule "example/contracts/lib/openzeppelin-contracts"] + path = example/contracts/lib/openzeppelin-contracts + url = https://github.com/OpenZeppelin/openzeppelin-contracts +[submodule "example/contracts/lib/openzeppelin-contracts-upgradeable"] + path = example/contracts/lib/openzeppelin-contracts-upgradeable + url = https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable +[submodule "example/contracts/lib/eigenlayer-middleware"] + path = example/contracts/lib/eigenlayer-middleware + url = https://github.com/Layr-Labs/eigenlayer-middleware diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..3abdd2e --- /dev/null +++ b/LICENSE @@ -0,0 +1,120 @@ +Business Source License 1.1 + +License text copyright (c) 2017 MariaDB Corporation Ab, All Rights Reserved. +"Business Source License" is a trademark of MariaDB Corporation Ab. + +----------------------------------------------------------------------------- + +Parameters + +Licensor: Layr Labs, Inc. + +Licensed Work: Teal + The Licensed Work is (c) 2023 Layr Labs, Inc. + +Additional Use Grant: + +You may additionally use any of the software included in the following repositories +[here](https://docs.google.com/spreadsheets/d/1PlJRow5C0GMqXZlIxRm5CEnkhH-gMV1wIdq1pCfbZco/edit?usp=sharing) +(“Additional Use Grant Software”) for production commercial uses, but only if such +uses are (i) built on or using the EigenLayer Protocol or EigenDA, and (ii) not +Competing Uses. + +“Competing Use” means any use of the Additional Use Grant Software in any product, +protocol, application or service that is made available to third parties and that +(i) substitutes for use of EigenLayer Protocol or EigenDA, (ii) offers the same or +substantially similar functionality as the EigenLayer Protocol or EigenDA or +(iii) is built on or using a protocol with substantially similar functionality as +the EigenLayer Protocol. + +EigenLayer Protocol means the restaking protocol as further described in the +documentation [here](https://docs.eigenlayer.xyz/), as updated from time to time. + +EigenDA means the data availability protocol built on top of the EigenLayer +Protocol as further described in the documentation +[here](https://docs.eigenlayer.xyz/eigenda/overview), as updated from time to time. + +Change Dates: + +- All commits before have a change date of 2029-01-20 (January 20th, 2029) + +Change License: MIT + +----------------------------------------------------------------------------- + +Terms + +The Licensor hereby grants you the right to copy, modify, create derivative +works, redistribute, and make non-production use of the Licensed Work. The +Licensor may make an Additional Use Grant, above, permitting limited +production use. + +Effective on the Change Date, or the fourth anniversary of the first publicly +available distribution of a specific version of the Licensed Work under this +License, whichever comes first, the Licensor hereby grants you rights under +the terms of the Change License, and the rights granted in the paragraph +above terminate. + +If your use of the Licensed Work does not comply with the requirements +currently in effect as described in this License, you must purchase a +commercial license from the Licensor, its affiliated entities, or authorized +resellers, or you must refrain from using the Licensed Work. + +All copies of the original and modified Licensed Work, and derivative works +of the Licensed Work, are subject to this License. This License applies +separately for each version of the Licensed Work and the Change Date may vary +for each version of the Licensed Work released by Licensor. + +You must conspicuously display this License on each original or modified copy +of the Licensed Work. If you receive the Licensed Work in original or +modified form from a third party, the terms and conditions set forth in this +License apply to your use of that work. + +Any use of the Licensed Work in violation of this License will automatically +terminate your rights under this License for the current and all other +versions of the Licensed Work. + +This License does not grant you any right in any trademark or logo of +Licensor or its affiliates (provided that you may use a trademark or logo of +Licensor as expressly required by this License). + +TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON +AN "AS IS" BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, +EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND +TITLE. + +MariaDB hereby grants you permission to use this License’s text to license +your works, and to refer to it using the trademark "Business Source License", +as long as you comply with the Covenants of Licensor below. + +----------------------------------------------------------------------------- + +Covenants of Licensor + +In consideration of the right to use this License’s text and the "Business +Source License" name and trademark, Licensor covenants to MariaDB, and to all +other recipients of the licensed work to be provided by Licensor: + +1. To specify as the Change License the GPL Version 2.0 or any later version, + or a license that is compatible with GPL Version 2.0 or a later version, + where "compatible" means that software provided under the Change License can + be included in a program with software provided under GPL Version 2.0 or a + later version. Licensor may specify additional Change Licenses without + limitation. + +2. To either: (a) specify an additional grant of rights to use that does not + impose any additional restriction on the right granted in this License, as + the Additional Use Grant; or (b) insert the text "None". + +3. To specify a Change Date. + +4. Not to modify this License in any other way. + +----------------------------------------------------------------------------- + +Notice + +The Business Source License (this document, or the "License") is not an Open +Source license. However, the Licensed Work will eventually be made available +under an Open Source License, as stated in this License. \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..a8e9cfb --- /dev/null +++ b/Makefile @@ -0,0 +1,29 @@ +.PHONY: install +install-macos-linux: + @echo "Installing dependencies" + brew install bufbuild/buf/buf + go install github.com/fullstorydev/grpcurl/cmd/grpcurl@latest + go install github.com/golang/protobuf/protoc-gen-go@latest + go install github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-grpc-gateway@latest + go install github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2@latest + @echo "Done" + +.PHONY: generate +generate: + @echo "Generating go bindings" + cd api/proto && buf generate + @echo "Done" + +.PHONY: build-node +build-node: + @echo "Building node" + go build -o bin/node node/cmd/main.go + @echo "Done" + +.PHONY: fmt +fmt: ## formats all go files + go fmt ./... + +.PHONY: test +tests: + go test ./... diff --git a/README.md b/README.md new file mode 100644 index 0000000..257a8fc --- /dev/null +++ b/README.md @@ -0,0 +1,7 @@ +# teal + +## Install Dependencies + +``` +make install-macos-linux +``` \ No newline at end of file diff --git a/aggregator/aggregator.go b/aggregator/aggregator.go new file mode 100644 index 0000000..2d846ec --- /dev/null +++ b/aggregator/aggregator.go @@ -0,0 +1,127 @@ +package aggregator + +import ( + "context" + "fmt" + "math/big" + "sync" + "time" + + "github.com/Layr-Labs/eigensdk-go/crypto/bls" + "github.com/Layr-Labs/eigensdk-go/logging" + "github.com/Layr-Labs/eigensdk-go/services/avsregistry" + blsagg "github.com/Layr-Labs/eigensdk-go/services/bls_aggregation" + "github.com/Layr-Labs/eigensdk-go/types" + operatorrequester "github.com/Layr-Labs/teal/aggregator/operator_requester" +) + +type AggregatorService struct { + logger logging.Logger + avsRegistryReader avsregistry.AvsRegistryService + blsAggService blsagg.BlsAggregationService + operatorRequester operatorrequester.OperatorRequester + + mu sync.Mutex +} + +func NewAggregatorService( + logger logging.Logger, + avsRegistryReader avsregistry.AvsRegistryService, + blsAggService blsagg.BlsAggregationService, + operatorRequester operatorrequester.OperatorRequester, +) *AggregatorService { + return &AggregatorService{ + logger: logger, + avsRegistryReader: avsRegistryReader, + blsAggService: blsAggService, + operatorRequester: operatorRequester, + } +} + +// GetCertificate sends a task to all registered nodes and aggregates their responses +// Only works for single quorum for simplicity +func (s *AggregatorService) GetCertificate( + ctx context.Context, + taskIndex types.TaskIndex, + taskCreatedBlock uint32, + quorumNumber types.QuorumNum, + quorumThresholdPercentage types.QuorumThresholdPercentage, + data []byte, + timeToExpiry time.Duration, +) (*blsagg.BlsAggregationServiceResponse, error) { + // Only allow one task at a time + s.mu.Lock() + defer s.mu.Unlock() + + quorumNumbers := types.QuorumNums{quorumNumber} + quorumThresholdPercentages := types.QuorumThresholdPercentages{quorumThresholdPercentage} + + // Initialize task in BLS aggregation service + err := s.blsAggService.InitializeNewTaskWithWindow( + taskIndex, + taskCreatedBlock, + quorumNumbers, + quorumThresholdPercentages, + timeToExpiry, + 1*time.Second, + ) + if err != nil { + return nil, fmt.Errorf("failed to initialize task: %w", err) + } + + // Get operators from registry + operators, err := s.avsRegistryReader.GetOperatorsAvsStateAtBlock(ctx, quorumNumbers, taskCreatedBlock) + if err != nil { + return nil, fmt.Errorf("failed to get operators: %w", err) + } + + // Send task to all operators in parallel + for operatorId, operator := range operators { + go func(operatorId types.OperatorId, operator types.OperatorAvsState) { + s.logger.Info("Requesting certification from operator", "operatorId", operatorId, "socket", operator.OperatorInfo.Socket) + // Create connection for this operator + resp, err := s.operatorRequester.RequestCertification(ctx, operator, taskIndex, data) + if err != nil { + return + } + + signature := &bls.Signature{G1Point: bls.NewG1Point(big.NewInt(0), big.NewInt(0))} + _, err = signature.SetBytes(resp.Signature) + if err != nil { + s.logger.Error("Failed to unmarshal signature", + "operatorId", operatorId, + "error", err) + return + } + + s.logger.Info("Received signature from operator", "operatorId", operatorId) + + // Process signature from node + err = s.blsAggService.ProcessNewSignature( + ctx, + taskIndex, + types.TaskResponse(resp.Data), + signature, + operatorId, + ) + if err != nil { + s.logger.Error("Failed to process signature", + "operatorId", operatorId, + "error", err) + return + } + s.logger.Info("Processed signature from operator", "operatorId", operatorId) + }(operatorId, operator) + } + + // Wait for aggregated response + select { + case resp := <-s.blsAggService.GetResponseChannel(): + if resp.Err != nil { + return nil, fmt.Errorf("aggregation failed: %w", resp.Err) + } + return &resp, nil + case <-ctx.Done(): + return nil, ctx.Err() + } +} diff --git a/aggregator/aggregator_test.go b/aggregator/aggregator_test.go new file mode 100644 index 0000000..4a61958 --- /dev/null +++ b/aggregator/aggregator_test.go @@ -0,0 +1,90 @@ +package aggregator_test + +import ( + "context" + "math/big" + "testing" + "time" + + "github.com/Layr-Labs/eigensdk-go/crypto/bls" + "github.com/Layr-Labs/eigensdk-go/services/avsregistry" + blsagg "github.com/Layr-Labs/eigensdk-go/services/bls_aggregation" + "github.com/Layr-Labs/eigensdk-go/testutils" + "github.com/Layr-Labs/eigensdk-go/types" + "github.com/Layr-Labs/teal/aggregator" + mockOperatorRequester "github.com/Layr-Labs/teal/aggregator/operator_requester/mocks" + pb "github.com/Layr-Labs/teal/api/service/v1" + "github.com/Layr-Labs/teal/common" + "github.com/stretchr/testify/assert" + "go.uber.org/mock/gomock" +) + +func TestAggregatorService(t *testing.T) { + ctrl := gomock.NewController(t) + + fakeOperatorRequester := mockOperatorRequester.NewMockOperatorRequester(ctrl) + + t.Run("successful certification with single operator", func(t *testing.T) { + ctx := context.Background() + + testOperator1 := types.TestOperator{ + OperatorId: types.OperatorId{1}, + StakePerQuorum: map[types.QuorumNum]types.StakeAmount{ + 0: big.NewInt(100), + }, + BlsKeypair: newBlsKeyPairPanics("0x1"), + } + blockNum := uint32(1) + taskIndex := types.TaskIndex(0) + quorumNumber := types.QuorumNum(0) + quorumThresholdPercentage := types.QuorumThresholdPercentage(100) + requestData := []byte("test 1") + + logger := testutils.GetTestLogger() + fakeAvsRegistryService := avsregistry.NewFakeAvsRegistryService(blockNum, []types.TestOperator{testOperator1}) + operators, _ := fakeAvsRegistryService.GetOperatorsAvsStateAtBlock(ctx, types.QuorumNums{quorumNumber}, blockNum) + + for _, operator := range operators { + responseData := []byte("test 1") + taskResponseDigest, _ := common.Keccak256HashFn(responseData) + fakeOperatorRequester.EXPECT().RequestCertification(ctx, operator, taskIndex, requestData).Return(&pb.CertifyResponse{ + Signature: testOperator1.BlsKeypair.SignMessage(taskResponseDigest).Marshal(), + Data: responseData, + }, nil) + } + + blsAggService := blsagg.NewBlsAggregatorService(fakeAvsRegistryService, common.Keccak256HashFn, logger) + + // Create aggregator service + aggregatorService := aggregator.NewAggregatorService( + logger, + fakeAvsRegistryService, + blsAggService, + fakeOperatorRequester, + ) + + resp, err := aggregatorService.GetCertificate( + ctx, + taskIndex, + blockNum, + quorumNumber, + quorumThresholdPercentage, + requestData, + 1*time.Second, + ) + + // Verify results + assert.NoError(t, err) + assert.NotNil(t, resp) + assert.Equal(t, taskIndex, resp.TaskIndex) + }) + +} + +func newBlsKeyPairPanics(hexKey string) *bls.KeyPair { + keypair, err := bls.NewKeyPairFromString(hexKey) + if err != nil { + panic(err) + } + return keypair +} diff --git a/aggregator/gen.go b/aggregator/gen.go new file mode 100644 index 0000000..ef86145 --- /dev/null +++ b/aggregator/gen.go @@ -0,0 +1,3 @@ +package aggregator + +//go:generate mockgen -destination=./operator_requester/mocks/operator_requester.go -package=mocks github.com/Layr-Labs/teal/aggregator/operator_requester OperatorRequester diff --git a/aggregator/operator_requester/mocks/operator_requester.go b/aggregator/operator_requester/mocks/operator_requester.go new file mode 100644 index 0000000..e38bbe6 --- /dev/null +++ b/aggregator/operator_requester/mocks/operator_requester.go @@ -0,0 +1,58 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/Layr-Labs/teal/aggregator/operator_requester (interfaces: OperatorRequester) +// +// Generated by this command: +// +// mockgen -destination=./operator_requester/mocks/operator_requester.go -package=mocks github.com/Layr-Labs/teal/aggregator/operator_requester OperatorRequester +// + +// Package mocks is a generated GoMock package. +package mocks + +import ( + context "context" + reflect "reflect" + + types "github.com/Layr-Labs/eigensdk-go/types" + v1 "github.com/Layr-Labs/teal/api/service/v1" + gomock "go.uber.org/mock/gomock" +) + +// MockOperatorRequester is a mock of OperatorRequester interface. +type MockOperatorRequester struct { + ctrl *gomock.Controller + recorder *MockOperatorRequesterMockRecorder + isgomock struct{} +} + +// MockOperatorRequesterMockRecorder is the mock recorder for MockOperatorRequester. +type MockOperatorRequesterMockRecorder struct { + mock *MockOperatorRequester +} + +// NewMockOperatorRequester creates a new mock instance. +func NewMockOperatorRequester(ctrl *gomock.Controller) *MockOperatorRequester { + mock := &MockOperatorRequester{ctrl: ctrl} + mock.recorder = &MockOperatorRequesterMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockOperatorRequester) EXPECT() *MockOperatorRequesterMockRecorder { + return m.recorder +} + +// RequestCertification mocks base method. +func (m *MockOperatorRequester) RequestCertification(ctx context.Context, operator types.OperatorAvsState, taskIndex uint32, requestData []byte) (*v1.CertifyResponse, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "RequestCertification", ctx, operator, taskIndex, requestData) + ret0, _ := ret[0].(*v1.CertifyResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// RequestCertification indicates an expected call of RequestCertification. +func (mr *MockOperatorRequesterMockRecorder) RequestCertification(ctx, operator, taskIndex, requestData any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RequestCertification", reflect.TypeOf((*MockOperatorRequester)(nil).RequestCertification), ctx, operator, taskIndex, requestData) +} diff --git a/aggregator/operator_requester/operator_requester.go b/aggregator/operator_requester/operator_requester.go new file mode 100644 index 0000000..a96e3db --- /dev/null +++ b/aggregator/operator_requester/operator_requester.go @@ -0,0 +1,56 @@ +package operatorrequester + +import ( + "context" + + "github.com/Layr-Labs/eigensdk-go/logging" + "github.com/Layr-Labs/eigensdk-go/types" + pb "github.com/Layr-Labs/teal/api/service/v1" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials/insecure" +) + +type OperatorRequester interface { + RequestCertification(ctx context.Context, operator types.OperatorAvsState, taskIndex types.TaskIndex, requestData []byte) (*pb.CertifyResponse, error) +} + +type operatorRequester struct { + logger logging.Logger +} + +func NewOperatorRequester(logger logging.Logger) OperatorRequester { + return &operatorRequester{ + logger: logger, + } +} + +func (or *operatorRequester) RequestCertification(ctx context.Context, operator types.OperatorAvsState, taskIndex types.TaskIndex, requestData []byte) (*pb.CertifyResponse, error) { + conn, err := grpc.NewClient( + operator.OperatorInfo.Socket.String(), + grpc.WithTransportCredentials(insecure.NewCredentials()), + ) + if err != nil { + or.logger.Error("Failed to connect to operator", + "operatorId", operator.OperatorId, + "socket", operator.OperatorInfo.Socket, + "error", err) + return nil, err + } + defer conn.Close() + + client := pb.NewNodeServiceClient(conn) + + // Send task to node + resp, err := client.Certify(ctx, &pb.CertifyRequest{ + TaskIndex: uint32(taskIndex), + Data: requestData, + }) + if err != nil { + or.logger.Error("Failed to send task to node", + "operatorId", operator.OperatorId, + "error", err) + return nil, err + } + + return resp, nil +} diff --git a/api/proto/buf.gen.yaml b/api/proto/buf.gen.yaml new file mode 100644 index 0000000..3996b2c --- /dev/null +++ b/api/proto/buf.gen.yaml @@ -0,0 +1,23 @@ +version: v1 +plugins: + - plugin: go + out: ../service/v1/ + opt: + - paths=source_relative + - plugin: go-grpc + out: ../service/v1/ + opt: + - paths=source_relative + - plugin: grpc-gateway + out: ../service/v1 + opt: + - paths=source_relative + - generate_unbound_methods=true + - plugin: openapiv2 + out: ../swagger/ + strategy: all + opt: + - allow_merge=true + - generate_unbound_methods=true + - merge_file_name=grpc + - output_format=yaml diff --git a/api/proto/buf.yaml b/api/proto/buf.yaml new file mode 100644 index 0000000..5830b70 --- /dev/null +++ b/api/proto/buf.yaml @@ -0,0 +1 @@ +version: v1 \ No newline at end of file diff --git a/api/proto/node.proto b/api/proto/node.proto new file mode 100644 index 0000000..c247e5f --- /dev/null +++ b/api/proto/node.proto @@ -0,0 +1,19 @@ +syntax = "proto3"; + +package node.v1; + +option go_package = "github.com/layr-labs/teal/api/node/v1"; + +service NodeService { + rpc Certify(CertifyRequest) returns (CertifyResponse) {} +} + +message CertifyRequest { + uint32 task_index = 1; + bytes data = 2; +} + +message CertifyResponse { + bytes signature = 1; + bytes data = 2; +} diff --git a/api/service/v1/node.pb.go b/api/service/v1/node.pb.go new file mode 100644 index 0000000..a0d9927 --- /dev/null +++ b/api/service/v1/node.pb.go @@ -0,0 +1,232 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.33.0 +// protoc (unknown) +// source: node.proto + +package v1 + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type CertifyRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + TaskIndex uint32 `protobuf:"varint,1,opt,name=task_index,json=taskIndex,proto3" json:"task_index,omitempty"` + Data []byte `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"` +} + +func (x *CertifyRequest) Reset() { + *x = CertifyRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_node_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CertifyRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CertifyRequest) ProtoMessage() {} + +func (x *CertifyRequest) ProtoReflect() protoreflect.Message { + mi := &file_node_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CertifyRequest.ProtoReflect.Descriptor instead. +func (*CertifyRequest) Descriptor() ([]byte, []int) { + return file_node_proto_rawDescGZIP(), []int{0} +} + +func (x *CertifyRequest) GetTaskIndex() uint32 { + if x != nil { + return x.TaskIndex + } + return 0 +} + +func (x *CertifyRequest) GetData() []byte { + if x != nil { + return x.Data + } + return nil +} + +type CertifyResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Signature []byte `protobuf:"bytes,1,opt,name=signature,proto3" json:"signature,omitempty"` + Data []byte `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"` +} + +func (x *CertifyResponse) Reset() { + *x = CertifyResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_node_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CertifyResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CertifyResponse) ProtoMessage() {} + +func (x *CertifyResponse) ProtoReflect() protoreflect.Message { + mi := &file_node_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CertifyResponse.ProtoReflect.Descriptor instead. +func (*CertifyResponse) Descriptor() ([]byte, []int) { + return file_node_proto_rawDescGZIP(), []int{1} +} + +func (x *CertifyResponse) GetSignature() []byte { + if x != nil { + return x.Signature + } + return nil +} + +func (x *CertifyResponse) GetData() []byte { + if x != nil { + return x.Data + } + return nil +} + +var File_node_proto protoreflect.FileDescriptor + +var file_node_proto_rawDesc = []byte{ + 0x0a, 0x0a, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x07, 0x6e, 0x6f, + 0x64, 0x65, 0x2e, 0x76, 0x31, 0x22, 0x43, 0x0a, 0x0e, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x79, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x74, 0x61, 0x73, 0x6b, 0x5f, + 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, 0x74, 0x61, 0x73, + 0x6b, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x22, 0x43, 0x0a, 0x0f, 0x43, 0x65, + 0x72, 0x74, 0x69, 0x66, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1c, 0x0a, + 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, + 0x52, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x64, + 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x32, + 0x4d, 0x0a, 0x0b, 0x4e, 0x6f, 0x64, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x3e, + 0x0a, 0x07, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x79, 0x12, 0x17, 0x2e, 0x6e, 0x6f, 0x64, 0x65, + 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x65, 0x72, + 0x74, 0x69, 0x66, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x27, + 0x5a, 0x25, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6c, 0x61, 0x79, + 0x72, 0x2d, 0x6c, 0x61, 0x62, 0x73, 0x2f, 0x74, 0x65, 0x61, 0x6c, 0x2f, 0x61, 0x70, 0x69, 0x2f, + 0x6e, 0x6f, 0x64, 0x65, 0x2f, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_node_proto_rawDescOnce sync.Once + file_node_proto_rawDescData = file_node_proto_rawDesc +) + +func file_node_proto_rawDescGZIP() []byte { + file_node_proto_rawDescOnce.Do(func() { + file_node_proto_rawDescData = protoimpl.X.CompressGZIP(file_node_proto_rawDescData) + }) + return file_node_proto_rawDescData +} + +var file_node_proto_msgTypes = make([]protoimpl.MessageInfo, 2) +var file_node_proto_goTypes = []interface{}{ + (*CertifyRequest)(nil), // 0: node.v1.CertifyRequest + (*CertifyResponse)(nil), // 1: node.v1.CertifyResponse +} +var file_node_proto_depIdxs = []int32{ + 0, // 0: node.v1.NodeService.Certify:input_type -> node.v1.CertifyRequest + 1, // 1: node.v1.NodeService.Certify:output_type -> node.v1.CertifyResponse + 1, // [1:2] is the sub-list for method output_type + 0, // [0:1] is the sub-list for method input_type + 0, // [0:0] is the sub-list for extension type_name + 0, // [0:0] is the sub-list for extension extendee + 0, // [0:0] is the sub-list for field type_name +} + +func init() { file_node_proto_init() } +func file_node_proto_init() { + if File_node_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_node_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CertifyRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_node_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CertifyResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_node_proto_rawDesc, + NumEnums: 0, + NumMessages: 2, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_node_proto_goTypes, + DependencyIndexes: file_node_proto_depIdxs, + MessageInfos: file_node_proto_msgTypes, + }.Build() + File_node_proto = out.File + file_node_proto_rawDesc = nil + file_node_proto_goTypes = nil + file_node_proto_depIdxs = nil +} diff --git a/api/service/v1/node.pb.gw.go b/api/service/v1/node.pb.gw.go new file mode 100644 index 0000000..abda1ad --- /dev/null +++ b/api/service/v1/node.pb.gw.go @@ -0,0 +1,154 @@ +// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT. +// source: node.proto + +/* +Package v1 is a reverse proxy. + +It translates gRPC into RESTful JSON APIs. +*/ +package v1 + +import ( + "context" + "errors" + "io" + "net/http" + + "github.com/grpc-ecosystem/grpc-gateway/v2/runtime" + "github.com/grpc-ecosystem/grpc-gateway/v2/utilities" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/grpclog" + "google.golang.org/grpc/metadata" + "google.golang.org/grpc/status" + "google.golang.org/protobuf/proto" +) + +// Suppress "imported and not used" errors +var ( + _ codes.Code + _ io.Reader + _ status.Status + _ = errors.New + _ = runtime.String + _ = utilities.NewDoubleArray + _ = metadata.Join +) + +func request_NodeService_Certify_0(ctx context.Context, marshaler runtime.Marshaler, client NodeServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var ( + protoReq CertifyRequest + metadata runtime.ServerMetadata + ) + if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && !errors.Is(err, io.EOF) { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + msg, err := client.Certify(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err +} + +func local_request_NodeService_Certify_0(ctx context.Context, marshaler runtime.Marshaler, server NodeServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var ( + protoReq CertifyRequest + metadata runtime.ServerMetadata + ) + if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && !errors.Is(err, io.EOF) { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + msg, err := server.Certify(ctx, &protoReq) + return msg, metadata, err +} + +// RegisterNodeServiceHandlerServer registers the http handlers for service NodeService to "mux". +// UnaryRPC :call NodeServiceServer directly. +// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. +// Note that using this registration option will cause many gRPC library features to stop working. Consider using RegisterNodeServiceHandlerFromEndpoint instead. +// GRPC interceptors will not work for this type of registration. To use interceptors, you must use the "runtime.WithMiddlewares" option in the "runtime.NewServeMux" call. +func RegisterNodeServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux, server NodeServiceServer) error { + mux.Handle(http.MethodPost, pattern_NodeService_Certify_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + annotatedContext, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/node.v1.NodeService/Certify", runtime.WithHTTPPathPattern("/node.v1.NodeService/Certify")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_NodeService_Certify_0(annotatedContext, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + forward_NodeService_Certify_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + }) + + return nil +} + +// RegisterNodeServiceHandlerFromEndpoint is same as RegisterNodeServiceHandler but +// automatically dials to "endpoint" and closes the connection when "ctx" gets done. +func RegisterNodeServiceHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) { + conn, err := grpc.NewClient(endpoint, opts...) + if err != nil { + return err + } + defer func() { + if err != nil { + if cerr := conn.Close(); cerr != nil { + grpclog.Errorf("Failed to close conn to %s: %v", endpoint, cerr) + } + return + } + go func() { + <-ctx.Done() + if cerr := conn.Close(); cerr != nil { + grpclog.Errorf("Failed to close conn to %s: %v", endpoint, cerr) + } + }() + }() + return RegisterNodeServiceHandler(ctx, mux, conn) +} + +// RegisterNodeServiceHandler registers the http handlers for service NodeService to "mux". +// The handlers forward requests to the grpc endpoint over "conn". +func RegisterNodeServiceHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error { + return RegisterNodeServiceHandlerClient(ctx, mux, NewNodeServiceClient(conn)) +} + +// RegisterNodeServiceHandlerClient registers the http handlers for service NodeService +// to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "NodeServiceClient". +// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "NodeServiceClient" +// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in +// "NodeServiceClient" to call the correct interceptors. This client ignores the HTTP middlewares. +func RegisterNodeServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux, client NodeServiceClient) error { + mux.Handle(http.MethodPost, pattern_NodeService_Certify_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + annotatedContext, err := runtime.AnnotateContext(ctx, mux, req, "/node.v1.NodeService/Certify", runtime.WithHTTPPathPattern("/node.v1.NodeService/Certify")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_NodeService_Certify_0(annotatedContext, inboundMarshaler, client, req, pathParams) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + forward_NodeService_Certify_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + }) + return nil +} + +var ( + pattern_NodeService_Certify_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"node.v1.NodeService", "Certify"}, "")) +) + +var ( + forward_NodeService_Certify_0 = runtime.ForwardResponseMessage +) diff --git a/api/service/v1/node_grpc.pb.go b/api/service/v1/node_grpc.pb.go new file mode 100644 index 0000000..c266f82 --- /dev/null +++ b/api/service/v1/node_grpc.pb.go @@ -0,0 +1,121 @@ +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.5.1 +// - protoc (unknown) +// source: node.proto + +package v1 + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.64.0 or later. +const _ = grpc.SupportPackageIsVersion9 + +const ( + NodeService_Certify_FullMethodName = "/node.v1.NodeService/Certify" +) + +// NodeServiceClient is the client API for NodeService service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +type NodeServiceClient interface { + Certify(ctx context.Context, in *CertifyRequest, opts ...grpc.CallOption) (*CertifyResponse, error) +} + +type nodeServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewNodeServiceClient(cc grpc.ClientConnInterface) NodeServiceClient { + return &nodeServiceClient{cc} +} + +func (c *nodeServiceClient) Certify(ctx context.Context, in *CertifyRequest, opts ...grpc.CallOption) (*CertifyResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(CertifyResponse) + err := c.cc.Invoke(ctx, NodeService_Certify_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +// NodeServiceServer is the server API for NodeService service. +// All implementations must embed UnimplementedNodeServiceServer +// for forward compatibility. +type NodeServiceServer interface { + Certify(context.Context, *CertifyRequest) (*CertifyResponse, error) + mustEmbedUnimplementedNodeServiceServer() +} + +// UnimplementedNodeServiceServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedNodeServiceServer struct{} + +func (UnimplementedNodeServiceServer) Certify(context.Context, *CertifyRequest) (*CertifyResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Certify not implemented") +} +func (UnimplementedNodeServiceServer) mustEmbedUnimplementedNodeServiceServer() {} +func (UnimplementedNodeServiceServer) testEmbeddedByValue() {} + +// UnsafeNodeServiceServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to NodeServiceServer will +// result in compilation errors. +type UnsafeNodeServiceServer interface { + mustEmbedUnimplementedNodeServiceServer() +} + +func RegisterNodeServiceServer(s grpc.ServiceRegistrar, srv NodeServiceServer) { + // If the following call pancis, it indicates UnimplementedNodeServiceServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } + s.RegisterService(&NodeService_ServiceDesc, srv) +} + +func _NodeService_Certify_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(CertifyRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(NodeServiceServer).Certify(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: NodeService_Certify_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(NodeServiceServer).Certify(ctx, req.(*CertifyRequest)) + } + return interceptor(ctx, in, info, handler) +} + +// NodeService_ServiceDesc is the grpc.ServiceDesc for NodeService service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var NodeService_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "node.v1.NodeService", + HandlerType: (*NodeServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "Certify", + Handler: _NodeService_Certify_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "node.proto", +} diff --git a/api/swagger/grpc.swagger.yaml b/api/swagger/grpc.swagger.yaml new file mode 100644 index 0000000..61592e7 --- /dev/null +++ b/api/swagger/grpc.swagger.yaml @@ -0,0 +1,69 @@ +swagger: "2.0" +info: + title: node.proto + version: version not set +tags: + - name: NodeService +consumes: + - application/json +produces: + - application/json +paths: + /node.v1.NodeService/Certify: + post: + operationId: NodeService_Certify + responses: + "200": + description: A successful response. + schema: + $ref: '#/definitions/v1CertifyResponse' + default: + description: An unexpected error response. + schema: + $ref: '#/definitions/rpcStatus' + parameters: + - name: body + in: body + required: true + schema: + $ref: '#/definitions/v1CertifyRequest' + tags: + - NodeService +definitions: + protobufAny: + type: object + properties: + '@type': + type: string + additionalProperties: {} + rpcStatus: + type: object + properties: + code: + type: integer + format: int32 + message: + type: string + details: + type: array + items: + type: object + $ref: '#/definitions/protobufAny' + v1CertifyRequest: + type: object + properties: + taskIndex: + type: integer + format: int64 + data: + type: string + format: byte + v1CertifyResponse: + type: object + properties: + signature: + type: string + format: byte + data: + type: string + format: byte diff --git a/common/hash.go b/common/hash.go new file mode 100644 index 0000000..f1a6366 --- /dev/null +++ b/common/hash.go @@ -0,0 +1,17 @@ +package common + +import ( + "fmt" + + "github.com/Layr-Labs/eigensdk-go/types" + "github.com/ethereum/go-ethereum/crypto" +) + +func Keccak256HashFn(response types.TaskResponse) (types.TaskResponseDigest, error) { + responseBytes, ok := response.([]byte) + if !ok { + return types.TaskResponseDigest{}, fmt.Errorf("response is not a byte array") + } + + return [32]byte(crypto.Keccak256(responseBytes)), nil +} diff --git a/e2e/e2e_test.go b/e2e/e2e_test.go new file mode 100644 index 0000000..f24a966 --- /dev/null +++ b/e2e/e2e_test.go @@ -0,0 +1,154 @@ +package e2e_test + +import ( + "context" + "log/slog" + "math/big" + "os" + "testing" + "time" + + "github.com/Layr-Labs/eigensdk-go/chainio/clients" + "github.com/Layr-Labs/eigensdk-go/crypto/bls" + "github.com/Layr-Labs/eigensdk-go/logging" + "github.com/Layr-Labs/eigensdk-go/services/avsregistry" + blsagg "github.com/Layr-Labs/eigensdk-go/services/bls_aggregation" + "github.com/Layr-Labs/eigensdk-go/services/operatorsinfo" + "github.com/Layr-Labs/eigensdk-go/testutils" + "github.com/Layr-Labs/eigensdk-go/types" + "github.com/Layr-Labs/teal/aggregator" + operatorrequester "github.com/Layr-Labs/teal/aggregator/operator_requester" + "github.com/Layr-Labs/teal/common" + "github.com/Layr-Labs/teal/node/server" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/ethclient" + "github.com/stretchr/testify/require" + + e2e "github.com/Layr-Labs/teal/e2e" +) + +var ( + ANVIL_FIRST_PRIVATE_KEY = "ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80" +) + +func TestIntegrationBlsAgg(t *testing.T) { + + tasksTimeToExpiry := 10 * time.Second + + anvilStateFileName := "contracts-deployed-anvil-state.json" + anvilC, err := testutils.StartAnvilContainer(anvilStateFileName) + require.NoError(t, err) + anvilHttpEndpoint, err := anvilC.Endpoint(context.Background(), "http") + require.NoError(t, err) + anvilWsEndpoint, err := anvilC.Endpoint(context.Background(), "ws") + require.NoError(t, err) + contractAddrs := testutils.GetContractAddressesFromContractRegistry(anvilHttpEndpoint) + t.Run("1 quorums 1 operator", func(t *testing.T) { + // read input from JSON if available, otherwise use default values + var defaultInput = struct { + QuorumNumbers types.QuorumNums `json:"quorum_numbers"` + QuorumThresholdPercentages types.QuorumThresholdPercentages `json:"quorum_threshold_percentages"` + BlsPrivKey string `json:"bls_key"` + }{ + QuorumNumbers: types.QuorumNums{0}, + QuorumThresholdPercentages: types.QuorumThresholdPercentages{100}, + BlsPrivKey: "0x1", + } + testData := testutils.NewTestData(defaultInput) + + // define operator ecdsa and bls private keys + ecdsaPrivKey, err := crypto.HexToECDSA(ANVIL_FIRST_PRIVATE_KEY) + require.NoError(t, err) + blsPrivKeyHex := testData.Input.BlsPrivKey + blsKeyPair := newBlsKeyPairPanics(blsPrivKeyHex) + // operatorId := types.OperatorIdFromG1Pubkey(blsKeyPair.GetPubKeyG1()) + + // create avs clients to interact with contracts deployed on anvil + ethHttpClient, err := ethclient.Dial(anvilHttpEndpoint) + require.NoError(t, err) + logger := logging.NewTextSLogger(os.Stdout, &logging.SLoggerOptions{Level: slog.LevelDebug}) + avsClients, err := clients.BuildAll(clients.BuildAllConfig{ + EthHttpUrl: anvilHttpEndpoint, + EthWsUrl: anvilWsEndpoint, // not used so doesn't matter that we pass an http url + RegistryCoordinatorAddr: contractAddrs.RegistryCoordinator.String(), + OperatorStateRetrieverAddr: contractAddrs.OperatorStateRetriever.String(), + AvsName: "avs", + PromMetricsIpPortAddress: "localhost:9090", + }, ecdsaPrivKey, logger) + require.NoError(t, err) + avsWriter := avsClients.AvsRegistryChainWriter + // avsServiceManager, err := avssm.NewContractMockAvsServiceManager(contractAddrs.ServiceManager, ethHttpClient) + require.NoError(t, err) + + // create aggregation service + operatorsInfoService := operatorsinfo.NewOperatorsInfoServiceInMemory( + context.TODO(), + avsClients.AvsRegistryChainSubscriber, + avsClients.AvsRegistryChainReader, + nil, + operatorsinfo.Opts{}, + logger, + ) + avsRegistryService := avsregistry.NewAvsRegistryServiceChainCaller( + avsClients.AvsRegistryChainReader, + operatorsInfoService, + logger, + ) + blsAggService := blsagg.NewBlsAggregatorService(avsRegistryService, common.Keccak256HashFn, logger) + + // register operator + quorumNumbers := testData.Input.QuorumNumbers + _, err = avsWriter.RegisterOperator( + context.Background(), + ecdsaPrivKey, + blsKeyPair, + quorumNumbers, + "localhost:8080", + true, + ) + require.NoError(t, err) + + evenLovingNode := e2e.NewEvenLovingNode(server.Config{ + ServicePort: 8080, + BlsKeyPair: blsKeyPair, + }) + go evenLovingNode.Start() + + // create the task related parameters: RBN, quorumThresholdPercentages, taskIndex and taskResponse + curBlockNum, err := ethHttpClient.BlockNumber(context.Background()) + require.NoError(t, err) + referenceBlockNumber := uint32(curBlockNum) + // need to advance chain by 1 block because of the check in signatureChecker where RBN must be < current block + // number + testutils.AdvanceChainByNBlocksExecInContainer(context.TODO(), 1, anvilC) + taskIndex := types.TaskIndex(0) + // taskResponse := mockTaskResponse{123} // Initialize with appropriate data + quorumThresholdPercentages := testData.Input.QuorumThresholdPercentages + + aggregator := aggregator.NewAggregatorService( + logger, + avsRegistryService, + blsAggService, + operatorrequester.NewOperatorRequester(logger), + ) + + _, err = aggregator.GetCertificate( + context.Background(), + taskIndex, + referenceBlockNumber, + quorumNumbers[0], + quorumThresholdPercentages[0], + big.NewInt(69420).Bytes(), + tasksTimeToExpiry, + ) + require.NoError(t, err) + }) +} + +func newBlsKeyPairPanics(hexKey string) *bls.KeyPair { + keypair, err := bls.NewKeyPairFromString(hexKey) + if err != nil { + panic(err) + } + return keypair +} diff --git a/e2e/even_loving.go b/e2e/even_loving.go new file mode 100644 index 0000000..16e5beb --- /dev/null +++ b/e2e/even_loving.go @@ -0,0 +1,31 @@ +package e2e + +import ( + "errors" + "math/big" + + "github.com/Layr-Labs/teal/node/server" +) + +type EvenLovingNode struct { + *server.BaseNode +} + +func NewEvenLovingNode(config server.Config) *EvenLovingNode { + node := &EvenLovingNode{} + node.BaseNode = server.NewBaseNode(config, node) + return node +} + +func (n *EvenLovingNode) GetResponse(config server.Config, data []byte) ([]byte, error) { + // convert data to bigInt + dataInt := new(big.Int).SetBytes(data) + + // Can use both config and data for validation + if dataInt.Mod(dataInt, big.NewInt(2)).Cmp(big.NewInt(0)) == 0 { + return data, nil + } + + // Custom validation logic using config parameters + return []byte{}, errors.New("invalid data") +} diff --git a/example/README.md b/example/README.md new file mode 100644 index 0000000..ddecc84 --- /dev/null +++ b/example/README.md @@ -0,0 +1,51 @@ +# Teal Example + +This example will take you end to end through deploying a minimal AVS that uses BLS aggregation to verify operator signatures on a SIMPLE TASK. + +## Step 0: Setup Environment + +``` +export ETH_RPC_URL= +export PRIVATE_KEY= +``` + +# Step 1: Deploy the AVS + +For demo purposes, we'll deploy an AVS to EigenLayer's Holesky testnet with a single quorum that just pays attention to the StETH strategy. + +``` +cd example/contracts +forge script --rpc-url $ETH_RPC_URL --private-key $PRIVATE_KEY script/DeployAVS.s.sol --broadcast --sig "run(string,uint256,address[])" -- ./script/input/testnet.json 200 "[0x7d704507b76571a51d9cae8addabbfd0ba0e63d3]" +``` +See that `example/contracts/script/output/avs_deploy_output.json` has been created. + +Only change the strategies if you know what you're doing. + +# Step 2: Setup Operators + +First, let's create an operator and give it some stETH. +``` +cd example/scripts +./init_operators.sh --num-operators 3 --rpc-url $ETH_RPC_URL --funds-pk $PRIVATE_KEY +``` +This will mint and deposit 0.1 ether of stETH into EigenLayer on behalf of the operator. + +Now, let's register the operator with EigenLayer and the AVS. + +``` +./register_operator_avs.sh --rpc-url $ETH_RPC_URL +``` + +This will register your operator with the AVS and EigenLayer. + +# Step 3: Run the Operator and Aggregator + +Run the operator first. +``` +./start-nodes.sh --rpc-url $ETH_RPC_URL +``` + +In a seperate terminal, run the aggregator. +``` +./start_aggregator.sh --rpc-url $HOLESKY_WSS_URL --private-key $PRIVATE_KEY +``` \ No newline at end of file diff --git a/example/aggregator/eth_call.go b/example/aggregator/eth_call.go new file mode 100644 index 0000000..3dc1bd2 --- /dev/null +++ b/example/aggregator/eth_call.go @@ -0,0 +1,254 @@ +package main + +import ( + "context" + "log" + "log/slog" + "math/big" + "os" + "time" + + "github.com/Layr-Labs/eigensdk-go/chainio/clients/avsregistry" + "github.com/Layr-Labs/eigensdk-go/chainio/clients/eth" + "github.com/Layr-Labs/eigensdk-go/chainio/clients/wallet" + "github.com/Layr-Labs/eigensdk-go/chainio/txmgr" + "github.com/Layr-Labs/eigensdk-go/logging" + rpccalls "github.com/Layr-Labs/eigensdk-go/metrics/collectors/rpc_calls" + avsservice "github.com/Layr-Labs/eigensdk-go/services/avsregistry" + blsagg "github.com/Layr-Labs/eigensdk-go/services/bls_aggregation" + "github.com/Layr-Labs/eigensdk-go/signerv2" + "github.com/Layr-Labs/eigensdk-go/types" + minimalCertificateVerifier "github.com/Layr-Labs/teal/example/contracts/bindings/MinimalCertificateVerifier" + "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + gethcommon "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" + + "github.com/Layr-Labs/eigensdk-go/services/operatorsinfo" + "github.com/Layr-Labs/teal/aggregator" + operatorrequester "github.com/Layr-Labs/teal/aggregator/operator_requester" + "github.com/Layr-Labs/teal/common" + "github.com/Layr-Labs/teal/example/utils" + "github.com/prometheus/client_golang/prometheus" + "github.com/urfave/cli/v2" +) + +var ( + strategyAddress = gethcommon.HexToAddress("0x7d704507b76571a51d9cae8addabbfd0ba0e63d3") +) + +func main() { + app := cli.NewApp() + app.Name = "aggregator" + app.Usage = "abc" + app.Version = "0.0.1" + + app.Flags = []cli.Flag{ + &utils.EthUrlFlag, + &utils.AvsDeploymentPathFlag, + &utils.EcdsaPrivateKeyFlag, + } + + app.Action = start + + if err := app.Run(os.Args); err != nil { + log.Fatal(err) + } +} + +func start(c *cli.Context) error { + ctx := context.Background() + + reg := prometheus.NewRegistry() + rpcCallsCollector := rpccalls.NewCollector("exampleAvs", reg) + client, err := eth.NewInstrumentedClient(c.String(utils.EthUrlFlag.Name), rpcCallsCollector) + if err != nil { + panic(err) + } + + logger := logging.NewTextSLogger(os.Stdout, &logging.SLoggerOptions{Level: slog.LevelInfo}) + + chainid, err := client.ChainID(ctx) + if err != nil { + panic(err) + } + + privateKeyString := c.String(utils.EcdsaPrivateKeyFlag.Name) + if privateKeyString[0:2] == "0x" { + privateKeyString = privateKeyString[2:] + } + + ecdsaPrivateKey, err := crypto.HexToECDSA(privateKeyString) + if err != nil { + panic(err) + } + + signerV2, addr, err := signerv2.SignerFromConfig(signerv2.Config{PrivateKey: ecdsaPrivateKey}, chainid) + if err != nil { + panic(err) + } + + pkWallet, err := wallet.NewPrivateKeyWallet(client, signerV2, addr, logger) + if err != nil { + panic(err) + } + + txManager := txmgr.NewSimpleTxManager( + pkWallet, + client, + logger, + addr, + ) + + avsDeployment, err := utils.ReadAVSDeployment(c.String(utils.AvsDeploymentPathFlag.Name)) + if err != nil { + panic(err) + } + + avsReader, err := avsregistry.NewReaderFromConfig( + avsDeployment.ToConfig(), + client, + logger, + ) + if err != nil { + panic(err) + } + + avsSubscriber, err := avsregistry.NewSubscriberFromConfig( + avsDeployment.ToConfig(), + client, + logger, + ) + if err != nil { + panic(err) + } + + operatorInfoService := operatorsinfo.NewOperatorsInfoServiceInMemory( + ctx, + avsSubscriber, + avsReader, + nil, + operatorsinfo.Opts{ + StartBlock: big.NewInt(int64(avsDeployment.DeploymentBlock)), + }, + logger, + ) + + avsRegistryService := avsservice.NewAvsRegistryServiceChainCaller( + avsReader, + operatorInfoService, + logger, + ) + + blsAggService := blsagg.NewBlsAggregatorService( + avsRegistryService, + common.Keccak256HashFn, + logger, + ) + + aggregator := aggregator.NewAggregatorService( + logger, + avsRegistryService, + blsAggService, + operatorrequester.NewOperatorRequester(logger), + ) + + certVerifier, err := minimalCertificateVerifier.NewContractMinimalCertificateVerifier( + avsDeployment.CertificateVerifier, + client, + ) + if err != nil { + panic(err) + } + + threshold, err := certVerifier.THRESHOLD(&bind.CallOpts{}) + if err != nil { + panic(err) + } + + denominator, err := certVerifier.DENOMINATOR(&bind.CallOpts{}) + if err != nil { + panic(err) + } + quorumThreshold := types.QuorumThresholdPercentage(uint8(new(big.Int).Div(new(big.Int).Mul(threshold, big.NewInt(100)), denominator).Uint64()) + 1) + + quorumNumber := types.QuorumNum(0) + requestNumber := uint32(0) + + // on a ticker every 30s, get the certificate + for { + func() { + defer time.Sleep(5 * time.Second) + requestNumber++ + + currentBlockNumber, err := client.BlockNumber(ctx) + if err != nil { + logger.Error("Failed to get current block number", "error", err) + return + } + referenceBlockNumber := uint32(currentBlockNumber - 5) + + callBlockNumber := currentBlockNumber - 150 + callMsg := ethereum.CallMsg{ + From: gethcommon.HexToAddress("0x4242424242424242424242424242424242424242"), + To: &strategyAddress, + Gas: 1000000, + GasPrice: big.NewInt(10000), + Value: big.NewInt(0), + // totalShares() + Data: []byte{0x3a, 0x98, 0xef, 0x39}, + } + request := utils.CallToBytes(uint64(callBlockNumber), callMsg) + + logger.Info("Requesting certificate of totalShares()", "callBlockNumber", callBlockNumber) + + resp, err := aggregator.GetCertificate( + ctx, + types.TaskIndex(requestNumber), + uint32(referenceBlockNumber), + quorumNumber, + quorumThreshold, + request, + 10*time.Second, + ) + if err != nil { + logger.Error("Failed to get certificate", "error", err) + return + } + + txOpts, err := txManager.GetNoSendTxOpts() + if err != nil { + logger.Error("Failed to get tx opts", "error", err) + return + } + tx, err := certVerifier.VerifyCertificate( + txOpts, + resp.TaskResponse.([]byte), + []byte{byte(quorumNumber)}, + uint32(referenceBlockNumber), + minimalCertificateVerifier.IBLSSignatureCheckerNonSignerStakesAndSignature{ + NonSignerQuorumBitmapIndices: resp.NonSignerQuorumBitmapIndices, + NonSignerPubkeys: utils.ToBN254G1Points(resp.NonSignersPubkeysG1), + QuorumApks: utils.ToBN254G1Points(resp.QuorumApksG1), + ApkG2: utils.ToBN254G2Point(resp.SignersApkG2), + Sigma: utils.ToBN254G1Point(resp.SignersAggSigG1.G1Point), + QuorumApkIndices: resp.QuorumApkIndices, + TotalStakeIndices: resp.TotalStakeIndices, + NonSignerStakeIndices: resp.NonSignerStakeIndices, + }, + ) + if err != nil { + logger.Error("Failed to assemble verify certificate tx", "error", err) + return + } + + _, err = txManager.Send(ctx, tx, true) + if err != nil { + logger.Error("Failed to send verify certificate tx", "tx", tx.Hash().Hex(), "error", err) + return + } + + logger.Info("Sent verify certificate tx", "tx", tx.Hash().Hex(), "requestNumber", requestNumber) + }() + } +} diff --git a/example/contracts/.github/workflows/test.yml b/example/contracts/.github/workflows/test.yml new file mode 100644 index 0000000..34a4a52 --- /dev/null +++ b/example/contracts/.github/workflows/test.yml @@ -0,0 +1,43 @@ +name: CI + +on: + push: + pull_request: + workflow_dispatch: + +env: + FOUNDRY_PROFILE: ci + +jobs: + check: + strategy: + fail-fast: true + + name: Foundry project + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + submodules: recursive + + - name: Install Foundry + uses: foundry-rs/foundry-toolchain@v1 + + - name: Show Forge version + run: | + forge --version + + - name: Run Forge fmt + run: | + forge fmt --check + id: fmt + + - name: Run Forge build + run: | + forge build --sizes + id: build + + - name: Run Forge tests + run: | + forge test -vvv + id: test diff --git a/example/contracts/.gitignore b/example/contracts/.gitignore new file mode 100644 index 0000000..c524b01 --- /dev/null +++ b/example/contracts/.gitignore @@ -0,0 +1,14 @@ +# Compiler files +cache/ +out/ + +# Ignores development broadcast logs +/broadcast +/broadcast/*/31337/ +/broadcast/**/dry-run/ + +# Docs +docs/ + +# Dotenv file +.env diff --git a/example/contracts/README.md b/example/contracts/README.md new file mode 100644 index 0000000..9265b45 --- /dev/null +++ b/example/contracts/README.md @@ -0,0 +1,66 @@ +## Foundry + +**Foundry is a blazing fast, portable and modular toolkit for Ethereum application development written in Rust.** + +Foundry consists of: + +- **Forge**: Ethereum testing framework (like Truffle, Hardhat and DappTools). +- **Cast**: Swiss army knife for interacting with EVM smart contracts, sending transactions and getting chain data. +- **Anvil**: Local Ethereum node, akin to Ganache, Hardhat Network. +- **Chisel**: Fast, utilitarian, and verbose solidity REPL. + +## Documentation + +https://book.getfoundry.sh/ + +## Usage + +### Build + +```shell +$ forge build +``` + +### Test + +```shell +$ forge test +``` + +### Format + +```shell +$ forge fmt +``` + +### Gas Snapshots + +```shell +$ forge snapshot +``` + +### Anvil + +```shell +$ anvil +``` + +### Deploy + +```shell +$ forge script script/Counter.s.sol:CounterScript --rpc-url --private-key +``` + +### Cast + +```shell +$ cast +``` + +### Help + +```shell +$ forge --help +$ anvil --help +$ cast --help +``` diff --git a/example/contracts/bindings/MinimalCertificateVerifier/binding.go b/example/contracts/bindings/MinimalCertificateVerifier/binding.go new file mode 100644 index 0000000..19570dc --- /dev/null +++ b/example/contracts/bindings/MinimalCertificateVerifier/binding.go @@ -0,0 +1,758 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package contractMinimalCertificateVerifier + +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 +) + +// BN254G1Point is an auto generated low-level Go binding around an user-defined struct. +type BN254G1Point struct { + X *big.Int + Y *big.Int +} + +// BN254G2Point is an auto generated low-level Go binding around an user-defined struct. +type BN254G2Point struct { + X [2]*big.Int + Y [2]*big.Int +} + +// IBLSSignatureCheckerNonSignerStakesAndSignature is an auto generated low-level Go binding around an user-defined struct. +type IBLSSignatureCheckerNonSignerStakesAndSignature struct { + NonSignerQuorumBitmapIndices []uint32 + NonSignerPubkeys []BN254G1Point + QuorumApks []BN254G1Point + ApkG2 BN254G2Point + Sigma BN254G1Point + QuorumApkIndices []uint32 + TotalStakeIndices []uint32 + NonSignerStakeIndices [][]uint32 +} + +// IBLSSignatureCheckerQuorumStakeTotals is an auto generated low-level Go binding around an user-defined struct. +type IBLSSignatureCheckerQuorumStakeTotals struct { + SignedStakeForQuorum []*big.Int + TotalStakeForQuorum []*big.Int +} + +// ContractMinimalCertificateVerifierMetaData contains all meta data concerning the ContractMinimalCertificateVerifier contract. +var ContractMinimalCertificateVerifierMetaData = &bind.MetaData{ + ABI: "[{\"type\":\"constructor\",\"inputs\":[{\"name\":\"__registryCoordinator\",\"type\":\"address\",\"internalType\":\"contractIRegistryCoordinator\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"DENOMINATOR\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"THRESHOLD\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"blsApkRegistry\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIBLSApkRegistry\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"checkSignatures\",\"inputs\":[{\"name\":\"msgHash\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"quorumNumbers\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"referenceBlockNumber\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"params\",\"type\":\"tuple\",\"internalType\":\"structIBLSSignatureChecker.NonSignerStakesAndSignature\",\"components\":[{\"name\":\"nonSignerQuorumBitmapIndices\",\"type\":\"uint32[]\",\"internalType\":\"uint32[]\"},{\"name\":\"nonSignerPubkeys\",\"type\":\"tuple[]\",\"internalType\":\"structBN254.G1Point[]\",\"components\":[{\"name\":\"X\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"Y\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]},{\"name\":\"quorumApks\",\"type\":\"tuple[]\",\"internalType\":\"structBN254.G1Point[]\",\"components\":[{\"name\":\"X\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"Y\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]},{\"name\":\"apkG2\",\"type\":\"tuple\",\"internalType\":\"structBN254.G2Point\",\"components\":[{\"name\":\"X\",\"type\":\"uint256[2]\",\"internalType\":\"uint256[2]\"},{\"name\":\"Y\",\"type\":\"uint256[2]\",\"internalType\":\"uint256[2]\"}]},{\"name\":\"sigma\",\"type\":\"tuple\",\"internalType\":\"structBN254.G1Point\",\"components\":[{\"name\":\"X\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"Y\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]},{\"name\":\"quorumApkIndices\",\"type\":\"uint32[]\",\"internalType\":\"uint32[]\"},{\"name\":\"totalStakeIndices\",\"type\":\"uint32[]\",\"internalType\":\"uint32[]\"},{\"name\":\"nonSignerStakeIndices\",\"type\":\"uint32[][]\",\"internalType\":\"uint32[][]\"}]}],\"outputs\":[{\"name\":\"\",\"type\":\"tuple\",\"internalType\":\"structIBLSSignatureChecker.QuorumStakeTotals\",\"components\":[{\"name\":\"signedStakeForQuorum\",\"type\":\"uint96[]\",\"internalType\":\"uint96[]\"},{\"name\":\"totalStakeForQuorum\",\"type\":\"uint96[]\",\"internalType\":\"uint96[]\"}]},{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"delegation\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIDelegationManager\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"registryCoordinator\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIRegistryCoordinator\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"setStaleStakesForbidden\",\"inputs\":[{\"name\":\"value\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"stakeRegistry\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIStakeRegistry\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"staleStakesForbidden\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"trySignatureAndApkVerification\",\"inputs\":[{\"name\":\"msgHash\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"apk\",\"type\":\"tuple\",\"internalType\":\"structBN254.G1Point\",\"components\":[{\"name\":\"X\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"Y\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]},{\"name\":\"apkG2\",\"type\":\"tuple\",\"internalType\":\"structBN254.G2Point\",\"components\":[{\"name\":\"X\",\"type\":\"uint256[2]\",\"internalType\":\"uint256[2]\"},{\"name\":\"Y\",\"type\":\"uint256[2]\",\"internalType\":\"uint256[2]\"}]},{\"name\":\"sigma\",\"type\":\"tuple\",\"internalType\":\"structBN254.G1Point\",\"components\":[{\"name\":\"X\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"Y\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]}],\"outputs\":[{\"name\":\"pairingSuccessful\",\"type\":\"bool\",\"internalType\":\"bool\"},{\"name\":\"siganatureIsValid\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"verificationRecords\",\"inputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[{\"name\":\"quorumNumbers\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"referenceBlockNumber\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"signatoryRecordHash\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"quorumStakeTotals\",\"type\":\"tuple\",\"internalType\":\"structIBLSSignatureChecker.QuorumStakeTotals\",\"components\":[{\"name\":\"signedStakeForQuorum\",\"type\":\"uint96[]\",\"internalType\":\"uint96[]\"},{\"name\":\"totalStakeForQuorum\",\"type\":\"uint96[]\",\"internalType\":\"uint96[]\"}]}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"verifyCertificate\",\"inputs\":[{\"name\":\"response\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"quorumNumbers\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"referenceBlockNumber\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"params\",\"type\":\"tuple\",\"internalType\":\"structIBLSSignatureChecker.NonSignerStakesAndSignature\",\"components\":[{\"name\":\"nonSignerQuorumBitmapIndices\",\"type\":\"uint32[]\",\"internalType\":\"uint32[]\"},{\"name\":\"nonSignerPubkeys\",\"type\":\"tuple[]\",\"internalType\":\"structBN254.G1Point[]\",\"components\":[{\"name\":\"X\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"Y\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]},{\"name\":\"quorumApks\",\"type\":\"tuple[]\",\"internalType\":\"structBN254.G1Point[]\",\"components\":[{\"name\":\"X\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"Y\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]},{\"name\":\"apkG2\",\"type\":\"tuple\",\"internalType\":\"structBN254.G2Point\",\"components\":[{\"name\":\"X\",\"type\":\"uint256[2]\",\"internalType\":\"uint256[2]\"},{\"name\":\"Y\",\"type\":\"uint256[2]\",\"internalType\":\"uint256[2]\"}]},{\"name\":\"sigma\",\"type\":\"tuple\",\"internalType\":\"structBN254.G1Point\",\"components\":[{\"name\":\"X\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"Y\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]},{\"name\":\"quorumApkIndices\",\"type\":\"uint32[]\",\"internalType\":\"uint32[]\"},{\"name\":\"totalStakeIndices\",\"type\":\"uint32[]\",\"internalType\":\"uint32[]\"},{\"name\":\"nonSignerStakeIndices\",\"type\":\"uint32[][]\",\"internalType\":\"uint32[][]\"}]}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"event\",\"name\":\"StaleStakesForbiddenUpdate\",\"inputs\":[{\"name\":\"value\",\"type\":\"bool\",\"indexed\":false,\"internalType\":\"bool\"}],\"anonymous\":false}]", + Bin: "0x610100604052348015610010575f5ffd5b5060405161305b38038061305b83398101604081905261002f916101c9565b80806001600160a01b03166080816001600160a01b031681525050806001600160a01b031663683048356040518163ffffffff1660e01b8152600401602060405180830381865afa158015610086573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906100aa91906101c9565b6001600160a01b031660a0816001600160a01b031681525050806001600160a01b0316635df459466040518163ffffffff1660e01b8152600401602060405180830381865afa1580156100ff573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061012391906101c9565b6001600160a01b031660c0816001600160a01b03168152505060a0516001600160a01b031663df5cf7236040518163ffffffff1660e01b8152600401602060405180830381865afa15801561017a573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061019e91906101c9565b6001600160a01b031660e052506101eb9050565b6001600160a01b03811681146101c6575f5ffd5b50565b5f602082840312156101d9575f5ffd5b81516101e4816101b2565b9392505050565b60805160a05160c05160e051612e066102555f395f81816102230152610bd001525f818160fe0152610dac01525f818161013d01528181610f7f015261113401525f8181610164015281816103c9015281816108b101528181610a420152610c6a0152612e065ff3fe608060405234801561000f575f5ffd5b50600436106100b1575f3560e01c8063785ffb371161006e578063785ffb37146101a757806381d18a0d146101bd57806381d9d23d146101d0578063918f8674146101f3578063b98d090814610202578063df5cf7231461021e575f5ffd5b8063171f1d5b146100b5578063416c7e5e146100e45780635df45946146100f957806368304835146101385780636d14a9871461015f5780636efb463614610186575b5f5ffd5b6100c86100c336600461248b565b610245565b6040805192151583529015156020830152015b60405180910390f35b6100f76100f23660046124d9565b6103c7565b005b6101207f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020016100db565b6101207f000000000000000000000000000000000000000000000000000000000000000081565b6101207f000000000000000000000000000000000000000000000000000000000000000081565b610199610194366004612803565b610504565b6040516100db9291906128fe565b6101af6113ce565b6040519081526020016100db565b6100f76101cb36600461291f565b6113e4565b6101e36101de3660046129cc565b61163b565b6040516100db94939291906129e3565b6101af670de0b6b3a764000081565b5f5461020e9060ff1681565b60405190151581526020016100db565b6101207f000000000000000000000000000000000000000000000000000000000000000081565b5f5f5f7f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000187875f01518860200151885f01515f6002811061028857610288612a43565b60200201518951600160200201518a602001515f600281106102ac576102ac612a43565b60200201518b602001516001600281106102c8576102c8612a43565b602090810291909101518c518d8301516040516103259a99989796959401988952602089019790975260408801959095526060870193909352608086019190915260a085015260c084015260e08301526101008201526101200190565b604051602081830303815290604052805190602001205f1c6103479190612a6b565b90506103b961036061035988846117ff565b869061188e565b610368611921565b6103af6103a08561039a6040805180820182525f80825260209182015281518083019092526001825260029082015290565b906117ff565b6103a98c6119e1565b9061188e565b886201d4c0611a6b565b909890975095505050505050565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610423573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906104479190612a7e565b6001600160a01b0316336001600160a01b0316146104f85760405162461bcd60e51b815260206004820152605c60248201527f424c535369676e6174757265436865636b65722e6f6e6c79436f6f7264696e6160448201527f746f724f776e65723a2063616c6c6572206973206e6f7420746865206f776e6560648201527f72206f6620746865207265676973747279436f6f7264696e61746f7200000000608482015260a4015b60405180910390fd5b61050181611c7f565b50565b60408051808201909152606080825260208201525f84810361057b5760405162461bcd60e51b815260206004820152603760248201525f516020612db15f395f51905f5260448201527f7265733a20656d7074792071756f72756d20696e70757400000000000000000060648201526084016104ef565b60408301515185148015610593575060a08301515185145b80156105a3575060c08301515185145b80156105b3575060e08301515185145b61061c5760405162461bcd60e51b815260206004820152604160248201525f516020612db15f395f51905f5260448201527f7265733a20696e7075742071756f72756d206c656e677468206d69736d6174636064820152600d60fb1b608482015260a4016104ef565b825151602084015151146106935760405162461bcd60e51b8152602060048201526044602482018190525f516020612db15f395f51905f52908201527f7265733a20696e707574206e6f6e7369676e6572206c656e677468206d69736d6064820152630c2e8c6d60e31b608482015260a4016104ef565b4363ffffffff168463ffffffff16106107015760405162461bcd60e51b815260206004820152603c60248201525f516020612db15f395f51905f5260448201527f7265733a20696e76616c6964207265666572656e636520626c6f636b0000000060648201526084016104ef565b6040805180820182525f808252602080830191909152825180840190935260608084529083015290866001600160401b0381111561074157610741612342565b60405190808252806020026020018201604052801561076a578160200160208202803683370190505b506020820152866001600160401b0381111561078857610788612342565b6040519080825280602002602001820160405280156107b1578160200160208202803683370190505b50815260408051808201909152606080825260208201528560200151516001600160401b038111156107e5576107e5612342565b60405190808252806020026020018201604052801561080e578160200160208202803683370190505b5081526020860151516001600160401b0381111561082e5761082e612342565b604051908082528060200260200182016040528015610857578160200160208202803683370190505b5081602001819052505f6109258a8a8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152505060408051639aa1653d60e01b815290516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169350639aa1653d925060048083019260209291908290030181865afa1580156108fc573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906109209190612aa4565b611cc5565b90505f5b876020015151811015610bac5761096d8860200151828151811061094f5761094f612a43565b602002602001015180515f9081526020918201519091526040902090565b8360200151828151811061098357610983612a43565b60209081029190910101528015610a405760208301516109a4600183612ad8565b815181106109b4576109b4612a43565b60200260200101515f1c836020015182815181106109d4576109d4612a43565b60200260200101515f1c11610a40576040805162461bcd60e51b81526020600482015260248101919091525f516020612db15f395f51905f5260448201527f7265733a206e6f6e5369676e65725075626b657973206e6f7420736f7274656460648201526084016104ef565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166304ec635184602001518381518110610a8557610a85612a43565b60200260200101518b8b5f01518581518110610aa357610aa3612a43565b60200260200101516040518463ffffffff1660e01b8152600401610ae09392919092835263ffffffff918216602084015216604082015260600190565b602060405180830381865afa158015610afb573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610b1f9190612aeb565b6001600160c01b0316835f01518281518110610b3d57610b3d612a43565b602002602001018181525050610ba2610359610b7684865f01518581518110610b6857610b68612a43565b602002602001015116611d57565b8a602001518481518110610b8c57610b8c612a43565b6020026020010151611d8190919063ffffffff16565b9450600101610929565b5050610bb783611e62565b5f805491945060ff9091169081610bce575f610c4e565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663c448feb86040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c2a573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610c4e9190612b11565b90505f5b8a8110156112a1578215610daa578963ffffffff16827f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663249a0c428f8f86818110610ca957610ca9612a43565b60405160e085901b6001600160e01b031916815292013560f81c600483015250602401602060405180830381865afa158015610ce7573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610d0b9190612b11565b610d159190612b28565b11610daa5760405162461bcd60e51b815260206004820152606660248201525f516020612db15f395f51905f5260448201527f7265733a205374616b6552656769737472792075706461746573206d7573742060648201527f62652077697468696e207769746864726177616c44656c6179426c6f636b732060848201526577696e646f7760d01b60a482015260c4016104ef565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166368bccaac8d8d84818110610deb57610deb612a43565b9050013560f81c60f81b60f81c8c8c60a001518581518110610e0f57610e0f612a43565b60209081029190910101516040516001600160e01b031960e086901b16815260ff909316600484015263ffffffff9182166024840152166044820152606401602060405180830381865afa158015610e69573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610e8d9190612b3b565b6001600160401b031916610eb08a60400151838151811061094f5761094f612a43565b67ffffffffffffffff191614610f4b5760405162461bcd60e51b815260206004820152606160248201525f516020612db15f395f51905f5260448201527f7265733a2071756f72756d41706b206861736820696e2073746f72616765206460648201527f6f6573206e6f74206d617463682070726f76696465642071756f72756d2061706084820152606b60f81b60a482015260c4016104ef565b610f7b89604001518281518110610f6457610f64612a43565b60200260200101518761188e90919063ffffffff16565b95507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663c8294c568d8d84818110610fbe57610fbe612a43565b9050013560f81c60f81b60f81c8c8c60c001518581518110610fe257610fe2612a43565b60209081029190910101516040516001600160e01b031960e086901b16815260ff909316600484015263ffffffff9182166024840152166044820152606401602060405180830381865afa15801561103c573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906110609190612b63565b8560200151828151811061107657611076612a43565b6001600160601b039092166020928302919091018201528501518051829081106110a2576110a2612a43565b6020026020010151855f015182815181106110bf576110bf612a43565b6001600160601b03909216602092830291909101909101525f805b8a60200151518110156112975761112d865f015182815181106110ff576110ff612a43565b60200260200101518f8f8681811061111957611119612a43565b600192013560f81c9290921c811614919050565b1561128f577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663f2be94ae8f8f8681811061117357611173612a43565b9050013560f81c60f81b60f81c8e8960200151858151811061119757611197612a43565b60200260200101518f60e0015188815181106111b5576111b5612a43565b602002602001015187815181106111ce576111ce612a43565b60209081029190910101516040516001600160e01b031960e087901b16815260ff909416600485015263ffffffff92831660248501526044840191909152166064820152608401602060405180830381865afa158015611230573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906112549190612b63565b875180518590811061126857611268612a43565b6020026020010181815161127c9190612b89565b6001600160601b03169052506001909101905b6001016110da565b5050600101610c52565b5050505f5f6112ba8c868a606001518b60800151610245565b915091508161132a5760405162461bcd60e51b815260206004820152604360248201525f516020612db15f395f51905f5260448201527f7265733a2070616972696e6720707265636f6d70696c652063616c6c206661696064820152621b195960ea1b608482015260a4016104ef565b8061138a5760405162461bcd60e51b815260206004820152603960248201525f516020612db15f395f51905f5260448201527f7265733a207369676e617475726520697320696e76616c69640000000000000060648201526084016104ef565b50505f8782602001516040516020016113a4929190612ba8565b60408051808303601f190181529190528051602090910120929b929a509198505050505050505050565b6113e16002670de0b6b3a7640000612bee565b81565b5f86866040516113f5929190612c01565b60408051918290039091205f8181526032602052919091206001015490915063ffffffff16156114675760405162461bcd60e51b815260206004820152601c60248201527f436572746966696361746520616c72656164792076657269666965640000000060448201526064016104ef565b5f806114798388888861019489612c10565b90925090505f5b8251518110156115505761149d6002670de0b6b3a7640000612bee565b836020015182815181106114b3576114b3612a43565b60200260200101516001600160601b03166114ce9190612c1b565b670de0b6b3a7640000845f015183815181106114ec576114ec612a43565b60200260200101516001600160601b03166115079190612c1b565b116115485760405162461bcd60e51b8152602060048201526011602482015270151a1c995cda1bdb19081b9bdd081b595d607a1b60448201526064016104ef565b600101611480565b50604051806080016040528088888080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92018290525093855250505063ffffffff8816602080840191909152604080840186905260609093018690528682526032905220815181906115c99082612cb6565b5060208281015160018301805463ffffffff191663ffffffff9092169190911790556040830151600283015560608301518051805191926003850192611612928492019061219f565b50602082810151805161162b926001850192019061219f565b5050505050505050505050505050565b60326020525f908152604090208054819061165590612c32565b80601f016020809104026020016040519081016040528092919081815260200182805461168190612c32565b80156116cc5780601f106116a3576101008083540402835291602001916116cc565b820191905f5260205f20905b8154815290600101906020018083116116af57829003601f168201915b505050506001830154600284015460408051600387018054606060208202840181018552938301818152979863ffffffff90961697949650919390928492849184018282801561176a57602002820191905f5260205f20905f905b82829054906101000a90046001600160601b03166001600160601b0316815260200190600c0190602082600b010492830192600103820291508084116117275790505b50505050508152602001600182018054806020026020016040519081016040528092919081815260200182805480156117f157602002820191905f5260205f20905f905b82829054906101000a90046001600160601b03166001600160601b0316815260200190600c0190602082600b010492830192600103820291508084116117ae5790505b505050505081525050905084565b604080518082019091525f808252602082015261181a612254565b835181526020808501519082015260408082018490525f908360608460076107d05a03fa9050808061184857fe5b50806118865760405162461bcd60e51b815260206004820152600d60248201526c1958cb5b5d5b0b59985a5b1959609a1b60448201526064016104ef565b505092915050565b604080518082019091525f80825260208201526118a9612272565b835181526020808501518183015283516040808401919091529084015160608301525f908360808460066107d05a03fa905080806118e357fe5b50806118865760405162461bcd60e51b815260206004820152600d60248201526c1958cb5859190b59985a5b1959609a1b60448201526064016104ef565b611929612290565b50604080516080810182527f198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c28183019081527f1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed6060830152815281518083019092527f275dc4a288d1afb3cbb1ac09187524c7db36395df7be3b99e673b13a075a65ec82527f1d9befcd05a5323e6da4d435f3b617cdb3af83285c2df711ef39c01571827f9d60208381019190915281019190915290565b604080518082019091525f80825260208201525f8080611a0e5f516020612d915f395f51905f5286612a6b565b90505b611a1a81611ef8565b90935091505f516020612d915f395f51905f528283098303611a52576040805180820190915290815260208101919091529392505050565b5f516020612d915f395f51905f52600182089050611a11565b6040805180820182528681526020808201869052825180840190935286835282018490525f91829190611a9c6122b5565b5f5b6002811015611c53575f611ab3826006612c1b565b9050848260028110611ac757611ac7612a43565b60200201515183611ad8835f612b28565b600c8110611ae857611ae8612a43565b6020020152848260028110611aff57611aff612a43565b60200201516020015183826001611b169190612b28565b600c8110611b2657611b26612a43565b6020020152838260028110611b3d57611b3d612a43565b6020020151515183611b50836002612b28565b600c8110611b6057611b60612a43565b6020020152838260028110611b7757611b77612a43565b6020020151516001602002015183611b90836003612b28565b600c8110611ba057611ba0612a43565b6020020152838260028110611bb757611bb7612a43565b6020020151602001515f60028110611bd157611bd1612a43565b602002015183611be2836004612b28565b600c8110611bf257611bf2612a43565b6020020152838260028110611c0957611c09612a43565b602002015160200151600160028110611c2457611c24612a43565b602002015183611c35836005612b28565b600c8110611c4557611c45612a43565b602002015250600101611a9e565b50611c5c6122d4565b5f6020826101808560088cfa9151919c9115159b50909950505050505050505050565b5f805460ff19168215159081179091556040519081527f40e4ed880a29e0f6ddce307457fb75cddf4feef7d3ecb0301bfdf4976a0e2dfc9060200160405180910390a150565b5f5f611cd084611f74565b9050808360ff166001901b11611d4e5760405162461bcd60e51b815260206004820152603f60248201527f4269746d61705574696c732e6f72646572656442797465734172726179546f4260448201527f69746d61703a206269746d61702065786365656473206d61782076616c75650060648201526084016104ef565b90505b92915050565b5f805b8215611d5157611d6b600184612ad8565b9092169180611d7981612d70565b915050611d5a565b604080518082019091525f80825260208201526102008261ffff1610611ddc5760405162461bcd60e51b815260206004820152601060248201526f7363616c61722d746f6f2d6c6172676560801b60448201526064016104ef565b8161ffff16600103611def575081611d51565b604080518082019091525f8082526020820181905284906001905b8161ffff168661ffff1610611e5757600161ffff871660ff83161c81169003611e3a57611e37848461188e565b93505b611e44838461188e565b92506201fffe600192831b169101611e0a565b509195945050505050565b604080518082019091525f80825260208201528151158015611e8657506020820151155b15611ea3575050604080518082019091525f808252602082015290565b6040518060400160405280835f015181526020015f516020612d915f395f51905f528460200151611ed49190612a6b565b611eeb905f516020612d915f395f51905f52612ad8565b905292915050565b919050565b5f80805f516020612d915f395f51905f5260035f516020612d915f395f51905f52865f516020612d915f395f51905f52888909090890505f611f68827f0c19139cb84c680a6e14116da060561765e05aa45a1c72a34f082305b61f3f525f516020612d915f395f51905f526120f7565b91959194509092505050565b5f61010082511115611ffc5760405162461bcd60e51b8152602060048201526044602482018190527f4269746d61705574696c732e6f72646572656442797465734172726179546f42908201527f69746d61703a206f7264657265644279746573417272617920697320746f6f206064820152636c6f6e6760e01b608482015260a4016104ef565b81515f0361200b57505f919050565b5f5f835f8151811061201f5761201f612a43565b0160200151600160f89190911c81901b92505b84518110156120ee5784818151811061204d5761204d612a43565b0160200151600160f89190911c1b91508282116120e25760405162461bcd60e51b815260206004820152604760248201527f4269746d61705574696c732e6f72646572656442797465734172726179546f4260448201527f69746d61703a206f72646572656442797465734172726179206973206e6f74206064820152661bdc99195c995960ca1b608482015260a4016104ef565b91811791600101612032565b50909392505050565b5f5f6121016122d4565b6121096122f2565b602080825281810181905260408201819052606082018890526080820187905260a082018690528260c08360056107d05a03fa9250828061214657fe5b50826121945760405162461bcd60e51b815260206004820152601a60248201527f424e3235342e6578704d6f643a2063616c6c206661696c75726500000000000060448201526064016104ef565b505195945050505050565b828054828255905f5260205f2090600101600290048101928215612244579160200282015f5b8382111561220f57835183826101000a8154816001600160601b0302191690836001600160601b031602179055509260200192600c01602081600b010492830192600103026121c5565b80156122425782816101000a8154906001600160601b030219169055600c01602081600b0104928301926001030261220f565b505b50612250929150612310565b5090565b60405180606001604052806003906020820280368337509192915050565b60405180608001604052806004906020820280368337509192915050565b60405180604001604052806122a3612324565b81526020016122b0612324565b905290565b604051806101800160405280600c906020820280368337509192915050565b60405180602001604052806001906020820280368337509192915050565b6040518060c001604052806006906020820280368337509192915050565b5b80821115612250575f8155600101612311565b60405180604001604052806002906020820280368337509192915050565b634e487b7160e01b5f52604160045260245ffd5b604080519081016001600160401b038111828210171561237857612378612342565b60405290565b60405161010081016001600160401b038111828210171561237857612378612342565b604051601f8201601f191681016001600160401b03811182821017156123c9576123c9612342565b604052919050565b5f604082840312156123e1575f5ffd5b6123e9612356565b823581526020928301359281019290925250919050565b5f82601f83011261240f575f5ffd5b612417612356565b806040840185811115612428575f5ffd5b845b8181101561244257803584526020938401930161242a565b509095945050505050565b5f6080828403121561245d575f5ffd5b612465612356565b90506124718383612400565b81526124808360408401612400565b602082015292915050565b5f5f5f5f610120858703121561249f575f5ffd5b843593506124b086602087016123d1565b92506124bf866060870161244d565b91506124ce8660e087016123d1565b905092959194509250565b5f602082840312156124e9575f5ffd5b81358015158114611d4e575f5ffd5b5f5f83601f840112612508575f5ffd5b5081356001600160401b0381111561251e575f5ffd5b602083019150836020828501011115612535575f5ffd5b9250929050565b803563ffffffff81168114611ef3575f5ffd5b5f6001600160401b0382111561256757612567612342565b5060051b60200190565b5f82601f830112612580575f5ffd5b813561259361258e8261254f565b6123a1565b8082825260208201915060208360051b8601019250858311156125b4575f5ffd5b602085015b838110156125d8576125ca8161253c565b8352602092830192016125b9565b5095945050505050565b5f82601f8301126125f1575f5ffd5b81356125ff61258e8261254f565b8082825260208201915060208360061b860101925085831115612620575f5ffd5b602085015b838110156125d85761263787826123d1565b8352602090920191604001612625565b5f82601f830112612656575f5ffd5b813561266461258e8261254f565b8082825260208201915060208360051b860101925085831115612685575f5ffd5b602085015b838110156125d85780356001600160401b038111156126a7575f5ffd5b6126b6886020838a0101612571565b8452506020928301920161268a565b5f61018082840312156126d6575f5ffd5b6126de61237e565b905081356001600160401b038111156126f5575f5ffd5b61270184828501612571565b82525060208201356001600160401b0381111561271c575f5ffd5b612728848285016125e2565b60208301525060408201356001600160401b03811115612746575f5ffd5b612752848285016125e2565b604083015250612765836060840161244d565b60608201526127778360e084016123d1565b60808201526101208201356001600160401b03811115612795575f5ffd5b6127a184828501612571565b60a0830152506101408201356001600160401b038111156127c0575f5ffd5b6127cc84828501612571565b60c0830152506101608201356001600160401b038111156127eb575f5ffd5b6127f784828501612647565b60e08301525092915050565b5f5f5f5f5f60808688031215612817575f5ffd5b8535945060208601356001600160401b03811115612833575f5ffd5b61283f888289016124f8565b909550935061285290506040870161253c565b915060608601356001600160401b0381111561286c575f5ffd5b612878888289016126c5565b9150509295509295909350565b5f8151808452602084019350602083015f5b828110156128be5781516001600160601b0316865260209586019590910190600101612897565b5093949350505050565b5f8151604084526128dc6040850182612885565b9050602083015184820360208601526128f58282612885565b95945050505050565b604081525f61291060408301856128c8565b90508260208301529392505050565b5f5f5f5f5f5f60808789031215612934575f5ffd5b86356001600160401b03811115612949575f5ffd5b61295589828a016124f8565b90975095505060208701356001600160401b03811115612973575f5ffd5b61297f89828a016124f8565b909550935061299290506040880161253c565b915060608701356001600160401b038111156129ac575f5ffd5b8701610180818a0312156129be575f5ffd5b809150509295509295509295565b5f602082840312156129dc575f5ffd5b5035919050565b608081525f8551806080840152806020880160a085015e5f60a08285010152601f19601f8201168301905063ffffffff8616602084015284604084015260a0838203016060840152612a3860a08201856128c8565b979650505050505050565b634e487b7160e01b5f52603260045260245ffd5b634e487b7160e01b5f52601260045260245ffd5b5f82612a7957612a79612a57565b500690565b5f60208284031215612a8e575f5ffd5b81516001600160a01b0381168114611d4e575f5ffd5b5f60208284031215612ab4575f5ffd5b815160ff81168114611d4e575f5ffd5b634e487b7160e01b5f52601160045260245ffd5b81810381811115611d5157611d51612ac4565b5f60208284031215612afb575f5ffd5b81516001600160c01b0381168114611d4e575f5ffd5b5f60208284031215612b21575f5ffd5b5051919050565b80820180821115611d5157611d51612ac4565b5f60208284031215612b4b575f5ffd5b815167ffffffffffffffff1981168114611d4e575f5ffd5b5f60208284031215612b73575f5ffd5b81516001600160601b0381168114611d4e575f5ffd5b6001600160601b038281168282160390811115611d5157611d51612ac4565b63ffffffff60e01b8360e01b1681525f600482018351602085015f5b82811015612be2578151845260209384019390910190600101612bc4565b50919695505050505050565b5f82612bfc57612bfc612a57565b500490565b818382375f9101908152919050565b5f611d5136836126c5565b8082028115828204841417611d5157611d51612ac4565b600181811c90821680612c4657607f821691505b602082108103612c6457634e487b7160e01b5f52602260045260245ffd5b50919050565b601f821115612cb157805f5260205f20601f840160051c81016020851015612c8f5750805b601f840160051c820191505b81811015612cae575f8155600101612c9b565b50505b505050565b81516001600160401b03811115612ccf57612ccf612342565b612ce381612cdd8454612c32565b84612c6a565b6020601f821160018114612d15575f8315612cfe5750848201515b5f19600385901b1c1916600184901b178455612cae565b5f84815260208120601f198516915b82811015612d445787850151825560209485019460019092019101612d24565b5084821015612d6157868401515f19600387901b60f8161c191681555b50505050600190811b01905550565b5f61ffff821661ffff8103612d8757612d87612ac4565b6001019291505056fe30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47424c535369676e6174757265436865636b65722e636865636b5369676e617475a26469706673582212200a031c0f40cd7a9dba41c0282418688d6e6bb6036a5315d58d2eb80f4f8ce74d64736f6c634300081b0033", +} + +// ContractMinimalCertificateVerifierABI is the input ABI used to generate the binding from. +// Deprecated: Use ContractMinimalCertificateVerifierMetaData.ABI instead. +var ContractMinimalCertificateVerifierABI = ContractMinimalCertificateVerifierMetaData.ABI + +// ContractMinimalCertificateVerifierBin is the compiled bytecode used for deploying new contracts. +// Deprecated: Use ContractMinimalCertificateVerifierMetaData.Bin instead. +var ContractMinimalCertificateVerifierBin = ContractMinimalCertificateVerifierMetaData.Bin + +// DeployContractMinimalCertificateVerifier deploys a new Ethereum contract, binding an instance of ContractMinimalCertificateVerifier to it. +func DeployContractMinimalCertificateVerifier(auth *bind.TransactOpts, backend bind.ContractBackend, __registryCoordinator common.Address) (common.Address, *types.Transaction, *ContractMinimalCertificateVerifier, error) { + parsed, err := ContractMinimalCertificateVerifierMetaData.GetAbi() + if err != nil { + return common.Address{}, nil, nil, err + } + if parsed == nil { + return common.Address{}, nil, nil, errors.New("GetABI returned nil") + } + + address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(ContractMinimalCertificateVerifierBin), backend, __registryCoordinator) + if err != nil { + return common.Address{}, nil, nil, err + } + return address, tx, &ContractMinimalCertificateVerifier{ContractMinimalCertificateVerifierCaller: ContractMinimalCertificateVerifierCaller{contract: contract}, ContractMinimalCertificateVerifierTransactor: ContractMinimalCertificateVerifierTransactor{contract: contract}, ContractMinimalCertificateVerifierFilterer: ContractMinimalCertificateVerifierFilterer{contract: contract}}, nil +} + +// ContractMinimalCertificateVerifier is an auto generated Go binding around an Ethereum contract. +type ContractMinimalCertificateVerifier struct { + ContractMinimalCertificateVerifierCaller // Read-only binding to the contract + ContractMinimalCertificateVerifierTransactor // Write-only binding to the contract + ContractMinimalCertificateVerifierFilterer // Log filterer for contract events +} + +// ContractMinimalCertificateVerifierCaller is an auto generated read-only Go binding around an Ethereum contract. +type ContractMinimalCertificateVerifierCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// ContractMinimalCertificateVerifierTransactor is an auto generated write-only Go binding around an Ethereum contract. +type ContractMinimalCertificateVerifierTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// ContractMinimalCertificateVerifierFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type ContractMinimalCertificateVerifierFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// ContractMinimalCertificateVerifierSession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type ContractMinimalCertificateVerifierSession struct { + Contract *ContractMinimalCertificateVerifier // 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 +} + +// ContractMinimalCertificateVerifierCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type ContractMinimalCertificateVerifierCallerSession struct { + Contract *ContractMinimalCertificateVerifierCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// ContractMinimalCertificateVerifierTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type ContractMinimalCertificateVerifierTransactorSession struct { + Contract *ContractMinimalCertificateVerifierTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// ContractMinimalCertificateVerifierRaw is an auto generated low-level Go binding around an Ethereum contract. +type ContractMinimalCertificateVerifierRaw struct { + Contract *ContractMinimalCertificateVerifier // Generic contract binding to access the raw methods on +} + +// ContractMinimalCertificateVerifierCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type ContractMinimalCertificateVerifierCallerRaw struct { + Contract *ContractMinimalCertificateVerifierCaller // Generic read-only contract binding to access the raw methods on +} + +// ContractMinimalCertificateVerifierTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type ContractMinimalCertificateVerifierTransactorRaw struct { + Contract *ContractMinimalCertificateVerifierTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewContractMinimalCertificateVerifier creates a new instance of ContractMinimalCertificateVerifier, bound to a specific deployed contract. +func NewContractMinimalCertificateVerifier(address common.Address, backend bind.ContractBackend) (*ContractMinimalCertificateVerifier, error) { + contract, err := bindContractMinimalCertificateVerifier(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &ContractMinimalCertificateVerifier{ContractMinimalCertificateVerifierCaller: ContractMinimalCertificateVerifierCaller{contract: contract}, ContractMinimalCertificateVerifierTransactor: ContractMinimalCertificateVerifierTransactor{contract: contract}, ContractMinimalCertificateVerifierFilterer: ContractMinimalCertificateVerifierFilterer{contract: contract}}, nil +} + +// NewContractMinimalCertificateVerifierCaller creates a new read-only instance of ContractMinimalCertificateVerifier, bound to a specific deployed contract. +func NewContractMinimalCertificateVerifierCaller(address common.Address, caller bind.ContractCaller) (*ContractMinimalCertificateVerifierCaller, error) { + contract, err := bindContractMinimalCertificateVerifier(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &ContractMinimalCertificateVerifierCaller{contract: contract}, nil +} + +// NewContractMinimalCertificateVerifierTransactor creates a new write-only instance of ContractMinimalCertificateVerifier, bound to a specific deployed contract. +func NewContractMinimalCertificateVerifierTransactor(address common.Address, transactor bind.ContractTransactor) (*ContractMinimalCertificateVerifierTransactor, error) { + contract, err := bindContractMinimalCertificateVerifier(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &ContractMinimalCertificateVerifierTransactor{contract: contract}, nil +} + +// NewContractMinimalCertificateVerifierFilterer creates a new log filterer instance of ContractMinimalCertificateVerifier, bound to a specific deployed contract. +func NewContractMinimalCertificateVerifierFilterer(address common.Address, filterer bind.ContractFilterer) (*ContractMinimalCertificateVerifierFilterer, error) { + contract, err := bindContractMinimalCertificateVerifier(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &ContractMinimalCertificateVerifierFilterer{contract: contract}, nil +} + +// bindContractMinimalCertificateVerifier binds a generic wrapper to an already deployed contract. +func bindContractMinimalCertificateVerifier(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := ContractMinimalCertificateVerifierMetaData.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 (_ContractMinimalCertificateVerifier *ContractMinimalCertificateVerifierRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _ContractMinimalCertificateVerifier.Contract.ContractMinimalCertificateVerifierCaller.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 (_ContractMinimalCertificateVerifier *ContractMinimalCertificateVerifierRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _ContractMinimalCertificateVerifier.Contract.ContractMinimalCertificateVerifierTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_ContractMinimalCertificateVerifier *ContractMinimalCertificateVerifierRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _ContractMinimalCertificateVerifier.Contract.ContractMinimalCertificateVerifierTransactor.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 (_ContractMinimalCertificateVerifier *ContractMinimalCertificateVerifierCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _ContractMinimalCertificateVerifier.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 (_ContractMinimalCertificateVerifier *ContractMinimalCertificateVerifierTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _ContractMinimalCertificateVerifier.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_ContractMinimalCertificateVerifier *ContractMinimalCertificateVerifierTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _ContractMinimalCertificateVerifier.Contract.contract.Transact(opts, method, params...) +} + +// DENOMINATOR is a free data retrieval call binding the contract method 0x918f8674. +// +// Solidity: function DENOMINATOR() view returns(uint256) +func (_ContractMinimalCertificateVerifier *ContractMinimalCertificateVerifierCaller) DENOMINATOR(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _ContractMinimalCertificateVerifier.contract.Call(opts, &out, "DENOMINATOR") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// DENOMINATOR is a free data retrieval call binding the contract method 0x918f8674. +// +// Solidity: function DENOMINATOR() view returns(uint256) +func (_ContractMinimalCertificateVerifier *ContractMinimalCertificateVerifierSession) DENOMINATOR() (*big.Int, error) { + return _ContractMinimalCertificateVerifier.Contract.DENOMINATOR(&_ContractMinimalCertificateVerifier.CallOpts) +} + +// DENOMINATOR is a free data retrieval call binding the contract method 0x918f8674. +// +// Solidity: function DENOMINATOR() view returns(uint256) +func (_ContractMinimalCertificateVerifier *ContractMinimalCertificateVerifierCallerSession) DENOMINATOR() (*big.Int, error) { + return _ContractMinimalCertificateVerifier.Contract.DENOMINATOR(&_ContractMinimalCertificateVerifier.CallOpts) +} + +// THRESHOLD is a free data retrieval call binding the contract method 0x785ffb37. +// +// Solidity: function THRESHOLD() view returns(uint256) +func (_ContractMinimalCertificateVerifier *ContractMinimalCertificateVerifierCaller) THRESHOLD(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _ContractMinimalCertificateVerifier.contract.Call(opts, &out, "THRESHOLD") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// THRESHOLD is a free data retrieval call binding the contract method 0x785ffb37. +// +// Solidity: function THRESHOLD() view returns(uint256) +func (_ContractMinimalCertificateVerifier *ContractMinimalCertificateVerifierSession) THRESHOLD() (*big.Int, error) { + return _ContractMinimalCertificateVerifier.Contract.THRESHOLD(&_ContractMinimalCertificateVerifier.CallOpts) +} + +// THRESHOLD is a free data retrieval call binding the contract method 0x785ffb37. +// +// Solidity: function THRESHOLD() view returns(uint256) +func (_ContractMinimalCertificateVerifier *ContractMinimalCertificateVerifierCallerSession) THRESHOLD() (*big.Int, error) { + return _ContractMinimalCertificateVerifier.Contract.THRESHOLD(&_ContractMinimalCertificateVerifier.CallOpts) +} + +// BlsApkRegistry is a free data retrieval call binding the contract method 0x5df45946. +// +// Solidity: function blsApkRegistry() view returns(address) +func (_ContractMinimalCertificateVerifier *ContractMinimalCertificateVerifierCaller) BlsApkRegistry(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _ContractMinimalCertificateVerifier.contract.Call(opts, &out, "blsApkRegistry") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// BlsApkRegistry is a free data retrieval call binding the contract method 0x5df45946. +// +// Solidity: function blsApkRegistry() view returns(address) +func (_ContractMinimalCertificateVerifier *ContractMinimalCertificateVerifierSession) BlsApkRegistry() (common.Address, error) { + return _ContractMinimalCertificateVerifier.Contract.BlsApkRegistry(&_ContractMinimalCertificateVerifier.CallOpts) +} + +// BlsApkRegistry is a free data retrieval call binding the contract method 0x5df45946. +// +// Solidity: function blsApkRegistry() view returns(address) +func (_ContractMinimalCertificateVerifier *ContractMinimalCertificateVerifierCallerSession) BlsApkRegistry() (common.Address, error) { + return _ContractMinimalCertificateVerifier.Contract.BlsApkRegistry(&_ContractMinimalCertificateVerifier.CallOpts) +} + +// CheckSignatures is a free data retrieval call binding the contract method 0x6efb4636. +// +// Solidity: function checkSignatures(bytes32 msgHash, bytes quorumNumbers, uint32 referenceBlockNumber, (uint32[],(uint256,uint256)[],(uint256,uint256)[],(uint256[2],uint256[2]),(uint256,uint256),uint32[],uint32[],uint32[][]) params) view returns((uint96[],uint96[]), bytes32) +func (_ContractMinimalCertificateVerifier *ContractMinimalCertificateVerifierCaller) CheckSignatures(opts *bind.CallOpts, msgHash [32]byte, quorumNumbers []byte, referenceBlockNumber uint32, params IBLSSignatureCheckerNonSignerStakesAndSignature) (IBLSSignatureCheckerQuorumStakeTotals, [32]byte, error) { + var out []interface{} + err := _ContractMinimalCertificateVerifier.contract.Call(opts, &out, "checkSignatures", msgHash, quorumNumbers, referenceBlockNumber, params) + + if err != nil { + return *new(IBLSSignatureCheckerQuorumStakeTotals), *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new(IBLSSignatureCheckerQuorumStakeTotals)).(*IBLSSignatureCheckerQuorumStakeTotals) + out1 := *abi.ConvertType(out[1], new([32]byte)).(*[32]byte) + + return out0, out1, err + +} + +// CheckSignatures is a free data retrieval call binding the contract method 0x6efb4636. +// +// Solidity: function checkSignatures(bytes32 msgHash, bytes quorumNumbers, uint32 referenceBlockNumber, (uint32[],(uint256,uint256)[],(uint256,uint256)[],(uint256[2],uint256[2]),(uint256,uint256),uint32[],uint32[],uint32[][]) params) view returns((uint96[],uint96[]), bytes32) +func (_ContractMinimalCertificateVerifier *ContractMinimalCertificateVerifierSession) CheckSignatures(msgHash [32]byte, quorumNumbers []byte, referenceBlockNumber uint32, params IBLSSignatureCheckerNonSignerStakesAndSignature) (IBLSSignatureCheckerQuorumStakeTotals, [32]byte, error) { + return _ContractMinimalCertificateVerifier.Contract.CheckSignatures(&_ContractMinimalCertificateVerifier.CallOpts, msgHash, quorumNumbers, referenceBlockNumber, params) +} + +// CheckSignatures is a free data retrieval call binding the contract method 0x6efb4636. +// +// Solidity: function checkSignatures(bytes32 msgHash, bytes quorumNumbers, uint32 referenceBlockNumber, (uint32[],(uint256,uint256)[],(uint256,uint256)[],(uint256[2],uint256[2]),(uint256,uint256),uint32[],uint32[],uint32[][]) params) view returns((uint96[],uint96[]), bytes32) +func (_ContractMinimalCertificateVerifier *ContractMinimalCertificateVerifierCallerSession) CheckSignatures(msgHash [32]byte, quorumNumbers []byte, referenceBlockNumber uint32, params IBLSSignatureCheckerNonSignerStakesAndSignature) (IBLSSignatureCheckerQuorumStakeTotals, [32]byte, error) { + return _ContractMinimalCertificateVerifier.Contract.CheckSignatures(&_ContractMinimalCertificateVerifier.CallOpts, msgHash, quorumNumbers, referenceBlockNumber, params) +} + +// Delegation is a free data retrieval call binding the contract method 0xdf5cf723. +// +// Solidity: function delegation() view returns(address) +func (_ContractMinimalCertificateVerifier *ContractMinimalCertificateVerifierCaller) Delegation(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _ContractMinimalCertificateVerifier.contract.Call(opts, &out, "delegation") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// Delegation is a free data retrieval call binding the contract method 0xdf5cf723. +// +// Solidity: function delegation() view returns(address) +func (_ContractMinimalCertificateVerifier *ContractMinimalCertificateVerifierSession) Delegation() (common.Address, error) { + return _ContractMinimalCertificateVerifier.Contract.Delegation(&_ContractMinimalCertificateVerifier.CallOpts) +} + +// Delegation is a free data retrieval call binding the contract method 0xdf5cf723. +// +// Solidity: function delegation() view returns(address) +func (_ContractMinimalCertificateVerifier *ContractMinimalCertificateVerifierCallerSession) Delegation() (common.Address, error) { + return _ContractMinimalCertificateVerifier.Contract.Delegation(&_ContractMinimalCertificateVerifier.CallOpts) +} + +// RegistryCoordinator is a free data retrieval call binding the contract method 0x6d14a987. +// +// Solidity: function registryCoordinator() view returns(address) +func (_ContractMinimalCertificateVerifier *ContractMinimalCertificateVerifierCaller) RegistryCoordinator(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _ContractMinimalCertificateVerifier.contract.Call(opts, &out, "registryCoordinator") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// RegistryCoordinator is a free data retrieval call binding the contract method 0x6d14a987. +// +// Solidity: function registryCoordinator() view returns(address) +func (_ContractMinimalCertificateVerifier *ContractMinimalCertificateVerifierSession) RegistryCoordinator() (common.Address, error) { + return _ContractMinimalCertificateVerifier.Contract.RegistryCoordinator(&_ContractMinimalCertificateVerifier.CallOpts) +} + +// RegistryCoordinator is a free data retrieval call binding the contract method 0x6d14a987. +// +// Solidity: function registryCoordinator() view returns(address) +func (_ContractMinimalCertificateVerifier *ContractMinimalCertificateVerifierCallerSession) RegistryCoordinator() (common.Address, error) { + return _ContractMinimalCertificateVerifier.Contract.RegistryCoordinator(&_ContractMinimalCertificateVerifier.CallOpts) +} + +// StakeRegistry is a free data retrieval call binding the contract method 0x68304835. +// +// Solidity: function stakeRegistry() view returns(address) +func (_ContractMinimalCertificateVerifier *ContractMinimalCertificateVerifierCaller) StakeRegistry(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _ContractMinimalCertificateVerifier.contract.Call(opts, &out, "stakeRegistry") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// StakeRegistry is a free data retrieval call binding the contract method 0x68304835. +// +// Solidity: function stakeRegistry() view returns(address) +func (_ContractMinimalCertificateVerifier *ContractMinimalCertificateVerifierSession) StakeRegistry() (common.Address, error) { + return _ContractMinimalCertificateVerifier.Contract.StakeRegistry(&_ContractMinimalCertificateVerifier.CallOpts) +} + +// StakeRegistry is a free data retrieval call binding the contract method 0x68304835. +// +// Solidity: function stakeRegistry() view returns(address) +func (_ContractMinimalCertificateVerifier *ContractMinimalCertificateVerifierCallerSession) StakeRegistry() (common.Address, error) { + return _ContractMinimalCertificateVerifier.Contract.StakeRegistry(&_ContractMinimalCertificateVerifier.CallOpts) +} + +// StaleStakesForbidden is a free data retrieval call binding the contract method 0xb98d0908. +// +// Solidity: function staleStakesForbidden() view returns(bool) +func (_ContractMinimalCertificateVerifier *ContractMinimalCertificateVerifierCaller) StaleStakesForbidden(opts *bind.CallOpts) (bool, error) { + var out []interface{} + err := _ContractMinimalCertificateVerifier.contract.Call(opts, &out, "staleStakesForbidden") + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// StaleStakesForbidden is a free data retrieval call binding the contract method 0xb98d0908. +// +// Solidity: function staleStakesForbidden() view returns(bool) +func (_ContractMinimalCertificateVerifier *ContractMinimalCertificateVerifierSession) StaleStakesForbidden() (bool, error) { + return _ContractMinimalCertificateVerifier.Contract.StaleStakesForbidden(&_ContractMinimalCertificateVerifier.CallOpts) +} + +// StaleStakesForbidden is a free data retrieval call binding the contract method 0xb98d0908. +// +// Solidity: function staleStakesForbidden() view returns(bool) +func (_ContractMinimalCertificateVerifier *ContractMinimalCertificateVerifierCallerSession) StaleStakesForbidden() (bool, error) { + return _ContractMinimalCertificateVerifier.Contract.StaleStakesForbidden(&_ContractMinimalCertificateVerifier.CallOpts) +} + +// TrySignatureAndApkVerification is a free data retrieval call binding the contract method 0x171f1d5b. +// +// Solidity: function trySignatureAndApkVerification(bytes32 msgHash, (uint256,uint256) apk, (uint256[2],uint256[2]) apkG2, (uint256,uint256) sigma) view returns(bool pairingSuccessful, bool siganatureIsValid) +func (_ContractMinimalCertificateVerifier *ContractMinimalCertificateVerifierCaller) TrySignatureAndApkVerification(opts *bind.CallOpts, msgHash [32]byte, apk BN254G1Point, apkG2 BN254G2Point, sigma BN254G1Point) (struct { + PairingSuccessful bool + SiganatureIsValid bool +}, error) { + var out []interface{} + err := _ContractMinimalCertificateVerifier.contract.Call(opts, &out, "trySignatureAndApkVerification", msgHash, apk, apkG2, sigma) + + outstruct := new(struct { + PairingSuccessful bool + SiganatureIsValid bool + }) + if err != nil { + return *outstruct, err + } + + outstruct.PairingSuccessful = *abi.ConvertType(out[0], new(bool)).(*bool) + outstruct.SiganatureIsValid = *abi.ConvertType(out[1], new(bool)).(*bool) + + return *outstruct, err + +} + +// TrySignatureAndApkVerification is a free data retrieval call binding the contract method 0x171f1d5b. +// +// Solidity: function trySignatureAndApkVerification(bytes32 msgHash, (uint256,uint256) apk, (uint256[2],uint256[2]) apkG2, (uint256,uint256) sigma) view returns(bool pairingSuccessful, bool siganatureIsValid) +func (_ContractMinimalCertificateVerifier *ContractMinimalCertificateVerifierSession) TrySignatureAndApkVerification(msgHash [32]byte, apk BN254G1Point, apkG2 BN254G2Point, sigma BN254G1Point) (struct { + PairingSuccessful bool + SiganatureIsValid bool +}, error) { + return _ContractMinimalCertificateVerifier.Contract.TrySignatureAndApkVerification(&_ContractMinimalCertificateVerifier.CallOpts, msgHash, apk, apkG2, sigma) +} + +// TrySignatureAndApkVerification is a free data retrieval call binding the contract method 0x171f1d5b. +// +// Solidity: function trySignatureAndApkVerification(bytes32 msgHash, (uint256,uint256) apk, (uint256[2],uint256[2]) apkG2, (uint256,uint256) sigma) view returns(bool pairingSuccessful, bool siganatureIsValid) +func (_ContractMinimalCertificateVerifier *ContractMinimalCertificateVerifierCallerSession) TrySignatureAndApkVerification(msgHash [32]byte, apk BN254G1Point, apkG2 BN254G2Point, sigma BN254G1Point) (struct { + PairingSuccessful bool + SiganatureIsValid bool +}, error) { + return _ContractMinimalCertificateVerifier.Contract.TrySignatureAndApkVerification(&_ContractMinimalCertificateVerifier.CallOpts, msgHash, apk, apkG2, sigma) +} + +// VerificationRecords is a free data retrieval call binding the contract method 0x81d9d23d. +// +// Solidity: function verificationRecords(bytes32 ) view returns(bytes quorumNumbers, uint32 referenceBlockNumber, bytes32 signatoryRecordHash, (uint96[],uint96[]) quorumStakeTotals) +func (_ContractMinimalCertificateVerifier *ContractMinimalCertificateVerifierCaller) VerificationRecords(opts *bind.CallOpts, arg0 [32]byte) (struct { + QuorumNumbers []byte + ReferenceBlockNumber uint32 + SignatoryRecordHash [32]byte + QuorumStakeTotals IBLSSignatureCheckerQuorumStakeTotals +}, error) { + var out []interface{} + err := _ContractMinimalCertificateVerifier.contract.Call(opts, &out, "verificationRecords", arg0) + + outstruct := new(struct { + QuorumNumbers []byte + ReferenceBlockNumber uint32 + SignatoryRecordHash [32]byte + QuorumStakeTotals IBLSSignatureCheckerQuorumStakeTotals + }) + if err != nil { + return *outstruct, err + } + + outstruct.QuorumNumbers = *abi.ConvertType(out[0], new([]byte)).(*[]byte) + outstruct.ReferenceBlockNumber = *abi.ConvertType(out[1], new(uint32)).(*uint32) + outstruct.SignatoryRecordHash = *abi.ConvertType(out[2], new([32]byte)).(*[32]byte) + outstruct.QuorumStakeTotals = *abi.ConvertType(out[3], new(IBLSSignatureCheckerQuorumStakeTotals)).(*IBLSSignatureCheckerQuorumStakeTotals) + + return *outstruct, err + +} + +// VerificationRecords is a free data retrieval call binding the contract method 0x81d9d23d. +// +// Solidity: function verificationRecords(bytes32 ) view returns(bytes quorumNumbers, uint32 referenceBlockNumber, bytes32 signatoryRecordHash, (uint96[],uint96[]) quorumStakeTotals) +func (_ContractMinimalCertificateVerifier *ContractMinimalCertificateVerifierSession) VerificationRecords(arg0 [32]byte) (struct { + QuorumNumbers []byte + ReferenceBlockNumber uint32 + SignatoryRecordHash [32]byte + QuorumStakeTotals IBLSSignatureCheckerQuorumStakeTotals +}, error) { + return _ContractMinimalCertificateVerifier.Contract.VerificationRecords(&_ContractMinimalCertificateVerifier.CallOpts, arg0) +} + +// VerificationRecords is a free data retrieval call binding the contract method 0x81d9d23d. +// +// Solidity: function verificationRecords(bytes32 ) view returns(bytes quorumNumbers, uint32 referenceBlockNumber, bytes32 signatoryRecordHash, (uint96[],uint96[]) quorumStakeTotals) +func (_ContractMinimalCertificateVerifier *ContractMinimalCertificateVerifierCallerSession) VerificationRecords(arg0 [32]byte) (struct { + QuorumNumbers []byte + ReferenceBlockNumber uint32 + SignatoryRecordHash [32]byte + QuorumStakeTotals IBLSSignatureCheckerQuorumStakeTotals +}, error) { + return _ContractMinimalCertificateVerifier.Contract.VerificationRecords(&_ContractMinimalCertificateVerifier.CallOpts, arg0) +} + +// SetStaleStakesForbidden is a paid mutator transaction binding the contract method 0x416c7e5e. +// +// Solidity: function setStaleStakesForbidden(bool value) returns() +func (_ContractMinimalCertificateVerifier *ContractMinimalCertificateVerifierTransactor) SetStaleStakesForbidden(opts *bind.TransactOpts, value bool) (*types.Transaction, error) { + return _ContractMinimalCertificateVerifier.contract.Transact(opts, "setStaleStakesForbidden", value) +} + +// SetStaleStakesForbidden is a paid mutator transaction binding the contract method 0x416c7e5e. +// +// Solidity: function setStaleStakesForbidden(bool value) returns() +func (_ContractMinimalCertificateVerifier *ContractMinimalCertificateVerifierSession) SetStaleStakesForbidden(value bool) (*types.Transaction, error) { + return _ContractMinimalCertificateVerifier.Contract.SetStaleStakesForbidden(&_ContractMinimalCertificateVerifier.TransactOpts, value) +} + +// SetStaleStakesForbidden is a paid mutator transaction binding the contract method 0x416c7e5e. +// +// Solidity: function setStaleStakesForbidden(bool value) returns() +func (_ContractMinimalCertificateVerifier *ContractMinimalCertificateVerifierTransactorSession) SetStaleStakesForbidden(value bool) (*types.Transaction, error) { + return _ContractMinimalCertificateVerifier.Contract.SetStaleStakesForbidden(&_ContractMinimalCertificateVerifier.TransactOpts, value) +} + +// VerifyCertificate is a paid mutator transaction binding the contract method 0x81d18a0d. +// +// Solidity: function verifyCertificate(bytes response, bytes quorumNumbers, uint32 referenceBlockNumber, (uint32[],(uint256,uint256)[],(uint256,uint256)[],(uint256[2],uint256[2]),(uint256,uint256),uint32[],uint32[],uint32[][]) params) returns() +func (_ContractMinimalCertificateVerifier *ContractMinimalCertificateVerifierTransactor) VerifyCertificate(opts *bind.TransactOpts, response []byte, quorumNumbers []byte, referenceBlockNumber uint32, params IBLSSignatureCheckerNonSignerStakesAndSignature) (*types.Transaction, error) { + return _ContractMinimalCertificateVerifier.contract.Transact(opts, "verifyCertificate", response, quorumNumbers, referenceBlockNumber, params) +} + +// VerifyCertificate is a paid mutator transaction binding the contract method 0x81d18a0d. +// +// Solidity: function verifyCertificate(bytes response, bytes quorumNumbers, uint32 referenceBlockNumber, (uint32[],(uint256,uint256)[],(uint256,uint256)[],(uint256[2],uint256[2]),(uint256,uint256),uint32[],uint32[],uint32[][]) params) returns() +func (_ContractMinimalCertificateVerifier *ContractMinimalCertificateVerifierSession) VerifyCertificate(response []byte, quorumNumbers []byte, referenceBlockNumber uint32, params IBLSSignatureCheckerNonSignerStakesAndSignature) (*types.Transaction, error) { + return _ContractMinimalCertificateVerifier.Contract.VerifyCertificate(&_ContractMinimalCertificateVerifier.TransactOpts, response, quorumNumbers, referenceBlockNumber, params) +} + +// VerifyCertificate is a paid mutator transaction binding the contract method 0x81d18a0d. +// +// Solidity: function verifyCertificate(bytes response, bytes quorumNumbers, uint32 referenceBlockNumber, (uint32[],(uint256,uint256)[],(uint256,uint256)[],(uint256[2],uint256[2]),(uint256,uint256),uint32[],uint32[],uint32[][]) params) returns() +func (_ContractMinimalCertificateVerifier *ContractMinimalCertificateVerifierTransactorSession) VerifyCertificate(response []byte, quorumNumbers []byte, referenceBlockNumber uint32, params IBLSSignatureCheckerNonSignerStakesAndSignature) (*types.Transaction, error) { + return _ContractMinimalCertificateVerifier.Contract.VerifyCertificate(&_ContractMinimalCertificateVerifier.TransactOpts, response, quorumNumbers, referenceBlockNumber, params) +} + +// ContractMinimalCertificateVerifierStaleStakesForbiddenUpdateIterator is returned from FilterStaleStakesForbiddenUpdate and is used to iterate over the raw logs and unpacked data for StaleStakesForbiddenUpdate events raised by the ContractMinimalCertificateVerifier contract. +type ContractMinimalCertificateVerifierStaleStakesForbiddenUpdateIterator struct { + Event *ContractMinimalCertificateVerifierStaleStakesForbiddenUpdate // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *ContractMinimalCertificateVerifierStaleStakesForbiddenUpdateIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(ContractMinimalCertificateVerifierStaleStakesForbiddenUpdate) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(ContractMinimalCertificateVerifierStaleStakesForbiddenUpdate) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *ContractMinimalCertificateVerifierStaleStakesForbiddenUpdateIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *ContractMinimalCertificateVerifierStaleStakesForbiddenUpdateIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// ContractMinimalCertificateVerifierStaleStakesForbiddenUpdate represents a StaleStakesForbiddenUpdate event raised by the ContractMinimalCertificateVerifier contract. +type ContractMinimalCertificateVerifierStaleStakesForbiddenUpdate struct { + Value bool + Raw types.Log // Blockchain specific contextual infos +} + +// FilterStaleStakesForbiddenUpdate is a free log retrieval operation binding the contract event 0x40e4ed880a29e0f6ddce307457fb75cddf4feef7d3ecb0301bfdf4976a0e2dfc. +// +// Solidity: event StaleStakesForbiddenUpdate(bool value) +func (_ContractMinimalCertificateVerifier *ContractMinimalCertificateVerifierFilterer) FilterStaleStakesForbiddenUpdate(opts *bind.FilterOpts) (*ContractMinimalCertificateVerifierStaleStakesForbiddenUpdateIterator, error) { + + logs, sub, err := _ContractMinimalCertificateVerifier.contract.FilterLogs(opts, "StaleStakesForbiddenUpdate") + if err != nil { + return nil, err + } + return &ContractMinimalCertificateVerifierStaleStakesForbiddenUpdateIterator{contract: _ContractMinimalCertificateVerifier.contract, event: "StaleStakesForbiddenUpdate", logs: logs, sub: sub}, nil +} + +// WatchStaleStakesForbiddenUpdate is a free log subscription operation binding the contract event 0x40e4ed880a29e0f6ddce307457fb75cddf4feef7d3ecb0301bfdf4976a0e2dfc. +// +// Solidity: event StaleStakesForbiddenUpdate(bool value) +func (_ContractMinimalCertificateVerifier *ContractMinimalCertificateVerifierFilterer) WatchStaleStakesForbiddenUpdate(opts *bind.WatchOpts, sink chan<- *ContractMinimalCertificateVerifierStaleStakesForbiddenUpdate) (event.Subscription, error) { + + logs, sub, err := _ContractMinimalCertificateVerifier.contract.WatchLogs(opts, "StaleStakesForbiddenUpdate") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(ContractMinimalCertificateVerifierStaleStakesForbiddenUpdate) + if err := _ContractMinimalCertificateVerifier.contract.UnpackLog(event, "StaleStakesForbiddenUpdate", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseStaleStakesForbiddenUpdate is a log parse operation binding the contract event 0x40e4ed880a29e0f6ddce307457fb75cddf4feef7d3ecb0301bfdf4976a0e2dfc. +// +// Solidity: event StaleStakesForbiddenUpdate(bool value) +func (_ContractMinimalCertificateVerifier *ContractMinimalCertificateVerifierFilterer) ParseStaleStakesForbiddenUpdate(log types.Log) (*ContractMinimalCertificateVerifierStaleStakesForbiddenUpdate, error) { + event := new(ContractMinimalCertificateVerifierStaleStakesForbiddenUpdate) + if err := _ContractMinimalCertificateVerifier.contract.UnpackLog(event, "StaleStakesForbiddenUpdate", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} diff --git a/example/contracts/compile.sh b/example/contracts/compile.sh new file mode 100755 index 0000000..aa05abe --- /dev/null +++ b/example/contracts/compile.sh @@ -0,0 +1,31 @@ +#!/bin/bash + +function create_binding { + contract_dir=$1 + contract=$2 + binding_dir=$3 + echo $contract + cd $contract_dir + forge b + # pop back to the original directory + cd - + mkdir -p $binding_dir/${contract} + contract_json="$contract_dir/out/${contract}.sol/${contract}.json" + solc_abi=$(cat ${contract_json} | jq -r '.abi') + solc_bin=$(cat ${contract_json} | jq -r '.bytecode.object') + + mkdir -p data + echo ${solc_abi} > data/tmp.abi + echo ${solc_bin} > data/tmp.bin + + rm -f $binding_dir/${contract}/binding.go + abigen --bin=data/tmp.bin --abi=data/tmp.abi --pkg=contract${contract} --out=$binding_dir/${contract}/binding.go + + rm -f data/tmp.abi + rm -f data/tmp.bin +} + +contracts="MinimalCertificateVerifier" +for contract in $contracts; do + create_binding . $contract ./bindings +done \ No newline at end of file diff --git a/example/contracts/foundry.toml b/example/contracts/foundry.toml new file mode 100644 index 0000000..ba4b00b --- /dev/null +++ b/example/contracts/foundry.toml @@ -0,0 +1,7 @@ +[profile.default] +src = "src" +out = "out" +libs = ["lib"] +fs_permissions = [{ access = "read-write", path = "./"}] + +# See more config options https://github.com/foundry-rs/foundry/blob/master/crates/config/README.md#all-options diff --git a/example/contracts/lib/eigenlayer-middleware b/example/contracts/lib/eigenlayer-middleware new file mode 160000 index 0000000..91400d9 --- /dev/null +++ b/example/contracts/lib/eigenlayer-middleware @@ -0,0 +1 @@ +Subproject commit 91400d9776d4f7276a2807a53559f49f7edf5378 diff --git a/example/contracts/lib/forge-std b/example/contracts/lib/forge-std new file mode 160000 index 0000000..b93cf4b --- /dev/null +++ b/example/contracts/lib/forge-std @@ -0,0 +1 @@ +Subproject commit b93cf4bc34ff214c099dc970b153f85ade8c9f66 diff --git a/example/contracts/lib/openzeppelin-contracts b/example/contracts/lib/openzeppelin-contracts new file mode 160000 index 0000000..54b3f14 --- /dev/null +++ b/example/contracts/lib/openzeppelin-contracts @@ -0,0 +1 @@ +Subproject commit 54b3f14346da01ba0d159114b399197fea8b7cda diff --git a/example/contracts/lib/openzeppelin-contracts-upgradeable b/example/contracts/lib/openzeppelin-contracts-upgradeable new file mode 160000 index 0000000..f6febd7 --- /dev/null +++ b/example/contracts/lib/openzeppelin-contracts-upgradeable @@ -0,0 +1 @@ +Subproject commit f6febd79e2a3a17e26969dd0d450c6ebd64bf459 diff --git a/example/contracts/remappings.txt b/example/contracts/remappings.txt new file mode 100644 index 0000000..3ecd305 --- /dev/null +++ b/example/contracts/remappings.txt @@ -0,0 +1,6 @@ +@openzeppelin-upgrades/=lib/openzeppelin-contracts-upgradeable/ +@openzeppelin/=lib/openzeppelin-contracts/ +eigenlayer-middleware/=lib/eigenlayer-middleware/src/ +eigenlayer-core/=lib/eigenlayer-middleware/lib/eigenlayer-contracts/src/ +eigenlayer-scripts/=lib/eigenlayer-middleware/lib/eigenlayer-contracts/script/ +forge-std/=lib/forge-std/src/ \ No newline at end of file diff --git a/example/contracts/script/DeployAVS.s.sol b/example/contracts/script/DeployAVS.s.sol new file mode 100644 index 0000000..09f54fd --- /dev/null +++ b/example/contracts/script/DeployAVS.s.sol @@ -0,0 +1,257 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.12; + +import {ProxyAdmin} from "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol"; +import {TransparentUpgradeableProxy} from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; +import {ITransparentUpgradeableProxy} from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; +import {PauserRegistry} from "eigenlayer-core/contracts/permissions/PauserRegistry.sol"; +import {EmptyContract} from "eigenlayer-core/test/mocks/EmptyContract.sol"; +import {IDelegationManager} from "eigenlayer-core/contracts/interfaces/IDelegationManager.sol"; +import {IAVSDirectory} from "eigenlayer-core/contracts/interfaces/IAVSDirectory.sol"; +import {IRewardsCoordinator} from "eigenlayer-core/contracts/interfaces/IRewardsCoordinator.sol"; + +import {BLSApkRegistry} from "eigenlayer-middleware/BLSApkRegistry.sol"; +import {RegistryCoordinator} from "eigenlayer-middleware/RegistryCoordinator.sol"; +import {OperatorStateRetriever} from "eigenlayer-middleware/OperatorStateRetriever.sol"; +import {IRegistryCoordinator} from "eigenlayer-middleware/interfaces/IRegistryCoordinator.sol"; +import {IndexRegistry} from "eigenlayer-middleware/IndexRegistry.sol"; +import {IIndexRegistry} from "eigenlayer-middleware/interfaces/IIndexRegistry.sol"; +import {StakeRegistry, IStrategy} from "eigenlayer-middleware/StakeRegistry.sol"; +import {IStakeRegistry} from "eigenlayer-middleware/interfaces/IStakeRegistry.sol"; +import {IServiceManager} from "eigenlayer-middleware/interfaces/IServiceManager.sol"; +import {IBLSApkRegistry} from "eigenlayer-middleware/interfaces/IBLSApkRegistry.sol"; +import {ServiceManagerBase} from "eigenlayer-middleware/ServiceManagerBase.sol"; +import {ISocketRegistry, SocketRegistry} from "eigenlayer-middleware/SocketRegistry.sol"; +import {IPauserRegistry} from "eigenlayer-core/contracts/interfaces/IPauserRegistry.sol"; + +import {MinimalServiceManager} from "../src/MinimalServiceManager.sol"; +import {MinimalCertificateVerifier} from "../src/MinimalCertificateVerifier.sol"; + +import "forge-std/Test.sol"; +import "forge-std/Script.sol"; +import "forge-std/StdJson.sol"; + +contract DeployAVS is Script, Test { + // Core contracts + ProxyAdmin public avsProxyAdmin; + PauserRegistry public avsPauserReg; + EmptyContract public emptyContract; + + // Middleware contracts + BLSApkRegistry public apkRegistry; + IServiceManager public serviceManager; + MinimalCertificateVerifier public certificateVerifier; + RegistryCoordinator public registryCoordinator; + IIndexRegistry public indexRegistry; + IStakeRegistry public stakeRegistry; + ISocketRegistry public socketRegistry; + OperatorStateRetriever public operatorStateRetriever; + + // Implementation contracts + BLSApkRegistry public apkRegistryImplementation; + IServiceManager public serviceManagerImplementation; + MinimalCertificateVerifier public certificateVerifierImplementation; + IRegistryCoordinator public registryCoordinatorImplementation; + IIndexRegistry public indexRegistryImplementation; + IStakeRegistry public stakeRegistryImplementation; + ISocketRegistry public socketRegistryImplementation; + + struct EigenlayerDeployment { + address avsDirectory; + address delegationManager; + address permissionsController; + address rewardsCoordinator; + } + + function run( + string memory inputConfigPath, + uint256 maxOperatorCount, + IStrategy[] memory strategies + ) external { + // read the json file + string memory inputConfig = vm.readFile(inputConfigPath); + bytes memory data = vm.parseJson(inputConfig); + EigenlayerDeployment memory eigenlayerDeployment = abi.decode(data, (EigenlayerDeployment)); + + emit log_named_address("delegation manager", eigenlayerDeployment.delegationManager); + emit log_named_address("avs directory", eigenlayerDeployment.avsDirectory); + emit log_named_address("rewards coordinator", eigenlayerDeployment.rewardsCoordinator); + + // only a lower bound for the deployment block number + uint256 deploymentBlock = block.number; + vm.startBroadcast(); + // deploy proxy admin for ability to upgrade proxy contracts + avsProxyAdmin = new ProxyAdmin(); + + // deploy pauser registry + { + address[] memory pausers = new address[](1); + pausers[0] = msg.sender; + avsPauserReg = new PauserRegistry(pausers, msg.sender); + } + + emptyContract = new EmptyContract(); + + // Deploy upgradeable proxy contracts pointing to empty contract initially + serviceManager = ServiceManagerBase( + address(new TransparentUpgradeableProxy(address(emptyContract), address(avsProxyAdmin), "")) + ); + + certificateVerifier = MinimalCertificateVerifier( + address(new TransparentUpgradeableProxy(address(emptyContract), address(avsProxyAdmin), "")) + ); + + registryCoordinator = RegistryCoordinator( + address(new TransparentUpgradeableProxy(address(emptyContract), address(avsProxyAdmin), "")) + ); + + indexRegistry = IIndexRegistry( + address(new TransparentUpgradeableProxy(address(emptyContract), address(avsProxyAdmin), "")) + ); + + stakeRegistry = IStakeRegistry( + address(new TransparentUpgradeableProxy(address(emptyContract), address(avsProxyAdmin), "")) + ); + + apkRegistry = BLSApkRegistry( + address(new TransparentUpgradeableProxy(address(emptyContract), address(avsProxyAdmin), "")) + ); + + socketRegistry = ISocketRegistry( + address(new TransparentUpgradeableProxy(address(emptyContract), address(avsProxyAdmin), "")) + ); + + // Deploy implementations and upgrade proxies + indexRegistryImplementation = new IndexRegistry( + registryCoordinator + ); + + avsProxyAdmin.upgrade( + ITransparentUpgradeableProxy(payable(address(indexRegistry))), + address(indexRegistryImplementation) + ); + + stakeRegistryImplementation = new StakeRegistry( + registryCoordinator, + IDelegationManager(eigenlayerDeployment.delegationManager) + ); + + avsProxyAdmin.upgrade( + ITransparentUpgradeableProxy(payable(address(stakeRegistry))), + address(stakeRegistryImplementation) + ); + + apkRegistryImplementation = new BLSApkRegistry( + registryCoordinator + ); + + avsProxyAdmin.upgrade( + ITransparentUpgradeableProxy(payable(address(apkRegistry))), + address(apkRegistryImplementation) + ); + + socketRegistryImplementation = new SocketRegistry(registryCoordinator); + + avsProxyAdmin.upgrade( + ITransparentUpgradeableProxy(payable(address(socketRegistry))), + address(socketRegistryImplementation) + ); + + registryCoordinatorImplementation = new RegistryCoordinator( + IServiceManager(address(serviceManager)), + stakeRegistry, + apkRegistry, + indexRegistry, + socketRegistry + ); + + { + IRegistryCoordinator.OperatorSetParam[] memory operatorSetParams = new IRegistryCoordinator.OperatorSetParam[](strategies.length); + for (uint i = 0; i < strategies.length; i++) { + operatorSetParams[i] = IRegistryCoordinator.OperatorSetParam({ + maxOperatorCount: uint32(maxOperatorCount), + kickBIPsOfOperatorStake: 11000, + kickBIPsOfTotalStake: 1001 + }); + } + + uint96[] memory minimumStakeForQuourm = new uint96[](strategies.length); + for (uint i = 0; i < strategies.length; i++) { + minimumStakeForQuourm[i] = 1; + } + IStakeRegistry.StrategyParams[][] memory strategyAndWeightingMultipliers = new IStakeRegistry.StrategyParams[][](strategies.length); + for (uint i = 0; i < strategies.length; i++) { + strategyAndWeightingMultipliers[i] = new IStakeRegistry.StrategyParams[](1); + strategyAndWeightingMultipliers[i][0] = IStakeRegistry.StrategyParams({ + strategy: strategies[i], + multiplier: 1 ether + }); + } + + avsProxyAdmin.upgradeAndCall( + ITransparentUpgradeableProxy(payable(address(registryCoordinator))), + address(registryCoordinatorImplementation), + abi.encodeWithSelector( + RegistryCoordinator.initialize.selector, + msg.sender, + msg.sender, + msg.sender, + IPauserRegistry(address(avsPauserReg)), + 0, // initial paused status + operatorSetParams, + minimumStakeForQuourm, + strategyAndWeightingMultipliers + ) + ); + } + + serviceManagerImplementation = new MinimalServiceManager( + IAVSDirectory(eigenlayerDeployment.avsDirectory), + IRewardsCoordinator(eigenlayerDeployment.rewardsCoordinator), + IRegistryCoordinator(address(registryCoordinator)), + IStakeRegistry(address(stakeRegistry)) + ); + + // Initialize ServiceManagerBase + avsProxyAdmin.upgradeAndCall( + ITransparentUpgradeableProxy(payable(address(serviceManager))), + address(serviceManagerImplementation), + abi.encodeWithSelector( + MinimalServiceManager.initialize.selector, + msg.sender, + msg.sender + ) + ); + + certificateVerifierImplementation = new MinimalCertificateVerifier( + registryCoordinator + ); + + avsProxyAdmin.upgrade( + ITransparentUpgradeableProxy(payable(address(certificateVerifier))), + address(certificateVerifierImplementation) + ); + + operatorStateRetriever = new OperatorStateRetriever(); + + vm.stopBroadcast(); + + string memory output = "deployment"; + vm.serializeAddress(output, "serviceManager", address(serviceManager)); + vm.serializeAddress(output, "certificateVerifier", address(certificateVerifier)); + vm.serializeAddress(output, "registryCoordinator", address(registryCoordinator)); + vm.serializeAddress(output, "indexRegistry", address(indexRegistry)); + vm.serializeAddress(output, "stakeRegistry", address(stakeRegistry)); + vm.serializeAddress(output, "apkRegistry", address(apkRegistry)); + vm.serializeAddress(output, "socketRegistry", address(socketRegistry)); + vm.serializeAddress(output, "operatorStateRetriever", address(operatorStateRetriever)); + vm.serializeAddress(output, "avsProxyAdmin", address(avsProxyAdmin)); + vm.serializeAddress(output, "avsPauserReg", address(avsPauserReg)); + vm.serializeUint(output, "deploymentBlock", deploymentBlock); + + string memory finalJson = vm.serializeString(output, "object", output); + + vm.createDir("./script/output", true); + vm.writeJson(finalJson, "./script/output/avs_deploy_output.json"); + } +} diff --git a/example/contracts/script/input/testnet.json b/example/contracts/script/input/testnet.json new file mode 100644 index 0000000..7a93260 --- /dev/null +++ b/example/contracts/script/input/testnet.json @@ -0,0 +1,7 @@ +{ + "strategyManager": "0xdfB5f6CE42aAA7830E94ECFCcAd411beF4d4D5b6", + "delegationManager": "0xA44151489861Fe9e3055d95adC98FbD462B948e7", + "avsDirectory": "0x055733000064333CaDDbC92763c58BF0192fFeBf", + "rewardsCoordinator": "0xAcc1fb458a1317E886dB376Fc8141540537E68fE", + "permissionsController": "0x598cb226B591155F767dA17AfE7A2241a68C5C10" +} \ No newline at end of file diff --git a/example/contracts/script/output/avs_deploy_output.json b/example/contracts/script/output/avs_deploy_output.json new file mode 100644 index 0000000..0cd80c9 --- /dev/null +++ b/example/contracts/script/output/avs_deploy_output.json @@ -0,0 +1,14 @@ +{ + "apkRegistry": "0x4CF2160928A4a353Cf0212EF953ee2Dc3d9F7e0B", + "avsPauserReg": "0xd9E7CEf66490Ce34EBE71d66036079e7A85790AE", + "avsProxyAdmin": "0x80Ee00FAE33ff8a16D7E094E11ff597f651ECF94", + "certificateVerifier": "0x035f01335d77c5c13cd477F5AD6518d3c50E4e68", + "deploymentBlock": 3199379, + "indexRegistry": "0x86650A65876E1e01b3EB39519f1EA5a517475B05", + "object": "deployment", + "operatorStateRetriever": "0x9aEBe2bd3384D30704b906a2728218242F3d39c0", + "registryCoordinator": "0xB8b2B243DDc1C66e9cE85f3bC76759a250b6c32A", + "serviceManager": "0x626F36f2dA0EF56d444cfa972e8E17305d814Aa1", + "socketRegistry": "0x45a1688085a6E00044B6B13Ccb0Cffe5957394aB", + "stakeRegistry": "0xC1F5ca8E62ed7c9EF6cE872888CE4ac92F20f30B" +} \ No newline at end of file diff --git a/example/contracts/src/MinimalCertificateVerifier.sol b/example/contracts/src/MinimalCertificateVerifier.sol new file mode 100644 index 0000000..d2f76db --- /dev/null +++ b/example/contracts/src/MinimalCertificateVerifier.sol @@ -0,0 +1,66 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.12; + +import {BLSSignatureChecker} from "eigenlayer-middleware/BLSSignatureChecker.sol"; +import {IRegistryCoordinator} from "eigenlayer-middleware/interfaces/IRegistryCoordinator.sol"; + +contract MinimalCertificateVerifier is BLSSignatureChecker { + + // CONSTANTS + uint256 public constant DENOMINATOR = 1e18; + uint256 public constant THRESHOLD = DENOMINATOR / 2; + + // STORAGE + struct VerificationRecord { + bytes quorumNumbers; + uint32 referenceBlockNumber; + bytes32 signatoryRecordHash; + QuorumStakeTotals quorumStakeTotals; + } + + mapping(bytes32 => VerificationRecord) public verificationRecords; + + constructor( + IRegistryCoordinator __registryCoordinator + ) + BLSSignatureChecker(__registryCoordinator) + { } + + function verifyCertificate( + bytes calldata response, + bytes calldata quorumNumbers, + uint32 referenceBlockNumber, + NonSignerStakesAndSignature calldata params + ) external { + bytes32 responseHash = keccak256(response); + require( + verificationRecords[responseHash].referenceBlockNumber == 0, + "Certificate already verified" + ); + + ( + QuorumStakeTotals memory quorumStakeTotals, + bytes32 signatoryRecordHash + ) = checkSignatures( + responseHash, + quorumNumbers, // use list of uint8s instead of uint256 bitmap to not iterate 256 times + referenceBlockNumber, + params + ); + + for (uint256 i = 0; i < quorumStakeTotals.signedStakeForQuorum.length; i++) { + require( + quorumStakeTotals.signedStakeForQuorum[i] * DENOMINATOR > + quorumStakeTotals.totalStakeForQuorum[i] * THRESHOLD, + "Threshold not met" + ); + } + + verificationRecords[responseHash] = VerificationRecord( + quorumNumbers, + referenceBlockNumber, + signatoryRecordHash, + quorumStakeTotals + ); + } +} diff --git a/example/contracts/src/MinimalServiceManager.sol b/example/contracts/src/MinimalServiceManager.sol new file mode 100644 index 0000000..3bcb243 --- /dev/null +++ b/example/contracts/src/MinimalServiceManager.sol @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.12; + +import {ServiceManagerBase, IAVSDirectory, IRewardsCoordinator, IServiceManager} from "eigenlayer-middleware/ServiceManagerBase.sol"; +import {IRegistryCoordinator} from "eigenlayer-middleware/interfaces/IRegistryCoordinator.sol"; +import {IStakeRegistry} from "eigenlayer-middleware/interfaces/IStakeRegistry.sol"; + +contract MinimalServiceManager is ServiceManagerBase { + constructor( + IAVSDirectory __avsDirectory, + IRewardsCoordinator __rewardsCoordinator, + IRegistryCoordinator __registryCoordinator, + IStakeRegistry __stakeRegistry + ) + ServiceManagerBase( + __avsDirectory, + __rewardsCoordinator, + __registryCoordinator, + __stakeRegistry + ) + { } + + function initialize( + address initialOwner, + address _rewardsInitiator + ) external initializer { + __ServiceManagerBase_init(initialOwner, _rewardsInitiator); + } +} diff --git a/example/node/cmd/main.go b/example/node/cmd/main.go new file mode 100644 index 0000000..3bc8e7a --- /dev/null +++ b/example/node/cmd/main.go @@ -0,0 +1,59 @@ +package main + +import ( + "log" + "os" + + "github.com/Layr-Labs/teal/example/node" + "github.com/Layr-Labs/teal/example/utils" + "github.com/Layr-Labs/teal/node/server" + "github.com/urfave/cli/v2" +) + +var ( + ServicePortFlag = cli.IntFlag{ + Name: "service-port", + Usage: "The port to serve the service on", + Value: 8080, + } + BlsPrivateKeyFlag = cli.StringFlag{ + Name: "bls-private-key", + Usage: "The private key to use for the node", + Value: "", + Required: true, + } +) + +func main() { + app := cli.NewApp() + app.Name = "eth_call_node" + app.Usage = "xyz" + app.Version = "0.0.1" + + app.Flags = []cli.Flag{ + &utils.EthUrlFlag, + &ServicePortFlag, + &BlsPrivateKeyFlag, + } + + app.Action = start + + if err := app.Run(os.Args); err != nil { + log.Fatal(err) + } +} + +func start(c *cli.Context) error { + keyPair := utils.NewBlsKeyPairPanics(c.String(BlsPrivateKeyFlag.Name)) + + cfg := server.Config{ + ServicePort: c.Int(ServicePortFlag.Name), + BlsKeyPair: keyPair, + } + + node := node.NewEthCallNode(cfg, c.String(utils.EthUrlFlag.Name)) + if err := node.Start(); err != nil { + log.Fatal(err) + } + return nil +} diff --git a/example/node/eth_call.go b/example/node/eth_call.go new file mode 100644 index 0000000..8f1c7d9 --- /dev/null +++ b/example/node/eth_call.go @@ -0,0 +1,71 @@ +package node + +import ( + "context" + "fmt" + "math/big" + + "github.com/Layr-Labs/teal/example/utils" + "github.com/Layr-Labs/teal/node/server" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/ethclient" +) + +const ( + MaxDataSize = 128000 + MaxGas = 30000000 + MinBlockDepth = 100 + MaxBlockDepth = 10000 +) + +type EthCallNode struct { + *server.BaseNode + ethClient *ethclient.Client +} + +func NewEthCallNode(nodeConfig server.Config, rpcUrl string) *EthCallNode { + node := &EthCallNode{} + node.BaseNode = server.NewBaseNode(nodeConfig, node) + + ethClient, err := ethclient.Dial(rpcUrl) + if err != nil { + panic(err) + } + node.ethClient = ethClient + + return node +} + +func (n *EthCallNode) GetResponse(nodeConfig server.Config, data []byte) ([]byte, error) { + if len(data) < utils.MinDataSize { + return nil, fmt.Errorf("data too short") + } + + if len(data) > MaxDataSize { + return nil, fmt.Errorf("data too long") + } + + currBlockNumber, err := n.ethClient.BlockNumber(context.Background()) + if err != nil { + return nil, fmt.Errorf("failed to get current block number: %w", err) + } + + // next bytes are the call msg + blockNumber, callMsg := utils.CallFromBytes(data) + if blockNumber+MinBlockDepth > currBlockNumber || blockNumber+MaxBlockDepth < currBlockNumber { + return nil, fmt.Errorf("block number out of range") + } + if callMsg.Gas > MaxGas { + return nil, fmt.Errorf("gas too high") + } + + returnData, err := n.ethClient.CallContract(context.Background(), callMsg, big.NewInt(int64(blockNumber))) + if err != nil { + return nil, fmt.Errorf("failed to call contract: %w", err) + } + + // summarise request and return data and return response! + requestDataHash := crypto.Keccak256(data) + returnDataHash := crypto.Keccak256(returnData) + return crypto.Keccak256(append(requestDataHash, returnDataHash...)), nil +} diff --git a/example/scripts/acquire_and_deposit_steth.sh b/example/scripts/acquire_and_deposit_steth.sh new file mode 100755 index 0000000..409abff --- /dev/null +++ b/example/scripts/acquire_and_deposit_steth.sh @@ -0,0 +1,31 @@ +#!/bin/bash + +# ./acquire_and_deposit_steth.sh $ETH_RPC_URL $PRIVATE_KEY ../contracts/script/input/testnet.json 0.1ether + +ETH_RPC_URL=$1 +PRIVATE_KEY=$2 +EIGENLAYER_DEPLOYMENT_PATH=$3 +STETH_STRATEGY=0x7d704507b76571a51d9cae8addabbfd0ba0e63d3 +STETH_ADDRESS=0x3F1c547b21f65e10480dE3ad8E19fAAC46C95034 +AMOUNT_TO_DEPOSIT=$4 + +OPERATOR_ADDRESS=$(cast wallet address $PRIVATE_KEY) + +cast send --rpc-url $ETH_RPC_URL --private-key $PRIVATE_KEY $STETH_ADDRESS --value=$AMOUNT_TO_DEPOSIT +sleep 5 + + +# set +e to avoid exiting the script if the server returns null response +set +e +balance=$(cast call --rpc-url $ETH_RPC_URL $STETH_ADDRESS "balanceOf(address)(uint256)" $OPERATOR_ADDRESS) +echo "StETH Balance: $balance" +set -e + +strategyManager=$(jq -r '.strategyManager' $EIGENLAYER_DEPLOYMENT_PATH) + +cast send --rpc-url $ETH_RPC_URL --private-key $PRIVATE_KEY $STETH_ADDRESS "approve(address,uint256)" $strategyManager $balance +echo "Approved Strategy Manager" +sleep 5 + +cast send --rpc-url $ETH_RPC_URL --private-key $PRIVATE_KEY $strategyManager "depositIntoStrategy(address,address,uint256)" $STETH_STRATEGY $STETH_ADDRESS $balance +echo "Deposited StETH" diff --git a/example/scripts/init_operators.sh b/example/scripts/init_operators.sh new file mode 100755 index 0000000..942b784 --- /dev/null +++ b/example/scripts/init_operators.sh @@ -0,0 +1,46 @@ +#! /bin/bash + +# Default values +NUM_OPERATORS=1 +FUNDS_PK="" +RPC_URL="http://0.0.0.0:8545" + +# Parse named arguments +while [ $# -gt 0 ]; do + case "$1" in + --num-operators) + NUM_OPERATORS="$2" + shift 2 + ;; + --funds-pk) + FUNDS_PK="$2" + shift 2 + ;; + --rpc-url) + RPC_URL="$2" + shift 2 + ;; + --help) + echo "Usage: $0 --num-operators --funds-pk --rpc-url " + exit 0 + ;; + *) + echo "Unknown parameter: $1" + exit 1 + ;; + esac +done + +# Get the directory where the script is located +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +echo "Creating $NUM_OPERATORS operators" +START_SOCKET=8080 +if [ "$NUM_OPERATORS" -gt 0 ]; then + for i in $(seq 0 $((NUM_OPERATORS-1))); do + echo "Creating operator $i" + $SCRIPT_DIR/initialize-operator.sh --id $i --funds-pk $FUNDS_PK --rpc-url $RPC_URL --socket $START_SOCKET + START_SOCKET=$((START_SOCKET+1)) + done +else + echo "No operators to create" +fi diff --git a/example/scripts/initialize-operator.sh b/example/scripts/initialize-operator.sh new file mode 100755 index 0000000..92402d8 --- /dev/null +++ b/example/scripts/initialize-operator.sh @@ -0,0 +1,155 @@ +#! /bin/bash + +# Exit the script if any command fails +# set -e + +# Default values +ID="" +FUNDS_PK="" +RPC_URL="http://0.0.0.0:8545" +SOCKET="" +REGISTER_AVS=false + +# Parse named arguments +while [ $# -gt 0 ]; do + case "$1" in + --id) + ID="$2" + shift 2 + ;; + --funds-pk) + FUNDS_PK="$2" + shift 2 + ;; + --rpc-url) + RPC_URL="$2" + shift 2 + ;; + --socket) + SOCKET="$2" + shift 2 + ;; + --register-avs) + REGISTER_AVS=true + shift 1 + ;; + --help) + echo "Usage: $0 --id --funds-pk --rpc-url --socket " + exit 0 + ;; + *) + echo "Unknown parameter: $1" + exit 1 + ;; + esac +done + + +# Get the directory where the script is located +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + +cleanup() { + # set +e to avoid exiting the script if the rm commands fail + set +e + + echo "Cleaning up..." + rm $HOME/.eigenlayer/operator_keys/opr$ID.ecdsa.key.json + rm $HOME/.eigenlayer/operator_keys/opr$ID.bls.key.json + rm opr$ID.ecdsa.key.json + rm opr$ID.bls.key.json + rm $SCRIPT_DIR/operator$ID.yaml + + echo "Cleaning up complete" + exit $? +} + +# trap cleanup on: interruption (ctrl+c), termination, and exit +trap cleanup EXIT INT TERM + +# Validate required arguments +if [ -z "$ID" ]; then + echo "Error: --id is required" + exit 1 +fi + +if [ -z "$FUNDS_PK" ]; then + echo "Error: --funds-pk is required" + exit 1 +fi + +if [ -z "$RPC_URL" ]; then + echo "Error: --rpc-url is required" + exit 1 +fi + +if [ -z "$SOCKET" ]; then + echo "Error: --socket is required" + exit 1 +fi + +# Use the arguments +echo "ID: $ID" +echo "RPC URL: $RPC_URL" +echo "SOCKET: $SOCKET" + +# Install EigenLayer CLI usinf curl +if ! command -v $HOME/bin/eigenlayer &> /dev/null; then + echo "EigenLayer CLI is not installed" + curl -sSfL https://raw.githubusercontent.com/layr-labs/eigenlayer-cli/master/scripts/install.sh | sh -s -- -b $HOME/bin v0.12.0-beta +fi + +## Create a new ecdsa key +echo "" | $HOME/bin/eigenlayer keys create --key-type=ecdsa --insecure opr$ID > opr$ID.ecdsa.key.json +ECDSA_PRIVATE_KEY=$(grep -o "//[[:space:]]*[0-9a-f]\{64\}[[:space:]]*//" opr$ID.ecdsa.key.json | tr -d '//' | tr -d ' ') +echo "ECDSA_PRIVATE_KEY=$ECDSA_PRIVATE_KEY" + +OPERATOR_ADDRESS=$(grep -o "[[:space:]]*0x[0-9a-fA-F]\{40\}[[:space:]]*" opr$ID.ecdsa.key.json | tr -d ' ') +echo "OPERATOR_ADDRESS=$OPERATOR_ADDRESS" + +# Create a new bls key +echo "" | $HOME/bin/eigenlayer keys create --key-type=bls --insecure opr$ID > opr$ID.bls.key.json +BLS_PRIVATE_KEY=$(grep -o "//[[:space:]]*[0-9]\{50,100\}[[:space:]]*//" opr$ID.bls.key.json | tr -d '//' | tr -d ' ') +echo "BLS_PRIVATE_KEY=$BLS_PRIVATE_KEY" + +cp $SCRIPT_DIR/operator.yaml $SCRIPT_DIR/operator$ID.yaml +sed -i '' "s/address: /address: $OPERATOR_ADDRESS/" $SCRIPT_DIR/operator$ID.yaml + +echo $HOME +sed -i '' "s|private_key_store_path: |private_key_store_path: $HOME/.eigenlayer/operator_keys/opr$ID.ecdsa.key.json|" $SCRIPT_DIR/operator$ID.yaml +sed -i '' "s|eth_rpc_url: |eth_rpc_url: $RPC_URL|" $SCRIPT_DIR/operator$ID.yaml + +# Send funds to the operator +cast send $OPERATOR_ADDRESS --value 0.2ether --private-key $FUNDS_PK --rpc-url $RPC_URL + +sleep 10 +# Register the operator +echo "Registering operator..." +echo "" | $HOME/bin/eigenlayer operator register $SCRIPT_DIR/operator$ID.yaml + +sleep 10 +# Restake +echo "Restaking..." +PARENT_DIR="$SCRIPT_DIR/.." +$SCRIPT_DIR/acquire_and_deposit_steth.sh $RPC_URL $ECDSA_PRIVATE_KEY $PARENT_DIR/contracts/script/input/testnet.json 0.1ether + +# Output to json +mkdir -p $SCRIPT_DIR/operators +cat << EOF > $SCRIPT_DIR/operators/operator$ID.json +{ + "operator_address": "$OPERATOR_ADDRESS", + "ecdsa_private_key": "$ECDSA_PRIVATE_KEY", + "bls_private_key": "$BLS_PRIVATE_KEY", + "socket": "localhost:$SOCKET" +} +EOF + +if $REGISTER_AVS; then + echo "Registering operator to AVS..." + go run $SCRIPT_DIR/register.go \ + --eth-url $RPC_URL \ + --eigenlayer-deployment-path $PARENT_DIR/contracts/script/input/testnet.json \ + --avs-deployment-path $PARENT_DIR/contracts/script/output/avs_deploy_output.json \ + --ecdsa-private-key $ECDSA_PRIVATE_KEY \ + --bls-private-key $BLS_PRIVATE_KEY \ + --socket "localhost:$SOCKET" +fi diff --git a/example/scripts/operator.yaml b/example/scripts/operator.yaml new file mode 100644 index 0000000..edf002f --- /dev/null +++ b/example/scripts/operator.yaml @@ -0,0 +1,10 @@ +operator: + address: + delegation_approver_address: "0x0000000000000000000000000000000000000000" + metadata_url: "https://madhur-test-public.s3.us-east-2.amazonaws.com/metadata.json" + allocation_delay: 1200 +el_delegation_manager_address: 0xA44151489861Fe9e3055d95adC98FbD462B948e7 +eth_rpc_url: +chain_id: 17000 +private_key_store_path: +signer_type: local_keystore diff --git a/example/scripts/register.go b/example/scripts/register.go new file mode 100644 index 0000000..480049f --- /dev/null +++ b/example/scripts/register.go @@ -0,0 +1,180 @@ +package main + +import ( + "context" + "log" + "log/slog" + "os" + + "github.com/Layr-Labs/eigensdk-go/chainio/clients/avsregistry" + "github.com/Layr-Labs/eigensdk-go/chainio/clients/elcontracts" + "github.com/Layr-Labs/eigensdk-go/chainio/clients/wallet" + "github.com/Layr-Labs/eigensdk-go/chainio/txmgr" + "github.com/Layr-Labs/eigensdk-go/logging" + "github.com/Layr-Labs/eigensdk-go/metrics" + rpccalls "github.com/Layr-Labs/eigensdk-go/metrics/collectors/rpc_calls" + "github.com/Layr-Labs/eigensdk-go/signerv2" + "github.com/Layr-Labs/eigensdk-go/types" + "github.com/Layr-Labs/teal/example/utils" + + "github.com/Layr-Labs/eigensdk-go/chainio/clients/eth" + "github.com/ethereum/go-ethereum/crypto" + "github.com/prometheus/client_golang/prometheus" + "github.com/urfave/cli/v2" +) + +var ( + BlsPrivateKeyFlag = cli.StringFlag{ + Name: "bls-private-key", + Usage: "The private key to use for the node", + Value: "", + Required: true, + } + SocketFlag = cli.StringFlag{ + Name: "socket", + Usage: "The socket to use for the node", + Value: "", + Required: true, + } +) + +func main() { + app := cli.NewApp() + app.Name = "register-avs" + app.Usage = "xyz" + app.Version = "0.0.1" + + app.Flags = []cli.Flag{ + &utils.EthUrlFlag, + &utils.EigenlayerDeploymentPathFlag, + &utils.AvsDeploymentPathFlag, + &utils.EcdsaPrivateKeyFlag, + &BlsPrivateKeyFlag, + &SocketFlag, + } + + app.Action = start + + if err := app.Run(os.Args); err != nil { + log.Fatal(err) + } +} + +func start(c *cli.Context) error { + reg := prometheus.NewRegistry() + rpcCallsCollector := rpccalls.NewCollector("exampleAvs", reg) + client, err := eth.NewInstrumentedClient(c.String(utils.EthUrlFlag.Name), rpcCallsCollector) + if err != nil { + panic(err) + } + + logger := logging.NewTextSLogger(os.Stdout, &logging.SLoggerOptions{Level: slog.LevelInfo}) + + chainid, err := client.ChainID(context.Background()) + if err != nil { + panic(err) + } + + privateKeyString := c.String(utils.EcdsaPrivateKeyFlag.Name) + if privateKeyString[0:2] == "0x" { + privateKeyString = privateKeyString[2:] + } + + ecdsaPrivateKey, err := crypto.HexToECDSA(privateKeyString) + if err != nil { + panic(err) + } + + signerV2, addr, err := signerv2.SignerFromConfig(signerv2.Config{PrivateKey: ecdsaPrivateKey}, chainid) + if err != nil { + panic(err) + } + + pkWallet, err := wallet.NewPrivateKeyWallet(client, signerV2, addr, logger) + if err != nil { + panic(err) + } + + txManager := txmgr.NewSimpleTxManager( + pkWallet, + client, + logger, + addr, + ) + + met := metrics.NewEigenMetrics("example", "9000", reg, logger) + + elConfig, err := utils.ReadEigenlayerDeployment(c.String(utils.EigenlayerDeploymentPathFlag.Name)) + if err != nil { + panic(err) + } + + avsDeployment, err := utils.ReadAVSDeployment(c.String(utils.AvsDeploymentPathFlag.Name)) + if err != nil { + panic(err) + } + + elReader, err := elcontracts.NewReaderFromConfig(elConfig, client, logger) + if err != nil { + panic(err) + } + + elWriter, err := elcontracts.NewWriterFromConfig(elConfig, client, logger, met, txManager) + if err != nil { + panic(err) + } + + operator := types.Operator{ + Address: addr.String(), + MetadataUrl: "https://example.com", + DelegationApproverAddress: "0x0000000000000000000000000000000000000000", + AllocationDelay: 0, + } + + isRegisteredWithEL, err := elReader.IsOperatorRegistered(context.Background(), operator) + if err != nil { + panic(err) + } + + if !isRegisteredWithEL { + reciept, err := elWriter.RegisterAsOperator(context.Background(), operator, true) + if err != nil { + panic(err) + } + + if reciept.Status == 0 { + logger.Error("Failed to register operator with EigenLayer", "receipt", reciept) + } else { + logger.Info("Registered operator with EigenLayer", "tx", reciept.TxHash.Hex()) + } + } + + avsWriter, err := avsregistry.NewWriterFromConfig( + avsDeployment.ToConfig(), + client, + txManager, + logger, + ) + if err != nil { + panic(err) + } + + reciept, err := avsWriter.RegisterOperator( + context.Background(), + ecdsaPrivateKey, + utils.NewBlsKeyPairPanics(c.String(BlsPrivateKeyFlag.Name)), + types.QuorumNums{0}, + c.String(SocketFlag.Name), + true, + ) + if err != nil { + panic(err) + } + + if reciept.Status == 0 { + logger.Error("Failed to register operator with AVS", "receipt", reciept) + } else { + logger.Info("Registered operator with AVS", "tx", reciept.TxHash.Hex()) + } + return nil +} diff --git a/example/scripts/register_operator_avs.sh b/example/scripts/register_operator_avs.sh new file mode 100755 index 0000000..a540e8e --- /dev/null +++ b/example/scripts/register_operator_avs.sh @@ -0,0 +1,58 @@ +#! /bin/bash + +set -e + +# Default values +RPC_URL="http://0.0.0.0:8545" + + +# Parse named arguments +while [ $# -gt 0 ]; do + case "$1" in + --rpc-url) + RPC_URL="$2" + shift 2 + ;; + --help) + echo "Usage: $0 --rpc-url " + exit 0 + ;; + *) + echo "Unknown parameter: $1" + exit 1 + ;; + esac +done + +if [ -z "$RPC_URL" ]; then + echo "Error: --rpc-url is required" + exit 1 +fi + +echo "Registering operator to AVS with RPC URL $RPC_URL" + +# Get the directory where the script is located +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + +# Build the nodes +PARENT_DIR=$SCRIPT_DIR/.. + +for file in $SCRIPT_DIR/operators/*.json; do + echo "Starting node from $file" + if [ -r "$file" ]; then + BLS_PRIVATE_KEY=$(jq -r '.bls_private_key' $file) + ECDSA_PRIVATE_KEY=$(jq -r '.ecdsa_private_key' $file) + SOCKET=$(jq -r '.socket' $file) + PORT=$(echo $SOCKET | cut -d ':' -f 2) + echo "Registering operator to AVS with BLS private key $BLS_PRIVATE_KEY, ECDSA private key $ECDSA_PRIVATE_KEY, socket $SOCKET" + go run $SCRIPT_DIR/register.go \ + --eth-url $RPC_URL \ + --eigenlayer-deployment-path $PARENT_DIR/contracts/script/input/testnet.json \ + --avs-deployment-path $PARENT_DIR/contracts/script/output/avs_deploy_output.json \ + --ecdsa-private-key $ECDSA_PRIVATE_KEY \ + --bls-private-key $BLS_PRIVATE_KEY \ + --socket "$SOCKET" + else + echo "File $file is not readable" + fi +done \ No newline at end of file diff --git a/example/scripts/start_aggregator.sh b/example/scripts/start_aggregator.sh new file mode 100755 index 0000000..8c1134c --- /dev/null +++ b/example/scripts/start_aggregator.sh @@ -0,0 +1,51 @@ +#! /bin/bash + +set -e + +# Default values +RPC_URL="http://0.0.0.0:8545" +PRIVATE_KEY="" + + +# Parse named arguments +while [ $# -gt 0 ]; do + case "$1" in + --rpc-url) + RPC_URL="$2" + shift 2 + ;; + --private-key) + PRIVATE_KEY="$2" + shift 2 + ;; + --help) + echo "Usage: $0 --rpc-url --private-key " + exit 0 + ;; + *) + echo "Unknown parameter: $1" + exit 1 + ;; + esac +done + +if [ -z "$RPC_URL" ]; then + echo "Error: --rpc-url is required" + exit 1 +fi + +if [ -z "$PRIVATE_KEY" ]; then + echo "Error: --private-key is required" + exit 1 +fi + +# Get the directory where the script is located +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + +# Build the nodes +PARENT_DIR=$SCRIPT_DIR/.. + +go run $PARENT_DIR/aggregator/eth_call.go \ + --eth-url $RPC_URL \ + --avs-deployment-path $PARENT_DIR/contracts/script/output/avs_deploy_output.json \ + --ecdsa-private-key $PRIVATE_KEY \ No newline at end of file diff --git a/example/scripts/start_nodes.sh b/example/scripts/start_nodes.sh new file mode 100755 index 0000000..0721fb1 --- /dev/null +++ b/example/scripts/start_nodes.sh @@ -0,0 +1,80 @@ +#!/bin/bash + +set -e + +# Default values +RPC_URL="http://0.0.0.0:8545" + + +# Parse named arguments +while [ $# -gt 0 ]; do + case "$1" in + --rpc-url) + RPC_URL="$2" + shift 2 + ;; + --help) + echo "Usage: $0 --rpc-url " + exit 0 + ;; + *) + echo "Unknown parameter: $1" + exit 1 + ;; + esac +done + +declare -a PIDS=() + +# Get the directory where the script is located +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + +# Build the nodes +PARENT_DIR=$SCRIPT_DIR/.. +go build -o $PARENT_DIR/bin/node $PARENT_DIR/node/cmd/main.go + +for file in $SCRIPT_DIR/operators/*.json; do + echo "Starting node from $file" + if [ -r "$file" ]; then + BLS_PRIVATE_KEY=$(jq -r '.bls_private_key' $file) + ECDSA_PRIVATE_KEY=$(jq -r '.ecdsa_private_key' $file) + SOCKET=$(jq -r '.socket' $file) + PORT=$(echo $SOCKET | cut -d ':' -f 2) + echo "Starting node with BLS private key $BLS_PRIVATE_KEY, ECDSA private key $ECDSA_PRIVATE_KEY, socket $SOCKET, and port $PORT" + $PARENT_DIR/bin/node --bls-private-key $BLS_PRIVATE_KEY --service-port $PORT --eth-url $RPC_URL & PIDS+=($!) + else + echo "File $file is not readable" + fi +done + +# Save PIDs to a file for later reference +echo "${PIDS[@]}" > /tmp/teal_pids.txt + +# Function to check if all processes are running +check_processes() { + for pid in "${PIDS[@]}"; do + if ! kill -0 "$pid" 2>/dev/null; then + echo "Process $pid has died" + exit 1 + fi + done +} + +echo "Nodes started with PIDs: ${PIDS[@]}" + +# Cleanup function +cleanup() { + echo "Stopping all processes..." + for pid in "${PIDS[@]}"; do + kill "$pid" 2>/dev/null || true + done + rm -f /tmp/teal_pids.txt +} + +trap cleanup EXIT INT TERM + +# Keep script running and monitoring processes +while true; do + check_processes + sleep 5 +done \ No newline at end of file diff --git a/example/utils/deployment.go b/example/utils/deployment.go new file mode 100644 index 0000000..50e6c91 --- /dev/null +++ b/example/utils/deployment.go @@ -0,0 +1,70 @@ +package utils + +import ( + "encoding/json" + "os" + + "github.com/Layr-Labs/eigensdk-go/chainio/clients/avsregistry" + "github.com/Layr-Labs/eigensdk-go/chainio/clients/elcontracts" + "github.com/ethereum/go-ethereum/common" +) + +type EigenLayerDeployment struct { + DelegationManager common.Address `json:"delegationManager"` + AvsDirectory common.Address `json:"avsDirectory"` + RewardsCoordinator common.Address `json:"rewardsCoordinator"` + PermissionsController common.Address `json:"permissionsController"` +} + +type AVSDeployment struct { + DeploymentBlock uint64 `json:"deploymentBlock"` + CertificateVerifier common.Address `json:"certificateVerifier"` + RegistryCoordinator common.Address `json:"registryCoordinator"` + OperatorStateRetriever common.Address `json:"operatorStateRetriever"` +} + +func ReadEigenlayerDeployment(path string) (elcontracts.Config, error) { + // read the json file + jsonFile, err := os.Open(path) + if err != nil { + return elcontracts.Config{}, err + } + defer jsonFile.Close() + + // parse the json file + var deployment EigenLayerDeployment + err = json.NewDecoder(jsonFile).Decode(&deployment) + if err != nil { + return elcontracts.Config{}, err + } + return elcontracts.Config{ + DelegationManagerAddress: deployment.DelegationManager, + AvsDirectoryAddress: deployment.AvsDirectory, + RewardsCoordinatorAddress: deployment.RewardsCoordinator, + PermissionsControllerAddress: deployment.PermissionsController, + }, nil +} + +func ReadAVSDeployment(path string) (AVSDeployment, error) { + // read the json file + jsonFile, err := os.Open(path) + if err != nil { + return AVSDeployment{}, err + } + defer jsonFile.Close() + + // parse the json file + var deployment AVSDeployment + err = json.NewDecoder(jsonFile).Decode(&deployment) + if err != nil { + return AVSDeployment{}, err + } + return deployment, nil +} + +func (d AVSDeployment) ToConfig() avsregistry.Config { + return avsregistry.Config{ + RegistryCoordinatorAddress: d.RegistryCoordinator, + OperatorStateRetrieverAddress: d.OperatorStateRetriever, + } +} diff --git a/example/utils/eth_call.go b/example/utils/eth_call.go new file mode 100644 index 0000000..171e20e --- /dev/null +++ b/example/utils/eth_call.go @@ -0,0 +1,44 @@ +package utils + +import ( + "encoding/binary" + "math/big" + + "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/common" +) + +const ( + MinDataSize = 96 +) + +func CallFromBytes(data []byte) (uint64, ethereum.CallMsg) { + blockNumber := binary.BigEndian.Uint64(data[:8]) + from := common.BytesToAddress(data[8:28]) + to := common.BytesToAddress(data[28:48]) + gas := binary.BigEndian.Uint64(data[48:56]) + gasPrice := new(big.Int).SetBytes(data[56:64]) + value := new(big.Int).SetBytes(data[64:96]) + calldata := data[96:] + + return blockNumber, ethereum.CallMsg{ + From: from, + To: &to, + Gas: gas, + GasPrice: gasPrice, + Value: value, + Data: calldata, + } +} + +func CallToBytes(blockNumber uint64, callMsg ethereum.CallMsg) []byte { + data := make([]byte, 96+len(callMsg.Data)) + binary.BigEndian.PutUint64(data[:8], blockNumber) + copy(data[8:28], callMsg.From.Bytes()) + copy(data[28:48], callMsg.To.Bytes()) + binary.BigEndian.PutUint64(data[48:56], callMsg.Gas) + copy(data[56:64], callMsg.GasPrice.Bytes()) + copy(data[64:96], callMsg.Value.Bytes()) + copy(data[96:], callMsg.Data) + return data +} diff --git a/example/utils/flags.go b/example/utils/flags.go new file mode 100644 index 0000000..b6634a1 --- /dev/null +++ b/example/utils/flags.go @@ -0,0 +1,32 @@ +package utils + +import ( + "github.com/urfave/cli/v2" +) + +var ( + EthUrlFlag = cli.StringFlag{ + Name: "eth-url", + Usage: "The URL of the Ethereum node", + Value: "", + Required: true, + } + EigenlayerDeploymentPathFlag = cli.StringFlag{ + Name: "eigenlayer-deployment-path", + Usage: "The path to the eigenlayer deployment", + Value: "", + Required: true, + } + AvsDeploymentPathFlag = cli.StringFlag{ + Name: "avs-deployment-path", + Usage: "The path to the avs deployment", + Value: "", + Required: true, + } + EcdsaPrivateKeyFlag = cli.StringFlag{ + Name: "ecdsa-private-key", + Usage: "The private key to use for the node", + Value: "", + Required: true, + } +) diff --git a/example/utils/utils.go b/example/utils/utils.go new file mode 100644 index 0000000..688c7dd --- /dev/null +++ b/example/utils/utils.go @@ -0,0 +1,46 @@ +package utils + +import ( + "math/big" + + "github.com/Layr-Labs/eigensdk-go/crypto/bls" + minimalCertificateVerifier "github.com/Layr-Labs/teal/example/contracts/bindings/MinimalCertificateVerifier" +) + +func NewBlsKeyPairPanics(privateKey string) *bls.KeyPair { + kp, err := bls.NewKeyPairFromString(privateKey) + if err != nil { + panic(err) + } + return kp +} + +func ToBN254G1Points(ps []*bls.G1Point) []minimalCertificateVerifier.BN254G1Point { + points := make([]minimalCertificateVerifier.BN254G1Point, len(ps)) + for i, p := range ps { + points[i] = ToBN254G1Point(p) + } + return points +} + +func ToBN254G1Point(p *bls.G1Point) minimalCertificateVerifier.BN254G1Point { + return minimalCertificateVerifier.BN254G1Point{ + X: p.X.BigInt(new(big.Int)), + Y: p.Y.BigInt(new(big.Int)), + } +} + +func ToBN254G2Points(ps []*bls.G2Point) []minimalCertificateVerifier.BN254G2Point { + points := make([]minimalCertificateVerifier.BN254G2Point, len(ps)) + for i, p := range ps { + points[i] = ToBN254G2Point(p) + } + return points +} + +func ToBN254G2Point(p *bls.G2Point) minimalCertificateVerifier.BN254G2Point { + return minimalCertificateVerifier.BN254G2Point{ + X: [2]*big.Int{p.X.A1.BigInt(new(big.Int)), p.X.A0.BigInt(new(big.Int))}, + Y: [2]*big.Int{p.Y.A1.BigInt(new(big.Int)), p.Y.A0.BigInt(new(big.Int))}, + } +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..1985143 --- /dev/null +++ b/go.mod @@ -0,0 +1,115 @@ +module github.com/Layr-Labs/teal + +go 1.22.3 + +require ( + github.com/Layr-Labs/eigensdk-go v0.2.0-beta.1.0.20250121160212-04449ff5cb25 + github.com/ethereum/go-ethereum v1.14.0 + github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1 + github.com/prometheus/client_golang v1.19.0 + github.com/stretchr/testify v1.9.0 + github.com/urfave/cli/v2 v2.27.5 + go.uber.org/mock v0.4.0 + google.golang.org/grpc v1.69.4 + google.golang.org/protobuf v1.36.3 +) + +require ( + dario.cat/mergo v1.0.0 // indirect + github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect + github.com/Microsoft/go-winio v0.6.1 // indirect + github.com/Microsoft/hcsshim v0.11.4 // indirect + github.com/StackExchange/wmi v1.2.1 // indirect + github.com/aws/aws-sdk-go-v2 v1.26.1 // indirect + github.com/aws/aws-sdk-go-v2/config v1.27.11 // indirect + github.com/aws/aws-sdk-go-v2/credentials v1.17.11 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.1 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.5 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.5 // indirect + github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.2 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.7 // indirect + github.com/aws/aws-sdk-go-v2/service/kms v1.31.0 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.20.5 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.23.4 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.28.6 // indirect + github.com/aws/smithy-go v1.20.2 // indirect + github.com/beorn7/perks v1.0.1 // indirect + github.com/bits-and-blooms/bitset v1.10.0 // indirect + github.com/btcsuite/btcd/btcec/v2 v2.2.0 // indirect + github.com/cenkalti/backoff/v4 v4.3.0 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect + github.com/consensys/bavard v0.1.13 // indirect + github.com/consensys/gnark-crypto v0.12.1 // indirect + github.com/containerd/containerd v1.7.12 // indirect + github.com/containerd/log v0.1.0 // indirect + github.com/cpuguy83/dockercfg v0.3.1 // indirect + github.com/cpuguy83/go-md2man/v2 v2.0.5 // indirect + github.com/crate-crypto/go-kzg-4844 v1.0.0 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/deckarep/golang-set/v2 v2.1.0 // indirect + github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect + github.com/distribution/reference v0.5.0 // indirect + github.com/docker/docker v25.0.6+incompatible // indirect + github.com/docker/go-connections v0.5.0 // indirect + github.com/docker/go-units v0.5.0 // indirect + github.com/ethereum/c-kzg-4844 v1.0.0 // indirect + github.com/felixge/httpsnoop v1.0.4 // indirect + github.com/fsnotify/fsnotify v1.6.0 // indirect + github.com/go-logr/logr v1.4.2 // indirect + github.com/go-logr/stdr v1.2.2 // indirect + github.com/go-ole/go-ole v1.3.0 // indirect + github.com/gogo/protobuf v1.3.2 // indirect + github.com/golang-jwt/jwt v3.2.2+incompatible // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/gorilla/websocket v1.4.2 // indirect + github.com/holiman/uint256 v1.2.4 // indirect + github.com/klauspost/compress v1.16.0 // indirect + github.com/lmittmann/tint v1.0.4 // indirect + github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect + github.com/magiconair/properties v1.8.7 // indirect + github.com/mmcloughlin/addchain v0.4.0 // indirect + github.com/moby/patternmatcher v0.6.0 // indirect + github.com/moby/sys/sequential v0.5.0 // indirect + github.com/moby/sys/user v0.1.0 // indirect + github.com/moby/term v0.5.0 // indirect + github.com/morikuni/aec v1.0.0 // indirect + github.com/opencontainers/go-digest v1.0.0 // indirect + github.com/opencontainers/image-spec v1.1.0 // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect + github.com/prometheus/client_model v0.5.0 // indirect + github.com/prometheus/common v0.48.0 // indirect + github.com/prometheus/procfs v0.12.0 // indirect + github.com/russross/blackfriday/v2 v2.1.0 // indirect + github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible // indirect + github.com/shirou/gopsutil/v3 v3.23.12 // indirect + github.com/shoenig/go-m1cpu v0.1.6 // indirect + github.com/shurcooL/graphql v0.0.0-20230722043721-ed46e5a46466 // indirect + github.com/sirupsen/logrus v1.9.3 // indirect + github.com/supranational/blst v0.3.11 // indirect + github.com/testcontainers/testcontainers-go v0.30.0 // indirect + github.com/tklauser/go-sysconf v0.3.12 // indirect + github.com/tklauser/numcpus v0.6.1 // indirect + github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect + github.com/yusufpapurcu/wmi v1.2.3 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 // indirect + go.opentelemetry.io/otel v1.31.0 // indirect + go.opentelemetry.io/otel/metric v1.31.0 // indirect + go.opentelemetry.io/otel/trace v1.31.0 // indirect + go.uber.org/multierr v1.11.0 // indirect + go.uber.org/zap v1.27.0 // indirect + golang.org/x/crypto v0.31.0 // indirect + golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa // indirect + golang.org/x/mod v0.17.0 // indirect + golang.org/x/net v0.33.0 // indirect + golang.org/x/sync v0.10.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect + golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20241219192143-6b3ec007d9bb // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20241219192143-6b3ec007d9bb // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + rsc.io/tmplfunc v0.0.3 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..8405fcb --- /dev/null +++ b/go.sum @@ -0,0 +1,379 @@ +dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= +dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= +github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 h1:bvDV9vkmnHYOMsOr4WLk+Vo07yKIzd94sVoIqshQ4bU= +github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8= +github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= +github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= +github.com/DataDog/zstd v1.4.5 h1:EndNeuB0l9syBZhut0wns3gV1hL8zX8LIu6ZiVHWLIQ= +github.com/DataDog/zstd v1.4.5/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= +github.com/Layr-Labs/eigensdk-go v0.2.0-beta.1.0.20250121160212-04449ff5cb25 h1:CbiEmXBWGdCo8h2GrRRQ0Z9EMx5MQ4ozE35PXaAAaDg= +github.com/Layr-Labs/eigensdk-go v0.2.0-beta.1.0.20250121160212-04449ff5cb25/go.mod h1:YNzORpoebdDNv0sJLm/H9LTx72M85zA54eBSXI5DULw= +github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= +github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= +github.com/Microsoft/hcsshim v0.11.4 h1:68vKo2VN8DE9AdN4tnkWnmdhqdbpUFM8OF3Airm7fz8= +github.com/Microsoft/hcsshim v0.11.4/go.mod h1:smjE4dvqPX9Zldna+t5FG3rnoHhaB7QYxPRqGcpAD9w= +github.com/StackExchange/wmi v1.2.1 h1:VIkavFPXSjcnS+O8yTq7NI32k0R5Aj+v39y29VYDOSA= +github.com/StackExchange/wmi v1.2.1/go.mod h1:rcmrprowKIVzvc+NUiLncP2uuArMWLCbu9SBzvHz7e8= +github.com/VictoriaMetrics/fastcache v1.12.1 h1:i0mICQuojGDL3KblA7wUNlY5lOK6a4bwt3uRKnkZU40= +github.com/VictoriaMetrics/fastcache v1.12.1/go.mod h1:tX04vaqcNoQeGLD+ra5pU5sWkuxnzWhEzLwhP9w653o= +github.com/aws/aws-sdk-go-v2 v1.26.1 h1:5554eUqIYVWpU0YmeeYZ0wU64H2VLBs8TlhRB2L+EkA= +github.com/aws/aws-sdk-go-v2 v1.26.1/go.mod h1:ffIFB97e2yNsv4aTSGkqtHnppsIJzw7G7BReUZ3jCXM= +github.com/aws/aws-sdk-go-v2/config v1.27.11 h1:f47rANd2LQEYHda2ddSCKYId18/8BhSRM4BULGmfgNA= +github.com/aws/aws-sdk-go-v2/config v1.27.11/go.mod h1:SMsV78RIOYdve1vf36z8LmnszlRWkwMQtomCAI0/mIE= +github.com/aws/aws-sdk-go-v2/credentials v1.17.11 h1:YuIB1dJNf1Re822rriUOTxopaHHvIq0l/pX3fwO+Tzs= +github.com/aws/aws-sdk-go-v2/credentials v1.17.11/go.mod h1:AQtFPsDH9bI2O+71anW6EKL+NcD7LG3dpKGMV4SShgo= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.1 h1:FVJ0r5XTHSmIHJV6KuDmdYhEpvlHpiSd38RQWhut5J4= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.1/go.mod h1:zusuAeqezXzAB24LGuzuekqMAEgWkVYukBec3kr3jUg= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.5 h1:aw39xVGeRWlWx9EzGVnhOR4yOjQDHPQ6o6NmBlscyQg= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.5/go.mod h1:FSaRudD0dXiMPK2UjknVwwTYyZMRsHv3TtkabsZih5I= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.5 h1:PG1F3OD1szkuQPzDw3CIQsRIrtTlUC3lP84taWzHlq0= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.5/go.mod h1:jU1li6RFryMz+so64PpKtudI+QzbKoIEivqdf6LNpOc= +github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 h1:hT8rVHwugYE2lEfdFE0QWVo81lF7jMrYJVDWI+f+VxU= +github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0/go.mod h1:8tu/lYfQfFe6IGnaOdrpVgEL2IrrDOf6/m9RQum4NkY= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.2 h1:Ji0DY1xUsUr3I8cHps0G+XM3WWU16lP6yG8qu1GAZAs= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.2/go.mod h1:5CsjAbs3NlGQyZNFACh+zztPDI7fU6eW9QsxjfnuBKg= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.7 h1:ogRAwT1/gxJBcSWDMZlgyFUM962F51A5CRhDLbxLdmo= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.7/go.mod h1:YCsIZhXfRPLFFCl5xxY+1T9RKzOKjCut+28JSX2DnAk= +github.com/aws/aws-sdk-go-v2/service/kms v1.31.0 h1:yl7wcqbisxPzknJVfWTLnK83McUvXba+pz2+tPbIUmQ= +github.com/aws/aws-sdk-go-v2/service/kms v1.31.0/go.mod h1:2snWQJQUKsbN66vAawJuOGX7dr37pfOq9hb0tZDGIqQ= +github.com/aws/aws-sdk-go-v2/service/sso v1.20.5 h1:vN8hEbpRnL7+Hopy9dzmRle1xmDc7o8tmY0klsr175w= +github.com/aws/aws-sdk-go-v2/service/sso v1.20.5/go.mod h1:qGzynb/msuZIE8I75DVRCUXw3o3ZyBmUvMwQ2t/BrGM= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.23.4 h1:Jux+gDDyi1Lruk+KHF91tK2KCuY61kzoCpvtvJJBtOE= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.23.4/go.mod h1:mUYPBhaF2lGiukDEjJX2BLRRKTmoUSitGDUgM4tRxak= +github.com/aws/aws-sdk-go-v2/service/sts v1.28.6 h1:cwIxeBttqPN3qkaAjcEcsh8NYr8n2HZPkcKgPAi1phU= +github.com/aws/aws-sdk-go-v2/service/sts v1.28.6/go.mod h1:FZf1/nKNEkHdGGJP/cI2MoIMquumuRK6ol3QQJNDxmw= +github.com/aws/smithy-go v1.20.2 h1:tbp628ireGtzcHDDmLT/6ADHidqnwgF57XOXZe6tp4Q= +github.com/aws/smithy-go v1.20.2/go.mod h1:krry+ya/rV9RDcV/Q16kpu6ypI4K2czasz0NC3qS14E= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bits-and-blooms/bitset v1.10.0 h1:ePXTeiPEazB5+opbv5fr8umg2R/1NlzgDsyepwsSr88= +github.com/bits-and-blooms/bitset v1.10.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= +github.com/btcsuite/btcd/btcec/v2 v2.2.0 h1:fzn1qaOt32TuLjFlkzYSsBC35Q3KUjT1SwPxiMSCF5k= +github.com/btcsuite/btcd/btcec/v2 v2.2.0/go.mod h1:U7MHm051Al6XmscBQ0BoNydpOTsFAn707034b5nY8zU= +github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 h1:q0rUy8C/TYNBQS1+CGKw68tLOFYSNEs0TFnxxnS9+4U= +github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= +github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= +github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= +github.com/cespare/cp v0.1.0 h1:SE+dxFebS7Iik5LK0tsi1k9ZCxEaFX4AjQmoyA+1dJk= +github.com/cespare/cp v0.1.0/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cockroachdb/errors v1.11.1 h1:xSEW75zKaKCWzR3OfxXUxgrk/NtT4G1MiOv5lWZazG8= +github.com/cockroachdb/errors v1.11.1/go.mod h1:8MUxA3Gi6b25tYlFEBGLf+D8aISL+M4MIpiWMSNRfxw= +github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b h1:r6VH0faHjZeQy818SGhaone5OnYfxFR/+AzdY3sf5aE= +github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b/go.mod h1:Vz9DsVWQQhf3vs21MhPMZpMGSht7O/2vFW2xusFUVOs= +github.com/cockroachdb/pebble v1.1.0 h1:pcFh8CdCIt2kmEpK0OIatq67Ln9uGDYY3d5XnE0LJG4= +github.com/cockroachdb/pebble v1.1.0/go.mod h1:sEHm5NOXxyiAoKWhoFxT8xMgd/f3RA6qUqQ1BXKrh2E= +github.com/cockroachdb/redact v1.1.5 h1:u1PMllDkdFfPWaNGMyLD1+so+aq3uUItthCFqzwPJ30= +github.com/cockroachdb/redact v1.1.5/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg= +github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 h1:zuQyyAKVxetITBuuhv3BI9cMrmStnpT18zmgmTxunpo= +github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06/go.mod h1:7nc4anLGjupUW/PeY5qiNYsdNXj7zopG+eqsS7To5IQ= +github.com/consensys/bavard v0.1.13 h1:oLhMLOFGTLdlda/kma4VOJazblc7IM5y5QPd2A/YjhQ= +github.com/consensys/bavard v0.1.13/go.mod h1:9ItSMtA/dXMAiL7BG6bqW2m3NdSEObYWoH223nGHukI= +github.com/consensys/gnark-crypto v0.12.1 h1:lHH39WuuFgVHONRl3J0LRBtuYdQTumFSDtJF7HpyG8M= +github.com/consensys/gnark-crypto v0.12.1/go.mod h1:v2Gy7L/4ZRosZ7Ivs+9SfUDr0f5UlG+EM5t7MPHiLuY= +github.com/containerd/containerd v1.7.12 h1:+KQsnv4VnzyxWcfO9mlxxELaoztsDEjOuCMPAuPqgU0= +github.com/containerd/containerd v1.7.12/go.mod h1:/5OMpE1p0ylxtEUGY8kuCYkDRzJm9NO1TFMWjUpdevk= +github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= +github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo= +github.com/cpuguy83/dockercfg v0.3.1 h1:/FpZ+JaygUR/lZP2NlFI2DVfrOEMAIKP5wWEJdoYe9E= +github.com/cpuguy83/dockercfg v0.3.1/go.mod h1:sugsbF4//dDlL/i+S+rtpIWp+5h0BHJHfjj5/jFyUJc= +github.com/cpuguy83/go-md2man/v2 v2.0.5 h1:ZtcqGrnekaHpVLArFSe4HK5DoKx1T0rq2DwVB0alcyc= +github.com/cpuguy83/go-md2man/v2 v2.0.5/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/crate-crypto/go-ipa v0.0.0-20231025140028-3c0104f4b233 h1:d28BXYi+wUpz1KBmiF9bWrjEMacUEREV6MBi2ODnrfQ= +github.com/crate-crypto/go-ipa v0.0.0-20231025140028-3c0104f4b233/go.mod h1:geZJZH3SzKCqnz5VT0q/DyIG/tvu/dZk+VIfXicupJs= +github.com/crate-crypto/go-kzg-4844 v1.0.0 h1:TsSgHwrkTKecKJ4kadtHi4b3xHW5dCFUDFnUp1TsawI= +github.com/crate-crypto/go-kzg-4844 v1.0.0/go.mod h1:1kMhvPgI0Ky3yIa+9lFySEBUBXkYxeOi8ZF1sYioxhc= +github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= +github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/deckarep/golang-set/v2 v2.1.0 h1:g47V4Or+DUdzbs8FxCCmgb6VYd+ptPAngjM6dtGktsI= +github.com/deckarep/golang-set/v2 v2.1.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4= +github.com/decred/dcrd/crypto/blake256 v1.0.0 h1:/8DMNYp9SGi5f0w7uCm6d6M4OU2rGFK09Y2A4Xv7EE0= +github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 h1:YLtO71vCjJRCBcrPMtQ9nqBsqpA1m5sE92cU+pd5Mcc= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeCxkaw7y45JueMRL4DIyJDKs= +github.com/distribution/reference v0.5.0 h1:/FUIFXtfc/x2gpa5/VGfiGLuOIdYa1t65IKK2OFGvA0= +github.com/distribution/reference v0.5.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= +github.com/docker/docker v25.0.6+incompatible h1:5cPwbwriIcsua2REJe8HqQV+6WlWc1byg2QSXzBxBGg= +github.com/docker/docker v25.0.6+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c= +github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc= +github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= +github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/ethereum/c-kzg-4844 v1.0.0 h1:0X1LBXxaEtYD9xsyj9B9ctQEZIpnvVDeoBx8aHEwTNA= +github.com/ethereum/c-kzg-4844 v1.0.0/go.mod h1:VewdlzQmpT5QSrVhbBuGoCdFJkpaJlO1aQputP83wc0= +github.com/ethereum/go-ethereum v1.14.0 h1:xRWC5NlB6g1x7vNy4HDBLuqVNbtLrc7v8S6+Uxim1LU= +github.com/ethereum/go-ethereum v1.14.0/go.mod h1:1STrq471D0BQbCX9He0hUj4bHxX2k6mt5nOQJhDNOJ8= +github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= +github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/fjl/memsize v0.0.2 h1:27txuSD9or+NZlnOWdKUxeBzTAUkWCVh+4Gf2dWFOzA= +github.com/fjl/memsize v0.0.2/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0= +github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= +github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= +github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff h1:tY80oXqGNY4FhTFhk+o9oFHGINQ/+vhlm8HFzi6znCI= +github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww= +github.com/gballet/go-verkle v0.1.1-0.20231031103413-a67434b50f46 h1:BAIP2GihuqhwdILrV+7GJel5lyPV3u1+PgzrWLc0TkE= +github.com/gballet/go-verkle v0.1.1-0.20231031103413-a67434b50f46/go.mod h1:QNpY22eby74jVhqH4WhDLDwxc/vqsern6pW+u2kbkpc= +github.com/getsentry/sentry-go v0.18.0 h1:MtBW5H9QgdcJabtZcuJG80BMOwaBpkRDZkxRkNC1sN0= +github.com/getsentry/sentry-go v0.18.0/go.mod h1:Kgon4Mby+FJ7ZWHFUAZgVaIa8sxHtnRJRLTXZr51aKQ= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= +github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= +github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= +github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= +github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= +github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw= +github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= +github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= +github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= +github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb h1:PBC98N2aIaM3XXiurYmW7fx4GZkL8feAMVq7nEjURHk= +github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= +github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1 h1:VNqngBF40hVlDloBruUehVYC3ArSgIyScOAyMRqBxRg= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1/go.mod h1:RBRO7fro65R6tjKzYgLAFo0t1QEXY1Dp+i/bvpRiqiQ= +github.com/hashicorp/go-bexpr v0.1.10 h1:9kuI5PFotCboP3dkDYFr/wi0gg0QVbSNz5oFRpxn4uE= +github.com/hashicorp/go-bexpr v0.1.10/go.mod h1:oxlubA2vC/gFVfX1A6JGp7ls7uCDlfJn732ehYYg+g0= +github.com/holiman/billy v0.0.0-20240216141850-2abb0c79d3c4 h1:X4egAf/gcS1zATw6wn4Ej8vjuVGxeHdan+bRb2ebyv4= +github.com/holiman/billy v0.0.0-20240216141850-2abb0c79d3c4/go.mod h1:5GuXa7vkL8u9FkFuWdVvfR5ix8hRB7DbOAaYULamFpc= +github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao= +github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iURXE7ZOP9L9hSkA= +github.com/holiman/uint256 v1.2.4 h1:jUc4Nk8fm9jZabQuqr2JzednajVmBpC+oiTiXZJEApU= +github.com/holiman/uint256 v1.2.4/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E= +github.com/huin/goupnp v1.3.0 h1:UvLUlWDNpoUdYzb2TCn+MuTWtcjXKSza2n6CBdQ0xXc= +github.com/huin/goupnp v1.3.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8= +github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus= +github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/klauspost/compress v1.16.0 h1:iULayQNOReoYUe+1qtKOqw9CwJv3aNQu8ivo7lw1HU4= +github.com/klauspost/compress v1.16.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= +github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= +github.com/leanovate/gopter v0.2.9 h1:fQjYxZaynp97ozCzfOyOuAGOU4aU/z37zf/tOujFk7c= +github.com/leanovate/gopter v0.2.9/go.mod h1:U2L/78B+KVFIx2VmW6onHJQzXtFb+p5y3y2Sh+Jxxv8= +github.com/lmittmann/tint v1.0.4 h1:LeYihpJ9hyGvE0w+K2okPTGUdVLfng1+nDNVR4vWISc= +github.com/lmittmann/tint v1.0.4/go.mod h1:HIS3gSy7qNwGCj+5oRjAutErFBl4BzdQP6cJZ0NfMwE= +github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4= +github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= +github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= +github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU= +github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/pointerstructure v1.2.0 h1:O+i9nHnXS3l/9Wu7r4NrEdwA2VFTicjUEN1uBnDo34A= +github.com/mitchellh/pointerstructure v1.2.0/go.mod h1:BRAsLI5zgXmw97Lf6s25bs8ohIXc3tViBH44KcwB2g4= +github.com/mmcloughlin/addchain v0.4.0 h1:SobOdjm2xLj1KkXN5/n0xTIWyZA2+s99UCY1iPfkHRY= +github.com/mmcloughlin/addchain v0.4.0/go.mod h1:A86O+tHqZLMNO4w6ZZ4FlVQEadcoqkyU72HC5wJ4RlU= +github.com/mmcloughlin/profile v0.1.1/go.mod h1:IhHD7q1ooxgwTgjxQYkACGA77oFTDdFVejUS1/tS/qU= +github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk= +github.com/moby/patternmatcher v0.6.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc= +github.com/moby/sys/sequential v0.5.0 h1:OPvI35Lzn9K04PBbCLW0g4LcFAJgHsvXsRyewg5lXtc= +github.com/moby/sys/sequential v0.5.0/go.mod h1:tH2cOOs5V9MlPiXcQzRC+eEyab644PWKGRYaaV5ZZlo= +github.com/moby/sys/user v0.1.0 h1:WmZ93f5Ux6het5iituh9x2zAG7NFY9Aqi49jjE1PaQg= +github.com/moby/sys/user v0.1.0/go.mod h1:fKJhFOnsCN6xZ5gSfbM6zaHGgDJMrqt9/reuj4T7MmU= +github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= +github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= +github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= +github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= +github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= +github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= +github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug= +github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw= +github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= +github.com/prometheus/client_golang v1.19.0 h1:ygXvpU1AoN1MhdzckN+PyD9QJOSD4x7kmXYlnfbA6JU= +github.com/prometheus/client_golang v1.19.0/go.mod h1:ZRM9uEAypZakd+q/x7+gmsvXdURP+DABIEIjnmDdp+k= +github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw= +github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI= +github.com/prometheus/common v0.48.0 h1:QO8U2CdOzSn1BBsmXJXduaaW+dY/5QLjfB8svtSzKKE= +github.com/prometheus/common v0.48.0/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc= +github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= +github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= +github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= +github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= +github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= +github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik= +github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= +github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible h1:Bn1aCHHRnjv4Bl16T8rcaFjYSrGrIZvpiGO6P3Q4GpU= +github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= +github.com/shirou/gopsutil/v3 v3.23.12 h1:z90NtUkp3bMtmICZKpC4+WaknU1eXtp5vtbQ11DgpE4= +github.com/shirou/gopsutil/v3 v3.23.12/go.mod h1:1FrWgea594Jp7qmjHUUPlJDTPgcsb9mGnXDxavtikzM= +github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM= +github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ= +github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU= +github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k= +github.com/shurcooL/graphql v0.0.0-20230722043721-ed46e5a46466 h1:17JxqqJY66GmZVHkmAsGEkcIu0oCe3AM420QDgGwZx0= +github.com/shurcooL/graphql v0.0.0-20230722043721-ed46e5a46466/go.mod h1:9dIRpgIY7hVhoqfe0/FcYp0bpInZaT7dc3BYOprrIUE= +github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= +github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/status-im/keycard-go v0.2.0 h1:QDLFswOQu1r5jsycloeQh3bVU8n/NatHHaZobtDnDzA= +github.com/status-im/keycard-go v0.2.0/go.mod h1:wlp8ZLbsmrF6g6WjugPAx+IzoLrkdf9+mHxBEeo3Hbg= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/supranational/blst v0.3.11 h1:LyU6FolezeWAhvQk0k6O/d49jqgO52MSDDfYgbeoEm4= +github.com/supranational/blst v0.3.11/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw= +github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY= +github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= +github.com/testcontainers/testcontainers-go v0.30.0 h1:jmn/XS22q4YRrcMwWg0pAwlClzs/abopbsBzrepyc4E= +github.com/testcontainers/testcontainers-go v0.30.0/go.mod h1:K+kHNGiM5zjklKjgTtcrEetF3uhWbMUyqAQoyoh8Pf0= +github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU= +github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI= +github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk= +github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY= +github.com/tyler-smith/go-bip39 v1.1.0 h1:5eUemwrMargf3BSLRRCalXT93Ns6pQJIjYQN2nyfOP8= +github.com/tyler-smith/go-bip39 v1.1.0/go.mod h1:gUYDtqQw1JS3ZJ8UWVcGTGqqr6YIN3CWg+kkNaLt55U= +github.com/urfave/cli/v2 v2.27.5 h1:WoHEJLdsXr6dDWoJgMq/CboDmyY/8HMMH1fTECbih+w= +github.com/urfave/cli/v2 v2.27.5/go.mod h1:3Sevf16NykTbInEnD0yKkjDAeZDS0A6bzhBH5hrMvTQ= +github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 h1:gEOO8jv9F4OT7lGCjxCBTO/36wtF6j2nSip77qHd4x4= +github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yusufpapurcu/wmi v1.2.3 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFiw= +github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 h1:jq9TW8u3so/bN+JPT166wjOI6/vQPF6Xe7nMNIltagk= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0/go.mod h1:p8pYQP+m5XfbZm9fxtSKAbM6oIllS7s2AfxrChvc7iw= +go.opentelemetry.io/otel v1.31.0 h1:NsJcKPIW0D0H3NgzPDHmo0WW6SptzPdqg/L1zsIm2hY= +go.opentelemetry.io/otel v1.31.0/go.mod h1:O0C14Yl9FgkjqcCZAsE053C13OaddMYr/hz6clDkEJE= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0 h1:Mne5On7VWdx7omSrSSZvM4Kw7cS7NQkOOmLcgscI51U= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0/go.mod h1:IPtUMKL4O3tH5y+iXVyAXqpAwMuzC1IrxVS81rummfE= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0 h1:IeMeyr1aBvBiPVYihXIaeIZba6b8E1bYp7lbdxK8CQg= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0/go.mod h1:oVdCUtjq9MK9BlS7TtucsQwUcXcymNiEDjgDD2jMtZU= +go.opentelemetry.io/otel/metric v1.31.0 h1:FSErL0ATQAmYHUIzSezZibnyVlft1ybhy4ozRPcF2fE= +go.opentelemetry.io/otel/metric v1.31.0/go.mod h1:C3dEloVbLuYoX41KpmAhOqNriGbA+qqH6PQ5E5mUfnY= +go.opentelemetry.io/otel/sdk v1.31.0 h1:xLY3abVHYZ5HSfOg3l2E5LUj2Cwva5Y7yGxnSW9H5Gk= +go.opentelemetry.io/otel/sdk v1.31.0/go.mod h1:TfRbMdhvxIIr/B2N2LQW2S5v9m3gOQ/08KsbbO5BPT0= +go.opentelemetry.io/otel/sdk/metric v1.31.0 h1:i9hxxLJF/9kkvfHppyLL55aW7iIJz4JjxTeYusH7zMc= +go.opentelemetry.io/otel/sdk/metric v1.31.0/go.mod h1:CRInTMVvNhUKgSAMbKyTMxqOBC0zgyxzW55lZzX43Y8= +go.opentelemetry.io/otel/trace v1.31.0 h1:ffjsj1aRouKewfr85U2aGagJ46+MvodynlQ1HYdmJys= +go.opentelemetry.io/otel/trace v1.31.0/go.mod h1:TXZkRk7SM2ZQLtR6eoAWQFIHPvzQ06FJAsO1tJg480A= +go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I= +go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= +go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU= +go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc= +go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= +go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= +go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= +golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= +golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa h1:FRnLl4eNAQl8hwxVVC17teOw8kdjVDVAiFMtgUdTSRQ= +golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa/go.mod h1:zk2irFbV9DP96SEBUUAy67IdHUaZuSnrz1n472HUCLE= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= +golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I= +golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= +golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= +golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= +golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= +golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= +golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto/googleapis/api v0.0.0-20241219192143-6b3ec007d9bb h1:B7GIB7sr443wZ/EAEl7VZjmh1V6qzkt5V+RYcUYtS1U= +google.golang.org/genproto/googleapis/api v0.0.0-20241219192143-6b3ec007d9bb/go.mod h1:E5//3O5ZIG2l71Xnt+P/CYUY8Bxs8E7WMoZ9tlcMbAY= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241219192143-6b3ec007d9bb h1:3oy2tynMOP1QbTC0MsNNAV+Se8M2Bd0A5+x1QHyw+pI= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241219192143-6b3ec007d9bb/go.mod h1:lcTa1sDdWEIHMWlITnIczmw5w60CF9ffkb8Z+DVmmjA= +google.golang.org/grpc v1.69.4 h1:MF5TftSMkd8GLw/m0KM6V8CMOCY6NZ1NQDPGFgbTt4A= +google.golang.org/grpc v1.69.4/go.mod h1:vyjdE6jLBI76dgpDojsFGNaHlxdjXN9ghpnd2o7JGZ4= +google.golang.org/protobuf v1.36.3 h1:82DV7MYdb8anAVi3qge1wSnMDrnKK7ebr+I0hHRN1BU= +google.golang.org/protobuf v1.36.3/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8= +gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gotest.tools/v3 v3.5.0 h1:Ljk6PdHdOhAb5aDMWXjDLMMhph+BpztA4v1QdqEW2eY= +gotest.tools/v3 v3.5.0/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU= +rsc.io/tmplfunc v0.0.3 h1:53XFQh69AfOa8Tw0Jm7t+GV7KZhOi6jzsCzTtKbMvzU= +rsc.io/tmplfunc v0.0.3/go.mod h1:AG3sTPzElb1Io3Yg4voV9AGZJuleGAwaVRxL9M49PhA= diff --git a/node/server/server.go b/node/server/server.go new file mode 100644 index 0000000..dc6378d --- /dev/null +++ b/node/server/server.go @@ -0,0 +1,72 @@ +package server + +import ( + "fmt" + "log" + "net" + + "google.golang.org/grpc" + "google.golang.org/grpc/reflection" + + "github.com/Layr-Labs/eigensdk-go/crypto/bls" + v1 "github.com/Layr-Labs/teal/api/service/v1" + "github.com/Layr-Labs/teal/node/service" +) + +type Config struct { + ServicePort int + BlsKeyPair *bls.KeyPair +} +type Certifier interface { + GetResponse(config Config, data []byte) ([]byte, error) +} + +type BaseNode struct { + config Config + certifier Certifier +} + +type Node interface { + Certifier + Start() error +} + +// NewBaseNode creates a new base node implementation +func NewBaseNode(config Config, certifier Certifier) *BaseNode { + return &BaseNode{ + config: config, + certifier: certifier, + } +} + +// Start implements the Node interface +func (n *BaseNode) Start() error { + lis, err := net.Listen("tcp", fmt.Sprintf(":%d", n.config.ServicePort)) + if err != nil { + return err + } + return n.StartWithListener(lis) +} + +func (n *BaseNode) StartWithListener(lis net.Listener) error { + grpcServer := grpc.NewServer() + + // Create a closure that captures the config for validation + getResponse := func(data []byte) ([]byte, error) { + return n.certifier.GetResponse(n.config, data) + } + + v1.RegisterNodeServiceServer(grpcServer, service.NewCertifyingService( + n.config.BlsKeyPair, + getResponse, + )) + + reflection.Register(grpcServer) + + log.Printf("Starting server on port %d", n.config.ServicePort) + if err := grpcServer.Serve(lis); err != nil { + log.Printf("Failed to serve on port %d: %v", n.config.ServicePort, err) + return err + } + return nil +} diff --git a/node/service/certify.go b/node/service/certify.go new file mode 100644 index 0000000..7c860e2 --- /dev/null +++ b/node/service/certify.go @@ -0,0 +1,44 @@ +package service + +import ( + "context" + + "github.com/Layr-Labs/eigensdk-go/crypto/bls" + "github.com/ethereum/go-ethereum/crypto" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + + v1 "github.com/Layr-Labs/teal/api/service/v1" +) + +type CertifyingService struct { + keyPair *bls.KeyPair + getResponse func(data []byte) ([]byte, error) + + v1.UnsafeNodeServiceServer +} + +func NewCertifyingService( + kp *bls.KeyPair, + getResponse func(data []byte) ([]byte, error), +) *CertifyingService { + return &CertifyingService{ + keyPair: kp, + getResponse: getResponse, + } +} + +func (s *CertifyingService) Certify(ctx context.Context, req *v1.CertifyRequest) (*v1.CertifyResponse, error) { + response, err := s.getResponse(req.Data) + if err != nil { + return nil, status.Errorf(codes.InvalidArgument, "data is invalid: %v", err) + } + + digest := crypto.Keccak256(response) + digestBytes := [32]byte(digest) + + signature := s.keyPair.SignMessage(digestBytes) + signatureBytes := signature.Marshal() + + return &v1.CertifyResponse{Signature: signatureBytes[:], Data: response}, nil +}