Initial work on support of standard API

This commit is contained in:
Jim McDonald 2020-11-14 08:36:49 +00:00
parent 796cb6348f
commit 4e5fbf18ba
No known key found for this signature in database
GPG Key ID: 89CEB61B2AD2A5E7
47 changed files with 1001 additions and 807 deletions

33
go.mod
View File

@ -3,19 +3,22 @@ module github.com/attestantio/vouch
go 1.14
require (
cloud.google.com/go v0.70.0 // indirect
cloud.google.com/go v0.72.0 // indirect
github.com/OneOfOne/xxhash v1.2.5 // indirect
github.com/attestantio/dirk v0.9.1
github.com/attestantio/go-eth2-client v0.6.8
github.com/aws/aws-sdk-go v1.35.14
github.com/ferranbt/fastssz v0.0.0-20201020132831-68dc48984fd3
github.com/grpc-ecosystem/grpc-gateway v1.15.2 // indirect
github.com/herumi/bls-eth-go-binary v0.0.0-20201019012252-4b463a10c225
github.com/attestantio/dirk v0.9.3
github.com/attestantio/go-eth2-client v0.6.10
github.com/aws/aws-sdk-go v1.35.28
github.com/ferranbt/fastssz v0.0.0-20201030134205-9b9624098321
github.com/goccy/go-yaml v1.8.4 // indirect
github.com/google/go-cmp v0.5.3 // indirect
github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect
github.com/herumi/bls-eth-go-binary v0.0.0-20201104034342-d782bdf735de
github.com/mitchellh/go-homedir v1.1.0
github.com/opentracing/opentracing-go v1.2.0
github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5 // indirect
github.com/pkg/errors v0.9.1
github.com/prometheus/client_golang v1.8.0
github.com/prometheus/common v0.15.0 // indirect
github.com/prysmaticlabs/ethereumapis v0.0.0-20201020182719-7f66dae2bbba
github.com/prysmaticlabs/go-bitfield v0.0.0-20200618145306-2ae0807bef65
github.com/rs/zerolog v1.20.0
@ -27,19 +30,19 @@ require (
github.com/uber/jaeger-client-go v2.25.0+incompatible
github.com/wealdtech/go-bytesutil v1.1.1
github.com/wealdtech/go-eth2-types/v2 v2.5.1
github.com/wealdtech/go-eth2-wallet v1.14.2
github.com/wealdtech/go-eth2-wallet-dirk v1.1.2
github.com/wealdtech/go-eth2-wallet v1.14.3
github.com/wealdtech/go-eth2-wallet-dirk v1.1.4
github.com/wealdtech/go-eth2-wallet-encryptor-keystorev4 v1.1.2
github.com/wealdtech/go-eth2-wallet-hd/v2 v2.5.2
github.com/wealdtech/go-eth2-wallet-hd/v2 v2.5.3
github.com/wealdtech/go-eth2-wallet-store-filesystem v1.16.13
github.com/wealdtech/go-eth2-wallet-store-scratch v1.6.1
github.com/wealdtech/go-eth2-wallet-types/v2 v2.8.1
github.com/wealdtech/go-majordomo v1.0.1
golang.org/x/net v0.0.0-20201026091529-146b70c837a4 // indirect
golang.org/x/crypto v0.0.0-20201112155050-0c6587e931a9 // indirect
golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58 // indirect
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9
google.golang.org/genproto v0.0.0-20201022181438-0ff5f38871d5 // indirect
google.golang.org/grpc v1.33.1
golang.org/x/sys v0.0.0-20201113233024-12cec1faf1ba // indirect
google.golang.org/genproto v0.0.0-20201113130914-ce600e9a6f9e // indirect
google.golang.org/grpc v1.33.2
gotest.tools v2.2.0+incompatible
)
replace github.com/attestantio/go-eth2-client => ../go-eth2-client

85
go.sum
View File

@ -16,6 +16,8 @@ cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHOb
cloud.google.com/go v0.68.0/go.mod h1:91NO4SCDjUfe1zeC0f4/dpckkUNpuNEyqm4X2KLrzNQ=
cloud.google.com/go v0.70.0 h1:ujhG1RejZYi+HYfJNlgBh3j/bVKD8DewM7AkJ5UPyBc=
cloud.google.com/go v0.70.0/go.mod h1:/UTKYRQTWjVnSe7nGvoSzxEFUELzSI/yAYd0JQT6cRo=
cloud.google.com/go v0.72.0 h1:eWRCuwubtDrCJG0oSUMgnsbD4CmPFQF2ei4OFbXvwww=
cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI=
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
@ -66,6 +68,10 @@ github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj
github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A=
github.com/attestantio/dirk v0.9.1 h1:oof1Xm0uI4a2T9vhQB+f3Wjlngd2rnfsKi8aj1wqNh0=
github.com/attestantio/dirk v0.9.1/go.mod h1:oWsyIb/OXdx9pvDQqS3hdFBB1eFaYnrNjuvLtVwo69w=
github.com/attestantio/dirk v0.9.3/go.mod h1:EfppeT+VjQXnE9Ti5/vxa6ptZJAN2vMXO6KZojvSOXA=
github.com/attestantio/go-eth2-client v0.6.9/go.mod h1:ODAZ4yS1YYYew/EsgGsVb/siNEoa505CrGsvlVFdkfo=
github.com/attestantio/go-eth2-client v0.6.10 h1:PMNBMLk6xfMEUqhaUnsI0/HZRrstZF18Gt6Dm5GelW4=
github.com/attestantio/go-eth2-client v0.6.10/go.mod h1:ODAZ4yS1YYYew/EsgGsVb/siNEoa505CrGsvlVFdkfo=
github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU=
github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
github.com/aws/aws-sdk-go v1.33.5/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0=
@ -73,6 +79,10 @@ github.com/aws/aws-sdk-go v1.33.17/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZve
github.com/aws/aws-sdk-go v1.35.7/go.mod h1:tlPOdRjfxPBpNIwqDj61rmsnA85v9jc0Ps9+muhnW+k=
github.com/aws/aws-sdk-go v1.35.14 h1:nucVVXXjAr9UkmYCBWxQWRuYa5KOlaXjuJGg2ulW0K0=
github.com/aws/aws-sdk-go v1.35.14/go.mod h1:tlPOdRjfxPBpNIwqDj61rmsnA85v9jc0Ps9+muhnW+k=
github.com/aws/aws-sdk-go v1.35.26 h1:MawRvDpAp/Ai859dPC1xo1fdU/BIkijoHj0DwXLXXkI=
github.com/aws/aws-sdk-go v1.35.26/go.mod h1:tlPOdRjfxPBpNIwqDj61rmsnA85v9jc0Ps9+muhnW+k=
github.com/aws/aws-sdk-go v1.35.28 h1:S2LuRnfC8X05zgZLC8gy/Sb82TGv2Cpytzbzz7tkeHc=
github.com/aws/aws-sdk-go v1.35.28/go.mod h1:tlPOdRjfxPBpNIwqDj61rmsnA85v9jc0Ps9+muhnW+k=
github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
@ -135,12 +145,17 @@ github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymF
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fatih/color v1.10.0 h1:s36xzo75JdqLaaWoiEHk767eHiwo0598uUxyfiPkDsg=
github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM=
github.com/ferranbt/fastssz v0.0.0-20200514094935-99fccaf93472/go.mod h1:LlFXPmgrgVYsuoFDwV8rDJ9tvt1pLQdjKvU1b5IRES0=
github.com/ferranbt/fastssz v0.0.0-20200728110133-0b6e349af87a/go.mod h1:DyEu2iuLBnb/T51BlsiO3yLYdJC6UbGMrIkqK1KmQxM=
github.com/ferranbt/fastssz v0.0.0-20200826142241-3a913c5a1313/go.mod h1:DyEu2iuLBnb/T51BlsiO3yLYdJC6UbGMrIkqK1KmQxM=
github.com/ferranbt/fastssz v0.0.0-20201020132831-68dc48984fd3 h1:FnpkCo1TAj/eq0ETLPhAplYYB4KlFQy3kVb8cLludAc=
github.com/ferranbt/fastssz v0.0.0-20201020132831-68dc48984fd3/go.mod h1:DyEu2iuLBnb/T51BlsiO3yLYdJC6UbGMrIkqK1KmQxM=
github.com/ferranbt/fastssz v0.0.0-20201030134205-9b9624098321 h1:9Pkbf8HgETu3xKpz12Sj5clUrVFp2O+ymK7pBsTPYRM=
github.com/ferranbt/fastssz v0.0.0-20201030134205-9b9624098321/go.mod h1:DyEu2iuLBnb/T51BlsiO3yLYdJC6UbGMrIkqK1KmQxM=
github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4=
github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
@ -156,9 +171,17 @@ github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgO
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4=
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/goccy/go-yaml v1.8.3 h1:VGzw2KWSUyQX0yXai02S0nttBc+Oa4Kvh6RCFoxt8SE=
github.com/goccy/go-yaml v1.8.3/go.mod h1:wS4gNoLalDSJxo/SpngzPQ2BN4uuZVLCmbM4S3vd4+Y=
github.com/goccy/go-yaml v1.8.4 h1:AOEdR7aQgbgwHznGe3BLkDQVujxCPUpHOZZcQcp8Y3M=
github.com/goccy/go-yaml v1.8.4/go.mod h1:U/jl18uSupI5rdI2jmuCswEA2htH9eXfferR3KfscvA=
github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
@ -209,10 +232,13 @@ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.3 h1:x95R7cp+rSeeqAMI2knLtQ0DKlaBhv2NrtrOvafPHRo=
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
@ -222,6 +248,7 @@ github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hf
github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200905233945-acf8798be1f7/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20201009210932-67992a1a5a35/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
@ -247,6 +274,8 @@ github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t
github.com/grpc-ecosystem/grpc-gateway v1.13.0/go.mod h1:8XEsbTttt/W+VvjtQhLACqCisSPWTxCZ7sBRjU6iH9c=
github.com/grpc-ecosystem/grpc-gateway v1.15.2 h1:HC+hWRWf+v5zTMPyoaYTKIJih+4sd4XRWmj0qlG87Co=
github.com/grpc-ecosystem/grpc-gateway v1.15.2/go.mod h1:vO11I9oWA+KsxmfFQPhLnnIb1VDE24M+pdxZFiuZcA8=
github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo=
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE=
github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
@ -275,6 +304,8 @@ github.com/herumi/bls-eth-go-binary v0.0.0-20200706085701-832d8c2c0f7d/go.mod h1
github.com/herumi/bls-eth-go-binary v0.0.0-20201008062400-71567a52ad65/go.mod h1:luAnRm3OsMQeokhGzpYmc0ZKwawY7o87PUEP11Z7r7U=
github.com/herumi/bls-eth-go-binary v0.0.0-20201019012252-4b463a10c225 h1:S7pKW74AvYc89WawL6IxGSnJRxF4TkE1GITYqKFyYy4=
github.com/herumi/bls-eth-go-binary v0.0.0-20201019012252-4b463a10c225/go.mod h1:luAnRm3OsMQeokhGzpYmc0ZKwawY7o87PUEP11Z7r7U=
github.com/herumi/bls-eth-go-binary v0.0.0-20201104034342-d782bdf735de h1:qLlwYGvpvAx/nDBnPt2KpZTXGli0oHBGddyYxJHTOds=
github.com/herumi/bls-eth-go-binary v0.0.0-20201104034342-d782bdf735de/go.mod h1:luAnRm3OsMQeokhGzpYmc0ZKwawY7o87PUEP11Z7r7U=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
@ -315,6 +346,7 @@ github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfn
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM=
github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4=
github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ=
@ -323,8 +355,17 @@ github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czP
github.com/magiconair/properties v1.8.4 h1:8KGKTcQQGm0Kv7vEbKFErAoAOFyyacLStRtQSeYtvkY=
github.com/magiconair/properties v1.8.4/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA=
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8=
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.10 h1:qxFzApOv4WsAL965uUPIsXzAKCZxN2p9UqdhFS4ZW10=
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
@ -420,6 +461,8 @@ github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt2
github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
github.com/prometheus/common v0.14.0 h1:RHRyE8UocrbjU+6UvRzwi6HjiDfxrrBU91TtbKzkGp4=
github.com/prometheus/common v0.14.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s=
github.com/prometheus/common v0.15.0 h1:4fgOnadei3EZvgRwxJ7RMpG1k1pOZth5Pc13tyspaKM=
github.com/prometheus/common v0.15.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
@ -534,14 +577,20 @@ github.com/wealdtech/go-eth2-util v1.6.0 h1:l2OR0SqfYdEnb1I1Ggnk0w+B9/LA5aHdQ2KK
github.com/wealdtech/go-eth2-util v1.6.0/go.mod h1:0PGWeWWc6qjky/aNjdPdguJdZ2HSEHHCA+3cTjvT+Hk=
github.com/wealdtech/go-eth2-util v1.6.1 h1:gYW2s6iea/6NoSuSbisMqETpcnQYfqQnpmGLPYc0XHY=
github.com/wealdtech/go-eth2-util v1.6.1/go.mod h1:0hCjncDU0yi6dzGgrCgWAj6grdvJ6loEKCGpCMfxo9c=
github.com/wealdtech/go-eth2-util v1.6.2 h1:Gk7xVTG/bY1IUw/8wxOf97DuPbLTGGoZ0k5dNayudhk=
github.com/wealdtech/go-eth2-util v1.6.2/go.mod h1:0hCjncDU0yi6dzGgrCgWAj6grdvJ6loEKCGpCMfxo9c=
github.com/wealdtech/go-eth2-wallet v1.14.1 h1:0XQ6Bc2vZQCvDMg4qD6usObsXEVUPaNdv31qpwHpm0g=
github.com/wealdtech/go-eth2-wallet v1.14.1/go.mod h1:MfQZSlMPfUlvh8EAnlHan/ZQSr+lSWA1zD4QTl4116w=
github.com/wealdtech/go-eth2-wallet v1.14.2 h1:pk6JGQdeEafVmZw5JYg2gk/8IeZjf0mY8gjufdTfYo8=
github.com/wealdtech/go-eth2-wallet v1.14.2/go.mod h1:irzlGFMyRCWlvGgdI7IjS+/Oyr3Y+Dkkh5kxo0VCRDg=
github.com/wealdtech/go-eth2-wallet v1.14.3 h1:VskYm62CSMPm9pc/93E2mO3p1GcYUg8HHUSW/rgXPks=
github.com/wealdtech/go-eth2-wallet v1.14.3/go.mod h1:cGFCLvyUua84+WQ9e9ETnXjx9hnlZgjRRYYltn+RfOE=
github.com/wealdtech/go-eth2-wallet-dirk v1.1.1 h1:lACHi/+nCQlxDEgMAwl4HE05+RN79NndqDNKTP7iAsk=
github.com/wealdtech/go-eth2-wallet-dirk v1.1.1/go.mod h1:qG4tbznw2pO80tMm3x42uPqOAO+LUhQosWApbL0enqY=
github.com/wealdtech/go-eth2-wallet-dirk v1.1.2 h1:HSF3j/RY5bl46cPgskNNz9k7NEeVRrZq+qKWDKRWqP8=
github.com/wealdtech/go-eth2-wallet-dirk v1.1.2/go.mod h1:WQ0YW8E+A8r+SjMYX8ZwouZNAHEQPvoxy4Q3OtC0KqU=
github.com/wealdtech/go-eth2-wallet-dirk v1.1.4 h1:huJwlmQDNGjjBi6B/yEDLYFUcx+xbldhoJfkVGLBJYY=
github.com/wealdtech/go-eth2-wallet-dirk v1.1.4/go.mod h1:CEQyNdk+egD2UbvnVn4qGeSBkvR09dmknCA293WiCVk=
github.com/wealdtech/go-eth2-wallet-distributed v1.1.1 h1:KSaNQbtj5XXjttTVHe1oy+LgvHmi4NHNfLl+jaTM8fU=
github.com/wealdtech/go-eth2-wallet-distributed v1.1.1/go.mod h1:Ik8JPsQQiMengG+dVUaLbFmGug1z9UOWqBDHkF1tGro=
github.com/wealdtech/go-eth2-wallet-distributed v1.1.2 h1:ABE1tyxGfXAPPphQ32dval7+9aP61BsIdtvuOJr3azY=
@ -557,6 +606,8 @@ github.com/wealdtech/go-eth2-wallet-hd/v2 v2.5.1 h1:QoIyyVQ/vaztkeG88L1vOZKkKMM4
github.com/wealdtech/go-eth2-wallet-hd/v2 v2.5.1/go.mod h1:smW8Ca0x7JO41urG0sgrlJALb1mGTSagnqaapMWiHfk=
github.com/wealdtech/go-eth2-wallet-hd/v2 v2.5.2 h1:3EYbuUrs4cCId+WxFAtx+H/uQXRRlBLzosMRSijpwps=
github.com/wealdtech/go-eth2-wallet-hd/v2 v2.5.2/go.mod h1:hmDme779S5sqxN+W+zmHpS0K8n13fGekHM3gUUB1Ip0=
github.com/wealdtech/go-eth2-wallet-hd/v2 v2.5.3 h1:9Gt/UGrg3wWkZEFuXOdmm5Ih/wOJPP/p8l9v3MIPPzc=
github.com/wealdtech/go-eth2-wallet-hd/v2 v2.5.3/go.mod h1:UzS7JsWmOGjaSky+NTSjriTpdv+Vww1pWemb+3+GRk8=
github.com/wealdtech/go-eth2-wallet-nd/v2 v2.3.1 h1:inSu0xN3LQN9/nEXTri5IbGLfhsvHwyrXiCI3rAHTzc=
github.com/wealdtech/go-eth2-wallet-nd/v2 v2.3.1/go.mod h1:72HjvN+bANNgv/YCZ4Rjwgn6wesg24aHSQlHzrbPFWo=
github.com/wealdtech/go-eth2-wallet-nd/v2 v2.3.2 h1:NwJV/Ll90WhqxhCcYCdHYWIURGXDt/GRPNFOvu4kzbg=
@ -569,6 +620,8 @@ github.com/wealdtech/go-eth2-wallet-store-s3 v1.9.0 h1:O5211UskLbK1WDecTXwugUlIN
github.com/wealdtech/go-eth2-wallet-store-s3 v1.9.0/go.mod h1:dcQPLsRRYDiMV0DFYzTX6HRpP9WP+gWreAX5SLBOJ0I=
github.com/wealdtech/go-eth2-wallet-store-s3 v1.9.1 h1:YGw5YanOepPGalSyvDKwCEdwvAmG9E3pwo7v6jR/7IM=
github.com/wealdtech/go-eth2-wallet-store-s3 v1.9.1/go.mod h1:FR+mhCaoZN4d+EEBSV2QT2cO4szdKvDLTHRygMrH6fk=
github.com/wealdtech/go-eth2-wallet-store-s3 v1.9.2 h1:HFT1w+8icvHj5Yb1qDZUjzIQYnFbau1ahYwB08kwwJM=
github.com/wealdtech/go-eth2-wallet-store-s3 v1.9.2/go.mod h1:oKDDrc/BMDotY8/zT9TfmnELt+QMaPCiWwTiBmjlwTw=
github.com/wealdtech/go-eth2-wallet-store-scratch v1.6.0 h1:41H6hnVsI/csBx20UHpI2pY922N7Vhcro35DFS+slj0=
github.com/wealdtech/go-eth2-wallet-store-scratch v1.6.0/go.mod h1:XtXHbl4OV/XenQsvGmXbh+bVXaGS788oa30DB7kDInA=
github.com/wealdtech/go-eth2-wallet-store-scratch v1.6.1 h1:vv9lR8K76FUSNbzUU25MN4HNhZIBBI1kJBNfHq2WjRY=
@ -627,6 +680,8 @@ golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899/go.mod h1:LzIPMQfyMNhhGPh
golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897 h1:pLI5jrR7OSLijeIDcmRxNmw2api+jEfxLoykJVice/E=
golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201112155050-0c6587e931a9 h1:umElSU9WZirRdgu2yFHY0ayQkEnKiOC1TtM3fWXFnoU=
golang.org/x/crypto v0.0.0-20201112155050-0c6587e931a9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@ -698,9 +753,13 @@ golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81R
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200927032502-5d4f70055728/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201024042810-be3efd7ff127/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201026091529-146b70c837a4 h1:awiuzyrRjJDb+OXi9ceHO3SDxVoN3JER57mhtqkdQBs=
golang.org/x/net v0.0.0-20201026091529-146b70c837a4/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b h1:uwuIcX0g4Yl1NC5XAz37xsr2lTtcqevgzYNVt49waME=
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@ -708,6 +767,8 @@ golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4Iltr
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43 h1:ld7aEMNHoBnnDAX15v1T6z31v8HwR2A9FYOuAhWqkwc=
golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58 h1:Mj83v+wSRNEar42a/MQgxk9X42TdEmrOl9i+y8WbxLo=
golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@ -729,6 +790,7 @@ golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5h
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190130150945-aca44879d564/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@ -741,11 +803,14 @@ golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@ -768,12 +833,20 @@ golang.org/x/sys v0.0.0-20201014080544-cc95f250f6bc/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20201015000850-e3ed0017c211/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201024232916-9f70ab9862d5 h1:iCaAy5bMeEvwANu3YnJfWwI0kWAGkEa2RXPdweI/ysk=
golang.org/x/sys v0.0.0-20201024232916-9f70ab9862d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201101102859-da207088b7d1 h1:a/mKvvZr9Jcc8oKfcmgzyp7OwF73JPWsQLvH1z2Kxck=
golang.org/x/sys v0.0.0-20201101102859-da207088b7d1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201112073958-5cba982894dd h1:5CtCZbICpIOFdgO940moixOPjc0178IU44m4EjOO5IY=
golang.org/x/sys v0.0.0-20201112073958-5cba982894dd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201113233024-12cec1faf1ba h1:xmhUJGQGbxlod18iJGqVEp9cHIPLl7QiX2aA3to708s=
golang.org/x/sys v0.0.0-20201113233024-12cec1faf1ba/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.4 h1:0YWbFKbhXG/wIiuHDSKpS0Iy7FSA+u45VtBMfQcFTTc=
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
@ -830,6 +903,7 @@ golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc
golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE=
golang.org/x/tools v0.0.0-20201002184944-ecd9fd270d5d/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU=
golang.org/x/tools v0.0.0-20201017001424-6003fad69a88/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU=
golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
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=
@ -855,6 +929,8 @@ google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz513
google.golang.org/api v0.32.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg=
google.golang.org/api v0.33.0 h1:+gL0XvACeMIvpwLZ5rQZzLn5cwOsgg8dIcfJ2SYfBVw=
google.golang.org/api v0.33.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg=
google.golang.org/api v0.35.0 h1:TBCmTTxUrRDA1iTctnK/fIeitxIZ+TQuaf0j29fmCGo=
google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
@ -905,6 +981,11 @@ google.golang.org/genproto v0.0.0-20201013134114-7f9ee70cb474/go.mod h1:FWY/as6D
google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201022181438-0ff5f38871d5 h1:YejJbGvoWsTXHab4OKNrzk27Dr7s4lPLnewbHue1+gM=
google.golang.org/genproto v0.0.0-20201022181438-0ff5f38871d5/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201111145450-ac7456db90a6 h1:iRN4+t0lvZX/l9gH14ARF9i58tsVa5a97k6aH95rC3Y=
google.golang.org/genproto v0.0.0-20201111145450-ac7456db90a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201113130914-ce600e9a6f9e h1:jRAe+6EDD0LNrVzmjx7FxBivivOZTKnXMbH5lvmxLP8=
google.golang.org/genproto v0.0.0-20201113130914-ce600e9a6f9e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM=
@ -929,6 +1010,8 @@ google.golang.org/grpc v1.33.0 h1:IBKSUNL2uBS2DkJBncPP+TwT0sp9tgA8A75NjHt6umg=
google.golang.org/grpc v1.33.0/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
google.golang.org/grpc v1.33.1 h1:DGeFlSan2f+WEtCERJ4J9GJWk15TxUi8QGagfI87Xyc=
google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
google.golang.org/grpc v1.33.2 h1:EQyQC3sa8M+p6Ulc8yy9SWSS2GVwyRc83gAbG8lrl4o=
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
@ -951,6 +1034,8 @@ gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qS
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o=
gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE=
gopkg.in/go-playground/validator.v9 v9.30.0/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ=
gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.62.0 h1:duBzk771uxoUuOlyRLkHsygud9+5lrlGjdFBb4mSKDU=
gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=

14
main.go
View File

@ -310,11 +310,17 @@ func startServices(ctx context.Context, majordomo majordomo.Service) error {
}
log.Trace().Msg("Starting beacon attestation aggregator")
var aggregationAttester standardattestationaggregator.Parameter
if provider, isProvider := eth2Client.(eth2client.AggregateAttestationProvider); isProvider {
aggregationAttester = standardattestationaggregator.WithAggregateAttestationDataProvider(provider)
} else {
aggregationAttester = standardattestationaggregator.WithPrysmAggregateAttestationDataProvider(eth2Client.(eth2client.PrysmAggregateAttestationProvider))
}
attestationAggregator, err := standardattestationaggregator.New(ctx,
standardattestationaggregator.WithLogLevel(logLevel(viper.GetString("attestationaggregator.log-level"))),
standardattestationaggregator.WithTargetAggregatorsPerCommitteeProvider(eth2Client.(eth2client.TargetAggregatorsPerCommitteeProvider)),
standardattestationaggregator.WithAggregateAttestationDataProvider(eth2Client.(eth2client.AggregateAttestationProvider)),
standardattestationaggregator.WithAggregateAttestationsSubmitter(submitterStrategy.(submitter.AggregateAttestationsSubmitter)),
aggregationAttester,
standardattestationaggregator.WithAggregateAttestationsSubmitter(eth2Client.(eth2client.AggregateAttestationsSubmitter)),
standardattestationaggregator.WithMonitor(monitor.(metrics.AttestationAggregationMonitor)),
standardattestationaggregator.WithValidatingAccountsProvider(accountManager.(accountmanager.ValidatingAccountsProvider)),
)
@ -524,7 +530,7 @@ func startAccountManager(ctx context.Context, monitor metrics.Service, eth2Clien
dirkaccountmanager.WithRANDAODomainProvider(eth2Client.(eth2client.RANDAODomainProvider)),
dirkaccountmanager.WithSelectionProofDomainProvider(eth2Client.(eth2client.SelectionProofDomainProvider)),
dirkaccountmanager.WithAggregateAndProofDomainProvider(eth2Client.(eth2client.AggregateAndProofDomainProvider)),
dirkaccountmanager.WithSignatureDomainProvider(eth2Client.(eth2client.SignatureDomainProvider)),
dirkaccountmanager.WithDomainProvider(eth2Client.(eth2client.DomainProvider)),
dirkaccountmanager.WithClientCert(certPEMBlock),
dirkaccountmanager.WithClientKey(keyPEMBlock),
dirkaccountmanager.WithCACert(caPEMBlock),
@ -563,7 +569,7 @@ func startAccountManager(ctx context.Context, monitor metrics.Service, eth2Clien
walletaccountmanager.WithRANDAODomainProvider(eth2Client.(eth2client.RANDAODomainProvider)),
walletaccountmanager.WithSelectionProofDomainProvider(eth2Client.(eth2client.SelectionProofDomainProvider)),
walletaccountmanager.WithAggregateAndProofDomainProvider(eth2Client.(eth2client.AggregateAndProofDomainProvider)),
walletaccountmanager.WithSignatureDomainProvider(eth2Client.(eth2client.SignatureDomainProvider)),
walletaccountmanager.WithDomainProvider(eth2Client.(eth2client.DomainProvider)),
)
if err != nil {
return nil, errors.Wrap(err, "failed to start wallet account manager service")

View File

@ -22,6 +22,7 @@ import (
"strings"
api "github.com/attestantio/go-eth2-client/api/v1"
spec "github.com/attestantio/go-eth2-client/spec/phase0"
"github.com/attestantio/vouch/services/accountmanager"
"github.com/herumi/bls-eth-go-binary/bls"
"github.com/pkg/errors"
@ -32,12 +33,14 @@ type validatingAccount struct {
key *bls.SecretKey
}
func (a *validatingAccount) PubKey(ctx context.Context) ([]byte, error) {
return a.key.GetPublicKey().Serialize(), nil
func (a *validatingAccount) PubKey(ctx context.Context) (spec.BLSPubKey, error) {
var res spec.BLSPubKey
copy(res[:], a.key.GetPublicKey().Serialize())
return res, nil
}
func (a *validatingAccount) Index(ctx context.Context) (uint64, error) {
return a.index, nil
func (a *validatingAccount) Index(ctx context.Context) (spec.ValidatorIndex, error) {
return spec.ValidatorIndex(a.index), nil
}
func (a *validatingAccount) State() api.ValidatorState {
@ -175,8 +178,8 @@ func (m *ValidatingAccountsProvider) Accounts(ctx context.Context) ([]accountman
}
// AccountsByIndex returns accounts.
func (m *ValidatingAccountsProvider) AccountsByIndex(ctx context.Context, indices []uint64) ([]accountmanager.ValidatingAccount, error) {
indexMap := make(map[uint64]bool)
func (m *ValidatingAccountsProvider) AccountsByIndex(ctx context.Context, indices []spec.ValidatorIndex) ([]accountmanager.ValidatingAccount, error) {
indexMap := make(map[spec.ValidatorIndex]bool)
for _, index := range indices {
indexMap[index] = true
}
@ -195,7 +198,7 @@ func (m *ValidatingAccountsProvider) AccountsByIndex(ctx context.Context, indice
}
// AccountsByPubKey returns accounts.
func (m *ValidatingAccountsProvider) AccountsByPubKey(ctx context.Context, pubKeys [][]byte) ([]accountmanager.ValidatingAccount, error) {
func (m *ValidatingAccountsProvider) AccountsByPubKey(ctx context.Context, pubKeys []spec.BLSPubKey) ([]accountmanager.ValidatingAccount, error) {
keyMap := make(map[string]bool)
for _, pubKey := range pubKeys {
keyMap[fmt.Sprintf("%x", pubKey)] = true

View File

@ -203,7 +203,7 @@ func NewBeaconBlockProposalProvider() eth2client.BeaconBlockProposalProvider {
}
// BeaconBlockProposal is a mock.
func (m *BeaconBlockProposalProvider) BeaconBlockProposal(ctx context.Context, slot uint64, randaoReveal []byte, graffiti []byte) (*spec.BeaconBlock, error) {
func (m *BeaconBlockProposalProvider) BeaconBlockProposal(ctx context.Context, slot spec.Slot, randaoReveal spec.BLSSignature, graffiti []byte) (*spec.BeaconBlock, error) {
// Graffiti should be 32 bytes.
fixedGraffiti := make([]byte, 32)
copy(fixedGraffiti, graffiti)
@ -219,55 +219,55 @@ func (m *BeaconBlockProposalProvider) BeaconBlockProposal(ctx context.Context, s
AggregationBits: aggregationBits,
Data: &spec.AttestationData{
Slot: slot - 1,
Index: i,
BeaconBlockRoot: []byte{
Index: spec.CommitteeIndex(i),
BeaconBlockRoot: spec.Root([32]byte{
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
},
}),
Source: &spec.Checkpoint{
Epoch: 0,
Root: []byte{
Root: spec.Root([32]byte{
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
},
}),
},
Target: &spec.Checkpoint{
Epoch: 1,
Root: []byte{
Root: spec.Root([32]byte{
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
},
}),
},
},
Signature: []byte{
Signature: spec.BLSSignature([96]byte{
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
},
}),
}
}
block := &spec.BeaconBlock{
Slot: slot,
ProposerIndex: 1,
ParentRoot: []byte{
ParentRoot: spec.Root([32]byte{
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
},
StateRoot: []byte{
}),
StateRoot: spec.Root([32]byte{
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
},
}),
Body: &spec.BeaconBlockBody{
RANDAOReveal: randaoReveal,
ETH1Data: &spec.ETH1Data{
DepositRoot: []byte{
DepositRoot: spec.Root([32]byte{
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
},
}),
DepositCount: 16384,
BlockHash: []byte{
0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
@ -295,8 +295,8 @@ func NewBeaconProposerDomainProvider() eth2client.BeaconProposerDomainProvider {
}
// BeaconProposerDomain is a mock.
func (m *BeaconProposerDomainProvider) BeaconProposerDomain(ctx context.Context) ([]byte, error) {
return []byte{0x00, 0x00, 0x00, 0x00}, nil
func (m *BeaconProposerDomainProvider) BeaconProposerDomain(ctx context.Context) (spec.DomainType, error) {
return spec.DomainType{0x00, 0x00, 0x00, 0x00}, nil
}
// ErroringBeaconProposerDomainProvider is a mock for eth2client.BeaconProposerDomainProvider.
@ -308,8 +308,8 @@ func NewErroringBeaconProposerDomainProvider() eth2client.BeaconProposerDomainPr
}
// BeaconProposerDomain is a mock.
func (m *ErroringBeaconProposerDomainProvider) BeaconProposerDomain(ctx context.Context) ([]byte, error) {
return nil, errors.New("error")
func (m *ErroringBeaconProposerDomainProvider) BeaconProposerDomain(ctx context.Context) (spec.DomainType, error) {
return spec.DomainType{}, errors.New("error")
}
// BeaconAttesterDomainProvider is a mock for eth2client.BeaconAttesterDomainProvider.
@ -321,8 +321,8 @@ func NewBeaconAttesterDomainProvider() eth2client.BeaconAttesterDomainProvider {
}
// BeaconAttesterDomain is a mock.
func (m *BeaconAttesterDomainProvider) BeaconAttesterDomain(ctx context.Context) ([]byte, error) {
return []byte{0x01, 0x00, 0x00, 0x00}, nil
func (m *BeaconAttesterDomainProvider) BeaconAttesterDomain(ctx context.Context) (spec.DomainType, error) {
return spec.DomainType{0x01, 0x00, 0x00, 0x00}, nil
}
// ErroringBeaconAttesterDomainProvider is a mock for eth2client.BeaconAttesterDomainProvider.
@ -334,8 +334,8 @@ func NewErroringBeaconAttesterDomainProvider() eth2client.BeaconAttesterDomainPr
}
// BeaconAttesterDomain is a mock.
func (m *ErroringBeaconAttesterDomainProvider) BeaconAttesterDomain(ctx context.Context) ([]byte, error) {
return nil, errors.New("error")
func (m *ErroringBeaconAttesterDomainProvider) BeaconAttesterDomain(ctx context.Context) (spec.DomainType, error) {
return spec.DomainType{}, errors.New("error")
}
// RANDAODomainProvider is a mock for eth2client.RANDAODomainProvider.
@ -347,8 +347,8 @@ func NewRANDAODomainProvider() eth2client.RANDAODomainProvider {
}
// RANDAODomain is a mock.
func (m *RANDAODomainProvider) RANDAODomain(ctx context.Context) ([]byte, error) {
return []byte{0x02, 0x00, 0x00, 0x00}, nil
func (m *RANDAODomainProvider) RANDAODomain(ctx context.Context) (spec.DomainType, error) {
return spec.DomainType{0x02, 0x00, 0x00, 0x00}, nil
}
// ErroringRANDAODomainProvider is a mock for eth2client.RANDAODomainProvider.
@ -360,8 +360,8 @@ func NewErroringRANDAODomainProvider() eth2client.RANDAODomainProvider {
}
// RANDAODomain is a mock.
func (m *ErroringRANDAODomainProvider) RANDAODomain(ctx context.Context) ([]byte, error) {
return nil, errors.New("error")
func (m *ErroringRANDAODomainProvider) RANDAODomain(ctx context.Context) (spec.DomainType, error) {
return spec.DomainType{}, errors.New("error")
}
// DepositDomainProvider is a mock for eth2client.DepositDomainProvider.
@ -373,8 +373,8 @@ func NewDepositDomainProvider() eth2client.DepositDomainProvider {
}
// DepositDomain is a mock.
func (m *DepositDomainProvider) DepositDomain(ctx context.Context) ([]byte, error) {
return []byte{0x03, 0x00, 0x00, 0x00}, nil
func (m *DepositDomainProvider) DepositDomain(ctx context.Context) (spec.DomainType, error) {
return spec.DomainType{0x03, 0x00, 0x00, 0x00}, nil
}
// ErroringDepositDomainProvider is a mock for eth2client.DepositDomainProvider.
@ -386,8 +386,8 @@ func NewErroringDepositDomainProvider() eth2client.DepositDomainProvider {
}
// DepositDomain is a mock.
func (m *ErroringDepositDomainProvider) DepositDomain(ctx context.Context) ([]byte, error) {
return nil, errors.New("error")
func (m *ErroringDepositDomainProvider) DepositDomain(ctx context.Context) (spec.DomainType, error) {
return spec.DomainType{}, errors.New("error")
}
// VoluntaryExitDomainProvider is a mock for eth2client.VoluntaryExitDomainProvider.
@ -399,8 +399,8 @@ func NewVoluntaryExitDomainProvider() eth2client.VoluntaryExitDomainProvider {
}
// VoluntaryExitDomain is a mock.
func (m *VoluntaryExitDomainProvider) VoluntaryExitDomain(ctx context.Context) ([]byte, error) {
return []byte{0x04, 0x00, 0x00, 0x00}, nil
func (m *VoluntaryExitDomainProvider) VoluntaryExitDomain(ctx context.Context) (spec.DomainType, error) {
return spec.DomainType{0x04, 0x00, 0x00, 0x00}, nil
}
// ErroringVoluntaryExitDomainProvider is a mock for eth2client.VoluntaryExitDomainProvider.
@ -412,8 +412,8 @@ func NewErroringVoluntaryExitDomainProvider() eth2client.VoluntaryExitDomainProv
}
// VoluntaryExitDomain is a mock.
func (m *ErroringVoluntaryExitDomainProvider) VoluntaryExitDomain(ctx context.Context) ([]byte, error) {
return nil, errors.New("error")
func (m *ErroringVoluntaryExitDomainProvider) VoluntaryExitDomain(ctx context.Context) (spec.DomainType, error) {
return spec.DomainType{}, errors.New("error")
}
// SelectionProofDomainProvider is a mock for eth2client.SelectionProofDomainProvider.
@ -425,8 +425,8 @@ func NewSelectionProofDomainProvider() eth2client.SelectionProofDomainProvider {
}
// SelectionProofDomain is a mock.
func (m *SelectionProofDomainProvider) SelectionProofDomain(ctx context.Context) ([]byte, error) {
return []byte{0x05, 0x00, 0x00, 0x00}, nil
func (m *SelectionProofDomainProvider) SelectionProofDomain(ctx context.Context) (spec.DomainType, error) {
return spec.DomainType{0x05, 0x00, 0x00, 0x00}, nil
}
// ErroringSelectionProofDomainProvider is a mock for eth2client.SelectionProofDomainProvider.
@ -438,8 +438,8 @@ func NewErroringSelectionProofDomainProvider() eth2client.SelectionProofDomainPr
}
// SelectionProofDomain is a mock.
func (m *ErroringSelectionProofDomainProvider) SelectionProofDomain(ctx context.Context) ([]byte, error) {
return nil, errors.New("error")
func (m *ErroringSelectionProofDomainProvider) SelectionProofDomain(ctx context.Context) (spec.DomainType, error) {
return spec.DomainType{}, errors.New("error")
}
// AggregateAndProofDomainProvider is a mock for eth2client.AggregateAndProofDomainProvider.
@ -451,8 +451,8 @@ func NewAggregateAndProofDomainProvider() eth2client.AggregateAndProofDomainProv
}
// AggregateAndProofDomain is a mock.
func (m *AggregateAndProofDomainProvider) AggregateAndProofDomain(ctx context.Context) ([]byte, error) {
return []byte{0x06, 0x00, 0x00, 0x00}, nil
func (m *AggregateAndProofDomainProvider) AggregateAndProofDomain(ctx context.Context) (spec.DomainType, error) {
return spec.DomainType{0x06, 0x00, 0x00, 0x00}, nil
}
// ErroringAggregateAndProofDomainProvider is a mock for eth2client.AggregateAndProofDomainProvider.
@ -464,38 +464,38 @@ func NewErroringAggregateAndProofDomainProvider() eth2client.AggregateAndProofDo
}
// AggregateAndProofDomain is a mock.
func (m *ErroringAggregateAndProofDomainProvider) AggregateAndProofDomain(ctx context.Context) ([]byte, error) {
return nil, errors.New("error")
func (m *ErroringAggregateAndProofDomainProvider) AggregateAndProofDomain(ctx context.Context) (spec.DomainType, error) {
return spec.DomainType{}, errors.New("error")
}
// SignatureDomainProvider is a mock for eth2client.SignatureDomainProvider.
type SignatureDomainProvider struct{}
// DomainProvider is a mock for eth2client.DomainProvider.
type DomainProvider struct{}
// NewSignatureDomainProvider returns a mock signature domain provider.
func NewSignatureDomainProvider() eth2client.SignatureDomainProvider {
return &SignatureDomainProvider{}
// NewDomainProvider returns a mock domain provider.
func NewDomainProvider() eth2client.DomainProvider {
return &DomainProvider{}
}
// SignatureDomain is a mock.
func (m *SignatureDomainProvider) SignatureDomain(ctx context.Context, domain []byte, epoch uint64) ([]byte, error) {
var signatureDomain [32]byte
// Put the domain in the first four bytes, to differentiate signatures.
copy(signatureDomain[:], domain)
// Domain is a mock.
func (m *DomainProvider) Domain(ctx context.Context, domainType spec.DomainType, epoch spec.Epoch) (spec.Domain, error) {
var domain spec.Domain
// Put the domain type in the first four bytes, to differentiate signatures.
copy(domain[:], domainType[:])
return signatureDomain[:], nil
return domain, nil
}
// ErroringSignatureDomainProvider is a mock for eth2client.SignatureDomainProvider.
type ErroringSignatureDomainProvider struct{}
// ErroringDomainProvider is a mock for eth2client.DomainProvider.
type ErroringDomainProvider struct{}
// NewErroringSignatureDomainProvider returns a mock signature domain provider that errors.
func NewErroringSignatureDomainProvider() eth2client.SignatureDomainProvider {
return &SignatureDomainProvider{}
// NewErroringDomainProvider returns a mock signature domain provider that errors.
func NewErroringDomainProvider() eth2client.DomainProvider {
return &ErroringDomainProvider{}
}
// SignatureDomain is a mock.
func (m *ErroringSignatureDomainProvider) SignatureDomain(ctx context.Context, domain []byte, epoch uint64) ([]byte, error) {
return nil, errors.New("error")
// Domain is a mock.
func (m *ErroringDomainProvider) Domain(ctx context.Context, domainType spec.DomainType, epoch spec.Epoch) (spec.Domain, error) {
return spec.Domain{}, errors.New("error")
}
// ValidatorsProvider is a mock for eth2client.ValidatorsProvider.
@ -511,13 +511,20 @@ func _byte(input string) []byte {
return res
}
func _epochValidator(index uint64, pubKey string, withdrwalCredentials string) *api.Validator {
func _blsPubKey(input string) spec.BLSPubKey {
tmp, _ := hex.DecodeString(strings.TrimPrefix(input, "0x"))
var res spec.BLSPubKey
copy(res[:], tmp)
return res
}
func _epochValidator(index spec.ValidatorIndex, pubKey string, withdrwalCredentials string) *api.Validator {
return &api.Validator{
Index: index,
Balance: 32000000000,
Status: api.ValidatorStateActiveOngoing,
Validator: &spec.Validator{
PublicKey: _byte(pubKey),
PublicKey: _blsPubKey(pubKey),
WithdrawalCredentials: _byte(withdrwalCredentials),
EffectiveBalance: 32000000,
Slashed: false,
@ -530,8 +537,8 @@ func _epochValidator(index uint64, pubKey string, withdrwalCredentials string) *
}
// Validators is a mock.
func (m *ValidatorsProvider) Validators(ctx context.Context, stateID string, validators []uint64) (map[uint64]*api.Validator, error) {
return map[uint64]*api.Validator{
func (m *ValidatorsProvider) Validators(ctx context.Context, stateID string, validators []spec.ValidatorIndex) (map[spec.ValidatorIndex]*api.Validator, error) {
return map[spec.ValidatorIndex]*api.Validator{
0: _epochValidator(0,
"0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c",
"0x00fad2a6bfb0e7f1f0f45460944fbd8dfa7f37da06a4d13b3983cc90bb46963b"),
@ -632,8 +639,8 @@ func (m *ValidatorsProvider) Validators(ctx context.Context, stateID string, val
}
// ValidatorsByPubKey is a mock.
func (m *ValidatorsProvider) ValidatorsByPubKey(ctx context.Context, stateID string, validators [][]byte) (map[uint64]*api.Validator, error) {
return map[uint64]*api.Validator{
func (m *ValidatorsProvider) ValidatorsByPubKey(ctx context.Context, stateID string, validators []spec.BLSPubKey) (map[spec.ValidatorIndex]*api.Validator, error) {
return map[spec.ValidatorIndex]*api.Validator{
0: _epochValidator(0,
"0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c",
"0x00fad2a6bfb0e7f1f0f45460944fbd8dfa7f37da06a4d13b3983cc90bb46963b"),
@ -742,8 +749,8 @@ func NewValidatorsWithoutBalanceProvider() eth2client.ValidatorsProvider {
}
// Validators is a mock.
func (m *ValidatorsWithoutBalanceProvider) Validators(ctx context.Context, stateID string, validators []uint64) (map[uint64]*api.Validator, error) {
return map[uint64]*api.Validator{
func (m *ValidatorsWithoutBalanceProvider) Validators(ctx context.Context, stateID string, validators []spec.ValidatorIndex) (map[spec.ValidatorIndex]*api.Validator, error) {
return map[spec.ValidatorIndex]*api.Validator{
0: _epochValidator(0,
"0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c",
"0x00fad2a6bfb0e7f1f0f45460944fbd8dfa7f37da06a4d13b3983cc90bb46963b"),
@ -844,8 +851,8 @@ func (m *ValidatorsWithoutBalanceProvider) Validators(ctx context.Context, state
}
// ValidatorsByPubKey is a mock.
func (m *ValidatorsWithoutBalanceProvider) ValidatorsByPubKey(ctx context.Context, stateID string, validators [][]byte) (map[uint64]*api.Validator, error) {
return map[uint64]*api.Validator{
func (m *ValidatorsWithoutBalanceProvider) ValidatorsByPubKey(ctx context.Context, stateID string, validators []spec.BLSPubKey) (map[spec.ValidatorIndex]*api.Validator, error) {
return map[spec.ValidatorIndex]*api.Validator{
0: _epochValidator(0,
"0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c",
"0x00fad2a6bfb0e7f1f0f45460944fbd8dfa7f37da06a4d13b3983cc90bb46963b"),
@ -946,8 +953,8 @@ func (m *ValidatorsWithoutBalanceProvider) ValidatorsByPubKey(ctx context.Contex
}
// ValidatorsWithoutBalance is a mock.
func (m *ValidatorsWithoutBalanceProvider) ValidatorsWithoutBalance(ctx context.Context, stateID string, validators []eth2client.ValidatorIDProvider) (map[uint64]*api.Validator, error) {
res := map[uint64]*api.Validator{
func (m *ValidatorsWithoutBalanceProvider) ValidatorsWithoutBalance(ctx context.Context, stateID string, validators []spec.ValidatorIndex) (map[spec.ValidatorIndex]*api.Validator, error) {
res := map[spec.ValidatorIndex]*api.Validator{
0: _epochValidator(0,
"0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c",
"0x00fad2a6bfb0e7f1f0f45460944fbd8dfa7f37da06a4d13b3983cc90bb46963b"),

View File

@ -38,7 +38,7 @@ type parameters struct {
randaoDomainProvider eth2client.RANDAODomainProvider
selectionProofDomainProvider eth2client.SelectionProofDomainProvider
aggregateAndProofDomainProvider eth2client.AggregateAndProofDomainProvider
signatureDomainProvider eth2client.SignatureDomainProvider
domainProvider eth2client.DomainProvider
validatorsProvider eth2client.ValidatorsProvider
}
@ -158,10 +158,10 @@ func WithAggregateAndProofDomainProvider(provider eth2client.AggregateAndProofDo
})
}
// WithSignatureDomainProvider sets the signature domain provider.
func WithSignatureDomainProvider(provider eth2client.SignatureDomainProvider) Parameter {
// WithDomainProvider sets the signature domain provider.
func WithDomainProvider(provider eth2client.DomainProvider) Parameter {
return parameterFunc(func(p *parameters) {
p.signatureDomainProvider = provider
p.domainProvider = provider
})
}
@ -217,8 +217,8 @@ func parseAndCheckParameters(params ...Parameter) (*parameters, error) {
if parameters.aggregateAndProofDomainProvider == nil {
return nil, errors.New("no aggregate and proof domain provider specified")
}
if parameters.signatureDomainProvider == nil {
return nil, errors.New("no signature domain provider specified")
if parameters.domainProvider == nil {
return nil, errors.New("no domain provider specified")
}
return &parameters, nil

View File

@ -26,6 +26,7 @@ import (
eth2client "github.com/attestantio/go-eth2-client"
api "github.com/attestantio/go-eth2-client/api/v1"
spec "github.com/attestantio/go-eth2-client/spec/phase0"
"github.com/attestantio/vouch/services/accountmanager"
"github.com/attestantio/vouch/services/metrics"
"github.com/pkg/errors"
@ -39,21 +40,21 @@ import (
// Service is the manager for dirk accounts.
type Service struct {
mutex sync.RWMutex
monitor metrics.AccountManagerMonitor
clientMonitor metrics.ClientMonitor
endpoints []*dirk.Endpoint
accountPaths []string
credentials credentials.TransportCredentials
accounts map[[48]byte]*ValidatingAccount
validatorsProvider eth2client.ValidatorsProvider
slotsPerEpoch uint64
beaconProposerDomain []byte
beaconAttesterDomain []byte
randaoDomain []byte
selectionProofDomain []byte
aggregateAndProofDomain []byte
signatureDomainProvider eth2client.SignatureDomainProvider
mutex sync.RWMutex
monitor metrics.AccountManagerMonitor
clientMonitor metrics.ClientMonitor
endpoints []*dirk.Endpoint
accountPaths []string
credentials credentials.TransportCredentials
accounts map[spec.BLSPubKey]*ValidatingAccount
validatorsProvider eth2client.ValidatorsProvider
slotsPerEpoch spec.Slot
beaconProposerDomainType spec.DomainType
beaconAttesterDomainType spec.DomainType
randaoDomainType spec.DomainType
selectionProofDomainType spec.DomainType
aggregateAndProofDomainType spec.DomainType
domainProvider eth2client.DomainProvider
}
// module-wide log.
@ -103,41 +104,41 @@ func New(ctx context.Context, params ...Parameter) (*Service, error) {
if err != nil {
return nil, errors.Wrap(err, "failed to obtain slots per epoch")
}
beaconAttesterDomain, err := parameters.beaconAttesterDomainProvider.BeaconAttesterDomain(ctx)
beaconAttesterDomainType, err := parameters.beaconAttesterDomainProvider.BeaconAttesterDomain(ctx)
if err != nil {
return nil, errors.Wrap(err, "failed to obtain beacon attester domain")
}
beaconProposerDomain, err := parameters.beaconProposerDomainProvider.BeaconProposerDomain(ctx)
beaconProposerDomainType, err := parameters.beaconProposerDomainProvider.BeaconProposerDomain(ctx)
if err != nil {
return nil, errors.Wrap(err, "failed to obtain beacon proposer domain")
}
randaoDomain, err := parameters.randaoDomainProvider.RANDAODomain(ctx)
randaoDomainType, err := parameters.randaoDomainProvider.RANDAODomain(ctx)
if err != nil {
return nil, errors.Wrap(err, "failed to obtain RANDAO domain")
}
selectionProofDomain, err := parameters.selectionProofDomainProvider.SelectionProofDomain(ctx)
selectionProofDomainType, err := parameters.selectionProofDomainProvider.SelectionProofDomain(ctx)
if err != nil {
return nil, errors.Wrap(err, "failed to obtain selection proof domain")
}
aggregateAndProofDomain, err := parameters.aggregateAndProofDomainProvider.AggregateAndProofDomain(ctx)
aggregateAndProofDomainType, err := parameters.aggregateAndProofDomainProvider.AggregateAndProofDomain(ctx)
if err != nil {
return nil, errors.Wrap(err, "failed to obtain aggregate and proof domain")
}
s := &Service{
monitor: parameters.monitor,
clientMonitor: parameters.clientMonitor,
endpoints: endpoints,
accountPaths: parameters.accountPaths,
credentials: credentials,
slotsPerEpoch: slotsPerEpoch,
beaconAttesterDomain: beaconAttesterDomain,
beaconProposerDomain: beaconProposerDomain,
randaoDomain: randaoDomain,
selectionProofDomain: selectionProofDomain,
aggregateAndProofDomain: aggregateAndProofDomain,
signatureDomainProvider: parameters.signatureDomainProvider,
validatorsProvider: parameters.validatorsProvider,
monitor: parameters.monitor,
clientMonitor: parameters.clientMonitor,
endpoints: endpoints,
accountPaths: parameters.accountPaths,
credentials: credentials,
slotsPerEpoch: spec.Slot(slotsPerEpoch),
beaconAttesterDomainType: beaconAttesterDomainType,
beaconProposerDomainType: beaconProposerDomainType,
randaoDomainType: randaoDomainType,
selectionProofDomainType: selectionProofDomainType,
aggregateAndProofDomainType: aggregateAndProofDomainType,
domainProvider: parameters.domainProvider,
validatorsProvider: parameters.validatorsProvider,
}
if err := s.RefreshAccounts(ctx); err != nil {
@ -161,8 +162,9 @@ func (s *Service) UpdateAccountsState(ctx context.Context) error {
log.Trace().Msg("No unactivated keys")
return nil
}
// TODO unactivated validators can have an index of 0, so cannot send via an API call that is by index. Need to use bypubkeys.
log.Trace().Int("total", len(s.accounts)).Int("unactivated", len(validatorIDProviders)).Msg("Updating state of unactivated keys")
var validators map[uint64]*api.Validator
var validators map[spec.ValidatorIndex]*api.Validator
var err error
if validatorsWithoutBalanceProvider, isProvider := s.validatorsProvider.(eth2client.ValidatorsWithoutBalanceProvider); isProvider {
started := time.Now()
@ -177,7 +179,7 @@ func (s *Service) UpdateAccountsState(ctx context.Context) error {
}
} else {
started := time.Now()
validatorIDs := make([]uint64, 0, len(s.accounts))
validatorIDs := make([]spec.ValidatorIndex, 0, len(s.accounts))
for _, account := range s.accounts {
if !account.state.HasActivated() {
index, err := account.Index(ctx)
@ -230,7 +232,7 @@ func (s *Service) RefreshAccounts(ctx context.Context) error {
verificationRegexes := accountPathsToVerificationRegexes(s.accountPaths)
// Fetch accounts for each wallet.
accounts := make(map[[48]byte]*ValidatingAccount)
accounts := make(map[spec.BLSPubKey]*ValidatingAccount)
for _, wallet := range wallets {
// if _, isProvider := wallet.(e2wtypes.WalletAccountsByPathProvider); isProvider {
// fmt.Printf("TODO: fetch accounts by path")
@ -240,7 +242,7 @@ func (s *Service) RefreshAccounts(ctx context.Context) error {
}
// Update indices for accounts.
pubKeys := make([][]byte, 0, len(accounts))
pubKeys := make([]spec.BLSPubKey, 0, len(accounts))
for _, account := range accounts {
pubKey, err := account.PubKey(ctx)
if err != nil {
@ -326,8 +328,8 @@ func (s *Service) Accounts(ctx context.Context) ([]accountmanager.ValidatingAcco
}
// AccountsByIndex returns attesting accounts.
func (s *Service) AccountsByIndex(ctx context.Context, indices []uint64) ([]accountmanager.ValidatingAccount, error) {
indexMap := make(map[uint64]bool)
func (s *Service) AccountsByIndex(ctx context.Context, indices []spec.ValidatorIndex) ([]accountmanager.ValidatingAccount, error) {
indexMap := make(map[spec.ValidatorIndex]bool)
for _, index := range indices {
indexMap[index] = true
}
@ -355,12 +357,10 @@ func (s *Service) AccountsByIndex(ctx context.Context, indices []uint64) ([]acco
}
// AccountsByPubKey returns validating accounts.
func (s *Service) AccountsByPubKey(ctx context.Context, pubKeys [][]byte) ([]accountmanager.ValidatingAccount, error) {
pubKeyMap := make(map[[48]byte]bool)
func (s *Service) AccountsByPubKey(ctx context.Context, pubKeys []spec.BLSPubKey) ([]accountmanager.ValidatingAccount, error) {
pubKeyMap := make(map[spec.BLSPubKey]bool)
for _, pubKey := range pubKeys {
var mapKey [48]byte
copy(mapKey[:], pubKey)
pubKeyMap[mapKey] = true
pubKeyMap[pubKey] = true
}
s.mutex.RLock()
@ -410,12 +410,10 @@ func accountPathsToVerificationRegexes(paths []string) []*regexp.Regexp {
return regexes
}
func (s *Service) updateAccountStates(ctx context.Context, accounts map[[48]byte]*ValidatingAccount, validators map[uint64]*api.Validator) {
func (s *Service) updateAccountStates(ctx context.Context, accounts map[spec.BLSPubKey]*ValidatingAccount, validators map[spec.ValidatorIndex]*api.Validator) {
validatorsByPubKey := make(map[[48]byte]*api.Validator, len(validators))
for _, validator := range validators {
var pubKey [48]byte
copy(pubKey[:], validator.Validator.PublicKey)
validatorsByPubKey[pubKey] = validator
validatorsByPubKey[validator.Validator.PublicKey] = validator
}
validatorStateCounts := make(map[string]uint64)
@ -441,7 +439,7 @@ func (s *Service) updateAccountStates(ctx context.Context, accounts map[[48]byte
}
}
func (s *Service) fetchAccountsForWallet(ctx context.Context, wallet e2wtypes.Wallet, accounts map[[48]byte]*ValidatingAccount, verificationRegexes []*regexp.Regexp) {
func (s *Service) fetchAccountsForWallet(ctx context.Context, wallet e2wtypes.Wallet, accounts map[spec.BLSPubKey]*ValidatingAccount, verificationRegexes []*regexp.Regexp) {
for account := range wallet.Accounts(ctx) {
// Ensure the name matches one of our account paths.
name := fmt.Sprintf("%s/%s", wallet.Name(), account.Name())
@ -466,9 +464,9 @@ func (s *Service) fetchAccountsForWallet(ctx context.Context, wallet e2wtypes.Wa
// Set up account as unknown to beacon chain.
accounts[bytesutil.ToBytes48(pubKey)] = &ValidatingAccount{
account: account,
accountManager: s,
signatureDomainProvider: s.signatureDomainProvider,
account: account,
accountManager: s,
domainProvider: s.domainProvider,
}
}
}

View File

@ -23,6 +23,7 @@ import (
"github.com/attestantio/dirk/testing/daemon"
api "github.com/attestantio/go-eth2-client/api/v1"
spec "github.com/attestantio/go-eth2-client/spec/phase0"
"github.com/attestantio/vouch/mock"
nullmetrics "github.com/attestantio/vouch/services/metrics/null"
"github.com/attestantio/vouch/testing/logger"
@ -57,9 +58,9 @@ func TestFetchAccountsForWallet(t *testing.T) {
// Test with wallet regex.
s, err := setupService(ctx, t, []string{"localhost:12345"}, []string{"wallet1", "wallet2"})
require.NoError(t, err)
validatingAccounts := make(map[[48]byte]*ValidatingAccount)
validatingAccounts := make(map[spec.BLSPubKey]*ValidatingAccount)
for account := range wallets[0].Accounts(ctx) {
var key [48]byte
var key spec.BLSPubKey
copy(key[:], account.PublicKey().Marshal())
validatingAccounts[key] = &ValidatingAccount{
account: account,
@ -76,9 +77,9 @@ func TestFetchAccountsForWallet(t *testing.T) {
capture := logger.NewLogCapture()
s, err = setupService(ctx, t, []string{"localhost:12345"}, []string{"wallet1", "wallet2"})
require.NoError(t, err)
validatingAccounts = make(map[[48]byte]*ValidatingAccount)
validatingAccounts = make(map[spec.BLSPubKey]*ValidatingAccount)
for account := range wallets[0].Accounts(ctx) {
var key [48]byte
var key spec.BLSPubKey
copy(key[:], account.PublicKey().Marshal())
validatingAccounts[key] = &ValidatingAccount{
account: account,
@ -180,7 +181,7 @@ func TestAccountPathsToVerificationRegexes(t *testing.T) {
func TestAccounts(t *testing.T) {
tests := []struct {
name string
accounts map[[48]byte]*ValidatingAccount
accounts map[spec.BLSPubKey]*ValidatingAccount
expected int
}{
{
@ -260,7 +261,7 @@ func TestUpdateAccountsStateWithoutBalances(t *testing.T) {
WithRANDAODomainProvider(mock.NewRANDAODomainProvider()),
WithSelectionProofDomainProvider(mock.NewSelectionProofDomainProvider()),
WithAggregateAndProofDomainProvider(mock.NewAggregateAndProofDomainProvider()),
WithSignatureDomainProvider(mock.NewSignatureDomainProvider()),
WithDomainProvider(mock.NewDomainProvider()),
)
require.NoError(t, err)
accounts, err := s.Accounts(ctx)
@ -301,7 +302,7 @@ func setupService(ctx context.Context, t *testing.T, endpoints []string, account
WithRANDAODomainProvider(mock.NewRANDAODomainProvider()),
WithSelectionProofDomainProvider(mock.NewSelectionProofDomainProvider()),
WithAggregateAndProofDomainProvider(mock.NewAggregateAndProofDomainProvider()),
WithSignatureDomainProvider(mock.NewSignatureDomainProvider()),
WithDomainProvider(mock.NewDomainProvider()),
)
}

View File

@ -23,11 +23,13 @@ import (
"time"
"github.com/attestantio/dirk/testing/daemon"
spec "github.com/attestantio/go-eth2-client/spec/phase0"
"github.com/attestantio/vouch/mock"
"github.com/attestantio/vouch/services/accountmanager/dirk"
nullmetrics "github.com/attestantio/vouch/services/metrics/null"
"github.com/attestantio/vouch/testing/logger"
"github.com/attestantio/vouch/testing/resources"
"github.com/attestantio/vouch/testutil"
"github.com/rs/zerolog"
"github.com/stretchr/testify/require"
)
@ -37,6 +39,36 @@ func _byte(input string) []byte {
return res
}
func _root(input string) spec.Root {
res, err := hex.DecodeString(strings.TrimPrefix(input, "0x"))
if err != nil {
panic(err)
}
var root spec.Root
copy(root[:], res)
return root
}
func _sig(input string) spec.BLSSignature {
res, err := hex.DecodeString(strings.TrimPrefix(input, "0x"))
if err != nil {
panic(err)
}
var sig spec.BLSSignature
copy(sig[:], res)
return sig
}
func _pubKey(input string) spec.BLSPubKey {
res, err := hex.DecodeString(strings.TrimPrefix(input, "0x"))
if err != nil {
panic(err)
}
var pubKey spec.BLSPubKey
copy(pubKey[:], res)
return pubKey
}
func TestService(t *testing.T) {
slotsPerEpochProvider := mock.NewSlotsPerEpochProvider(32)
beaconProposerDomainProvider := mock.NewBeaconProposerDomainProvider()
@ -44,7 +76,7 @@ func TestService(t *testing.T) {
randaoDomainProvider := mock.NewRANDAODomainProvider()
selectionProofDomainProvider := mock.NewSelectionProofDomainProvider()
aggregateAndProofDomainProvider := mock.NewAggregateAndProofDomainProvider()
signatureDomainProvider := mock.NewSignatureDomainProvider()
domainProvider := mock.NewDomainProvider()
validatorsProvider := mock.NewValidatorsProvider()
tests := []struct {
@ -71,7 +103,7 @@ func TestService(t *testing.T) {
dirk.WithRANDAODomainProvider(randaoDomainProvider),
dirk.WithSelectionProofDomainProvider(selectionProofDomainProvider),
dirk.WithAggregateAndProofDomainProvider(aggregateAndProofDomainProvider),
dirk.WithSignatureDomainProvider(signatureDomainProvider),
dirk.WithDomainProvider(domainProvider),
},
err: "problem with parameters: no monitor specified",
},
@ -93,7 +125,7 @@ func TestService(t *testing.T) {
dirk.WithRANDAODomainProvider(randaoDomainProvider),
dirk.WithSelectionProofDomainProvider(selectionProofDomainProvider),
dirk.WithAggregateAndProofDomainProvider(aggregateAndProofDomainProvider),
dirk.WithSignatureDomainProvider(signatureDomainProvider),
dirk.WithDomainProvider(domainProvider),
},
err: "problem with parameters: no client monitor specified",
},
@ -114,7 +146,7 @@ func TestService(t *testing.T) {
dirk.WithRANDAODomainProvider(randaoDomainProvider),
dirk.WithSelectionProofDomainProvider(selectionProofDomainProvider),
dirk.WithAggregateAndProofDomainProvider(aggregateAndProofDomainProvider),
dirk.WithSignatureDomainProvider(signatureDomainProvider),
dirk.WithDomainProvider(domainProvider),
},
err: "problem with parameters: no endpoints specified",
},
@ -136,7 +168,7 @@ func TestService(t *testing.T) {
dirk.WithRANDAODomainProvider(randaoDomainProvider),
dirk.WithSelectionProofDomainProvider(selectionProofDomainProvider),
dirk.WithAggregateAndProofDomainProvider(aggregateAndProofDomainProvider),
dirk.WithSignatureDomainProvider(signatureDomainProvider),
dirk.WithDomainProvider(domainProvider),
},
err: "problem with parameters: no endpoints specified",
},
@ -158,7 +190,7 @@ func TestService(t *testing.T) {
dirk.WithRANDAODomainProvider(randaoDomainProvider),
dirk.WithSelectionProofDomainProvider(selectionProofDomainProvider),
dirk.WithAggregateAndProofDomainProvider(aggregateAndProofDomainProvider),
dirk.WithSignatureDomainProvider(signatureDomainProvider),
dirk.WithDomainProvider(domainProvider),
},
err: "no valid endpoints specified",
logEntry: "Malformed endpoint",
@ -181,7 +213,7 @@ func TestService(t *testing.T) {
dirk.WithRANDAODomainProvider(randaoDomainProvider),
dirk.WithSelectionProofDomainProvider(selectionProofDomainProvider),
dirk.WithAggregateAndProofDomainProvider(aggregateAndProofDomainProvider),
dirk.WithSignatureDomainProvider(signatureDomainProvider),
dirk.WithDomainProvider(domainProvider),
},
err: "no valid endpoints specified",
logEntry: "Malformed port",
@ -204,7 +236,7 @@ func TestService(t *testing.T) {
dirk.WithRANDAODomainProvider(randaoDomainProvider),
dirk.WithSelectionProofDomainProvider(selectionProofDomainProvider),
dirk.WithAggregateAndProofDomainProvider(aggregateAndProofDomainProvider),
dirk.WithSignatureDomainProvider(signatureDomainProvider),
dirk.WithDomainProvider(domainProvider),
},
err: "no valid endpoints specified",
logEntry: "Invalid port",
@ -226,7 +258,7 @@ func TestService(t *testing.T) {
dirk.WithRANDAODomainProvider(randaoDomainProvider),
dirk.WithSelectionProofDomainProvider(selectionProofDomainProvider),
dirk.WithAggregateAndProofDomainProvider(aggregateAndProofDomainProvider),
dirk.WithSignatureDomainProvider(signatureDomainProvider),
dirk.WithDomainProvider(domainProvider),
},
err: "problem with parameters: no account paths specified",
},
@ -248,7 +280,7 @@ func TestService(t *testing.T) {
dirk.WithRANDAODomainProvider(randaoDomainProvider),
dirk.WithSelectionProofDomainProvider(selectionProofDomainProvider),
dirk.WithAggregateAndProofDomainProvider(aggregateAndProofDomainProvider),
dirk.WithSignatureDomainProvider(signatureDomainProvider),
dirk.WithDomainProvider(domainProvider),
},
err: "problem with parameters: no account paths specified",
},
@ -269,7 +301,7 @@ func TestService(t *testing.T) {
dirk.WithRANDAODomainProvider(randaoDomainProvider),
dirk.WithSelectionProofDomainProvider(selectionProofDomainProvider),
dirk.WithAggregateAndProofDomainProvider(aggregateAndProofDomainProvider),
dirk.WithSignatureDomainProvider(signatureDomainProvider),
dirk.WithDomainProvider(domainProvider),
},
err: "problem with parameters: no client certificate specified",
},
@ -290,7 +322,7 @@ func TestService(t *testing.T) {
dirk.WithRANDAODomainProvider(randaoDomainProvider),
dirk.WithSelectionProofDomainProvider(selectionProofDomainProvider),
dirk.WithAggregateAndProofDomainProvider(aggregateAndProofDomainProvider),
dirk.WithSignatureDomainProvider(signatureDomainProvider),
dirk.WithDomainProvider(domainProvider),
},
err: "problem with parameters: no client key specified",
},
@ -312,7 +344,7 @@ func TestService(t *testing.T) {
dirk.WithRANDAODomainProvider(randaoDomainProvider),
dirk.WithSelectionProofDomainProvider(selectionProofDomainProvider),
dirk.WithAggregateAndProofDomainProvider(aggregateAndProofDomainProvider),
dirk.WithSignatureDomainProvider(signatureDomainProvider),
dirk.WithDomainProvider(domainProvider),
},
err: "failed to build credentials: failed to load client keypair: tls: private key does not match public key",
},
@ -333,7 +365,7 @@ func TestService(t *testing.T) {
dirk.WithRANDAODomainProvider(randaoDomainProvider),
dirk.WithSelectionProofDomainProvider(selectionProofDomainProvider),
dirk.WithAggregateAndProofDomainProvider(aggregateAndProofDomainProvider),
dirk.WithSignatureDomainProvider(signatureDomainProvider),
dirk.WithDomainProvider(domainProvider),
},
err: "problem with parameters: no validators provider specified",
},
@ -354,7 +386,7 @@ func TestService(t *testing.T) {
dirk.WithRANDAODomainProvider(randaoDomainProvider),
dirk.WithSelectionProofDomainProvider(selectionProofDomainProvider),
dirk.WithAggregateAndProofDomainProvider(aggregateAndProofDomainProvider),
dirk.WithSignatureDomainProvider(signatureDomainProvider),
dirk.WithDomainProvider(domainProvider),
},
err: "problem with parameters: no slots per epoch provider specified",
},
@ -376,7 +408,7 @@ func TestService(t *testing.T) {
dirk.WithRANDAODomainProvider(randaoDomainProvider),
dirk.WithSelectionProofDomainProvider(selectionProofDomainProvider),
dirk.WithAggregateAndProofDomainProvider(aggregateAndProofDomainProvider),
dirk.WithSignatureDomainProvider(signatureDomainProvider),
dirk.WithDomainProvider(domainProvider),
},
err: "failed to obtain slots per epoch: error",
},
@ -397,7 +429,7 @@ func TestService(t *testing.T) {
dirk.WithRANDAODomainProvider(randaoDomainProvider),
dirk.WithSelectionProofDomainProvider(selectionProofDomainProvider),
dirk.WithAggregateAndProofDomainProvider(aggregateAndProofDomainProvider),
dirk.WithSignatureDomainProvider(signatureDomainProvider),
dirk.WithDomainProvider(domainProvider),
},
err: "problem with parameters: no beacon proposer domain provider specified",
},
@ -419,7 +451,7 @@ func TestService(t *testing.T) {
dirk.WithRANDAODomainProvider(randaoDomainProvider),
dirk.WithSelectionProofDomainProvider(selectionProofDomainProvider),
dirk.WithAggregateAndProofDomainProvider(aggregateAndProofDomainProvider),
dirk.WithSignatureDomainProvider(signatureDomainProvider),
dirk.WithDomainProvider(domainProvider),
},
err: "failed to obtain beacon proposer domain: error",
},
@ -440,7 +472,7 @@ func TestService(t *testing.T) {
dirk.WithRANDAODomainProvider(randaoDomainProvider),
dirk.WithSelectionProofDomainProvider(selectionProofDomainProvider),
dirk.WithAggregateAndProofDomainProvider(aggregateAndProofDomainProvider),
dirk.WithSignatureDomainProvider(signatureDomainProvider),
dirk.WithDomainProvider(domainProvider),
},
err: "problem with parameters: no beacon attester domain provider specified",
},
@ -462,7 +494,7 @@ func TestService(t *testing.T) {
dirk.WithRANDAODomainProvider(randaoDomainProvider),
dirk.WithSelectionProofDomainProvider(selectionProofDomainProvider),
dirk.WithAggregateAndProofDomainProvider(aggregateAndProofDomainProvider),
dirk.WithSignatureDomainProvider(signatureDomainProvider),
dirk.WithDomainProvider(domainProvider),
},
err: "failed to obtain beacon attester domain: error",
},
@ -483,7 +515,7 @@ func TestService(t *testing.T) {
dirk.WithBeaconAttesterDomainProvider(beaconAttesterDomainProvider),
dirk.WithSelectionProofDomainProvider(selectionProofDomainProvider),
dirk.WithAggregateAndProofDomainProvider(aggregateAndProofDomainProvider),
dirk.WithSignatureDomainProvider(signatureDomainProvider),
dirk.WithDomainProvider(domainProvider),
},
err: "problem with parameters: no RANDAO domain provider specified",
},
@ -505,7 +537,7 @@ func TestService(t *testing.T) {
dirk.WithRANDAODomainProvider(mock.NewErroringRANDAODomainProvider()),
dirk.WithSelectionProofDomainProvider(selectionProofDomainProvider),
dirk.WithAggregateAndProofDomainProvider(aggregateAndProofDomainProvider),
dirk.WithSignatureDomainProvider(signatureDomainProvider),
dirk.WithDomainProvider(domainProvider),
},
err: "failed to obtain RANDAO domain: error",
},
@ -526,7 +558,7 @@ func TestService(t *testing.T) {
dirk.WithBeaconAttesterDomainProvider(beaconAttesterDomainProvider),
dirk.WithRANDAODomainProvider(randaoDomainProvider),
dirk.WithAggregateAndProofDomainProvider(aggregateAndProofDomainProvider),
dirk.WithSignatureDomainProvider(signatureDomainProvider),
dirk.WithDomainProvider(domainProvider),
},
err: "problem with parameters: no selection proof domain provider specified",
},
@ -548,7 +580,7 @@ func TestService(t *testing.T) {
dirk.WithRANDAODomainProvider(randaoDomainProvider),
dirk.WithSelectionProofDomainProvider(mock.NewErroringSelectionProofDomainProvider()),
dirk.WithAggregateAndProofDomainProvider(aggregateAndProofDomainProvider),
dirk.WithSignatureDomainProvider(signatureDomainProvider),
dirk.WithDomainProvider(domainProvider),
},
err: "failed to obtain selection proof domain: error",
},
@ -569,7 +601,7 @@ func TestService(t *testing.T) {
dirk.WithBeaconAttesterDomainProvider(beaconAttesterDomainProvider),
dirk.WithRANDAODomainProvider(randaoDomainProvider),
dirk.WithSelectionProofDomainProvider(selectionProofDomainProvider),
dirk.WithSignatureDomainProvider(signatureDomainProvider),
dirk.WithDomainProvider(domainProvider),
},
err: "problem with parameters: no aggregate and proof domain provider specified",
},
@ -591,12 +623,12 @@ func TestService(t *testing.T) {
dirk.WithRANDAODomainProvider(randaoDomainProvider),
dirk.WithSelectionProofDomainProvider(selectionProofDomainProvider),
dirk.WithAggregateAndProofDomainProvider(mock.NewErroringAggregateAndProofDomainProvider()),
dirk.WithSignatureDomainProvider(signatureDomainProvider),
dirk.WithDomainProvider(domainProvider),
},
err: "failed to obtain aggregate and proof domain: error",
},
{
name: "SignatureDomainProviderMissing",
name: "DomainProviderMissing",
params: []dirk.Parameter{
dirk.WithLogLevel(zerolog.TraceLevel),
dirk.WithMonitor(nullmetrics.New(context.Background())),
@ -614,7 +646,7 @@ func TestService(t *testing.T) {
dirk.WithSelectionProofDomainProvider(selectionProofDomainProvider),
dirk.WithAggregateAndProofDomainProvider(aggregateAndProofDomainProvider),
},
err: "problem with parameters: no signature domain provider specified",
err: "problem with parameters: no domain provider specified",
},
{
name: "Good",
@ -634,7 +666,7 @@ func TestService(t *testing.T) {
dirk.WithRANDAODomainProvider(randaoDomainProvider),
dirk.WithSelectionProofDomainProvider(selectionProofDomainProvider),
dirk.WithAggregateAndProofDomainProvider(aggregateAndProofDomainProvider),
dirk.WithSignatureDomainProvider(signatureDomainProvider),
dirk.WithDomainProvider(domainProvider),
},
},
}
@ -705,7 +737,7 @@ func TestAccounts(t *testing.T) {
dirk.WithRANDAODomainProvider(mock.NewRANDAODomainProvider()),
dirk.WithSelectionProofDomainProvider(mock.NewSelectionProofDomainProvider()),
dirk.WithAggregateAndProofDomainProvider(mock.NewAggregateAndProofDomainProvider()),
dirk.WithSignatureDomainProvider(mock.NewSignatureDomainProvider()),
dirk.WithDomainProvider(mock.NewDomainProvider()),
)
require.Nil(t, err)
@ -728,7 +760,7 @@ func TestAccountsByIndex(t *testing.T) {
tests := []struct {
name string
indices []uint64
indices []spec.ValidatorIndex
accounts int
}{
{
@ -737,17 +769,17 @@ func TestAccountsByIndex(t *testing.T) {
},
{
name: "Empty",
indices: []uint64{},
indices: []spec.ValidatorIndex{},
accounts: 0,
},
{
name: "All",
indices: []uint64{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},
indices: []spec.ValidatorIndex{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},
accounts: 16,
},
{
name: "Missing",
indices: []uint64{15, 16},
indices: []spec.ValidatorIndex{15, 16},
accounts: 1,
},
}
@ -770,7 +802,7 @@ func TestAccountsByIndex(t *testing.T) {
dirk.WithRANDAODomainProvider(mock.NewRANDAODomainProvider()),
dirk.WithSelectionProofDomainProvider(mock.NewSelectionProofDomainProvider()),
dirk.WithAggregateAndProofDomainProvider(mock.NewAggregateAndProofDomainProvider()),
dirk.WithSignatureDomainProvider(mock.NewSignatureDomainProvider()),
dirk.WithDomainProvider(mock.NewDomainProvider()),
)
require.Nil(t, err)
@ -793,7 +825,7 @@ func TestAccountsByPubKey(t *testing.T) {
tests := []struct {
name string
pubKeys [][]byte
pubKeys []spec.BLSPubKey
accounts int
}{
{
@ -802,38 +834,38 @@ func TestAccountsByPubKey(t *testing.T) {
},
{
name: "Empty",
pubKeys: [][]byte{
_byte(""),
pubKeys: []spec.BLSPubKey{
{},
},
accounts: 0,
},
{
name: "All",
pubKeys: [][]byte{
_byte("0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c"),
_byte("0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b"),
_byte("0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b"),
_byte("0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e"),
_byte("0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e"),
_byte("0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34"),
_byte("0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373"),
_byte("0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac"),
_byte("0xa6d310dbbfab9a22450f59993f87a4ce5db6223f3b5f1f30d2c4ec718922d400e0b3c7741de8e59960f72411a0ee10a7"),
_byte("0x9893413c00283a3f9ed9fd9845dda1cea38228d22567f9541dccc357e54a2d6a6e204103c92564cbc05f4905ac7c493a"),
_byte("0x876dd4705157eb66dc71bc2e07fb151ea53e1a62a0bb980a7ce72d15f58944a8a3752d754f52f4a60dbfc7b18169f268"),
_byte("0xaec922bd7a9b7b1dc21993133b586b0c3041c1e2e04b513e862227b9d7aecaf9444222f7e78282a449622ffc6278915d"),
_byte("0x9314c6de0386635e2799af798884c2ea09c63b9f079e572acc00b06a7faccce501ea4dfc0b1a23b8603680a5e3481327"),
_byte("0x903e2989e7442ee0a8958d020507a8bd985d3974f5e8273093be00db3935f0500e141b252bd09e3728892c7a8443863c"),
_byte("0x84398f539a64cbe01cfcd8c485ea51cd6657b94df93ee9b5dc61e1f18f69da6ca9d4dba63c956a81c68d5d4d4277a60f"),
_byte("0x872c61b4a7f8510ec809e5b023f5fdda2105d024c470ddbbeca4bc74e8280af0d178d749853e8f6a841083ac1b4db98f"),
pubKeys: []spec.BLSPubKey{
testutil.HexToPubKey("0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c"),
testutil.HexToPubKey("0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b"),
testutil.HexToPubKey("0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b"),
testutil.HexToPubKey("0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e"),
testutil.HexToPubKey("0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e"),
testutil.HexToPubKey("0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34"),
testutil.HexToPubKey("0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373"),
testutil.HexToPubKey("0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac"),
testutil.HexToPubKey("0xa6d310dbbfab9a22450f59993f87a4ce5db6223f3b5f1f30d2c4ec718922d400e0b3c7741de8e59960f72411a0ee10a7"),
testutil.HexToPubKey("0x9893413c00283a3f9ed9fd9845dda1cea38228d22567f9541dccc357e54a2d6a6e204103c92564cbc05f4905ac7c493a"),
testutil.HexToPubKey("0x876dd4705157eb66dc71bc2e07fb151ea53e1a62a0bb980a7ce72d15f58944a8a3752d754f52f4a60dbfc7b18169f268"),
testutil.HexToPubKey("0xaec922bd7a9b7b1dc21993133b586b0c3041c1e2e04b513e862227b9d7aecaf9444222f7e78282a449622ffc6278915d"),
testutil.HexToPubKey("0x9314c6de0386635e2799af798884c2ea09c63b9f079e572acc00b06a7faccce501ea4dfc0b1a23b8603680a5e3481327"),
testutil.HexToPubKey("0x903e2989e7442ee0a8958d020507a8bd985d3974f5e8273093be00db3935f0500e141b252bd09e3728892c7a8443863c"),
testutil.HexToPubKey("0x84398f539a64cbe01cfcd8c485ea51cd6657b94df93ee9b5dc61e1f18f69da6ca9d4dba63c956a81c68d5d4d4277a60f"),
testutil.HexToPubKey("0x872c61b4a7f8510ec809e5b023f5fdda2105d024c470ddbbeca4bc74e8280af0d178d749853e8f6a841083ac1b4db98f"),
},
accounts: 16,
},
{
name: "Missing",
pubKeys: [][]byte{
_byte("0x872c61b4a7f8510ec809e5b023f5fdda2105d024c470ddbbeca4bc74e8280af0d178d749853e8f6a841083ac1b4db98f"),
_byte("0x8f467e5723deac7659e1ca273e28410cbaa6d495ab66ae77014f4cd21c64b6b5ab9987c9b5537fe0279bd063fe609be7"),
pubKeys: []spec.BLSPubKey{
testutil.HexToPubKey("0x872c61b4a7f8510ec809e5b023f5fdda2105d024c470ddbbeca4bc74e8280af0d178d749853e8f6a841083ac1b4db98f"),
testutil.HexToPubKey("0x8f467e5723deac7659e1ca273e28410cbaa6d495ab66ae77014f4cd21c64b6b5ab9987c9b5537fe0279bd063fe609be7"),
},
accounts: 1,
},
@ -857,7 +889,7 @@ func TestAccountsByPubKey(t *testing.T) {
dirk.WithRANDAODomainProvider(mock.NewRANDAODomainProvider()),
dirk.WithSelectionProofDomainProvider(mock.NewSelectionProofDomainProvider()),
dirk.WithAggregateAndProofDomainProvider(mock.NewAggregateAndProofDomainProvider()),
dirk.WithSignatureDomainProvider(mock.NewSignatureDomainProvider()),
dirk.WithDomainProvider(mock.NewDomainProvider()),
)
require.Nil(t, err)

View File

@ -19,30 +19,33 @@ import (
eth2client "github.com/attestantio/go-eth2-client"
api "github.com/attestantio/go-eth2-client/api/v1"
"github.com/opentracing/opentracing-go"
spec "github.com/attestantio/go-eth2-client/spec/phase0"
"github.com/pkg/errors"
e2wtypes "github.com/wealdtech/go-eth2-wallet-types/v2"
)
// ValidatingAccount is a wrapper around the dirk account that implements ValidatingAccount.
type ValidatingAccount struct {
account e2wtypes.Account
index uint64
state api.ValidatorState
accountManager *Service
signatureDomainProvider eth2client.SignatureDomainProvider
account e2wtypes.Account
index spec.ValidatorIndex
state api.ValidatorState
accountManager *Service
domainProvider eth2client.DomainProvider
}
// PubKey returns the public key of the validating account.
func (d *ValidatingAccount) PubKey(ctx context.Context) ([]byte, error) {
func (d *ValidatingAccount) PubKey(ctx context.Context) (spec.BLSPubKey, error) {
var pubKey spec.BLSPubKey
if provider, isProvider := d.account.(e2wtypes.AccountCompositePublicKeyProvider); isProvider {
return provider.CompositePublicKey().Marshal(), nil
copy(pubKey[:], provider.CompositePublicKey().Marshal())
} else {
copy(pubKey[:], d.account.PublicKey().Marshal())
}
return d.account.PublicKey().Marshal(), nil
return pubKey, nil
}
// Index returns the index of the validating account.
func (d *ValidatingAccount) Index(ctx context.Context) (uint64, error) {
func (d *ValidatingAccount) Index(ctx context.Context) (spec.ValidatorIndex, error) {
return d.index, nil
}
@ -53,133 +56,142 @@ func (d *ValidatingAccount) State() api.ValidatorState {
// SignSlotSelection returns a slot selection signature.
// This signs a slot with the "selection proof" domain.
func (d *ValidatingAccount) SignSlotSelection(ctx context.Context, slot uint64) ([]byte, error) {
span, ctx := opentracing.StartSpanFromContext(ctx, "dirk.SignSlotSelection")
defer span.Finish()
func (d *ValidatingAccount) SignSlotSelection(ctx context.Context, slot spec.Slot) (spec.BLSSignature, error) {
var messageRoot spec.Root
binary.LittleEndian.PutUint64(messageRoot[:], uint64(slot))
// Calculate the signature domain.
signatureDomain, err := d.signatureDomainProvider.SignatureDomain(ctx,
d.accountManager.selectionProofDomain,
slot/d.accountManager.slotsPerEpoch)
// Calculate the domain.
domain, err := d.domainProvider.Domain(ctx,
d.accountManager.selectionProofDomainType,
spec.Epoch(slot/d.accountManager.slotsPerEpoch))
if err != nil {
return nil, errors.Wrap(err, "failed to obtain signature domain for selection proof")
return spec.BLSSignature{}, errors.Wrap(err, "failed to obtain signature domain for selection proof")
}
slotBytes := make([]byte, 32)
binary.LittleEndian.PutUint64(slotBytes, slot)
binary.LittleEndian.PutUint64(slotBytes, uint64(slot))
sig, err := d.account.(e2wtypes.AccountProtectingSigner).SignGeneric(ctx, slotBytes, signatureDomain)
sig, err := d.account.(e2wtypes.AccountProtectingSigner).SignGeneric(ctx, slotBytes, domain[:])
if err != nil {
return nil, errors.Wrap(err, "failed to sign slot")
return spec.BLSSignature{}, errors.Wrap(err, "failed to sign slot")
}
return sig.Marshal(), nil
var signature spec.BLSSignature
copy(signature[:], sig.Marshal())
return signature, nil
}
// SignRANDAOReveal returns a RANDAO reveal signature.
// This signs an epoch with the "RANDAO reveal" domain.
// N.B. This passes in a slot, not an epoch.
func (d *ValidatingAccount) SignRANDAOReveal(ctx context.Context, slot uint64) ([]byte, error) {
span, ctx := opentracing.StartSpanFromContext(ctx, "dirk.SignRANDAOReveal")
defer span.Finish()
func (d *ValidatingAccount) SignRANDAOReveal(ctx context.Context, slot spec.Slot) (spec.BLSSignature, error) {
var messageRoot spec.Root
epoch := spec.Epoch(slot / d.accountManager.slotsPerEpoch)
binary.LittleEndian.PutUint64(messageRoot[:], uint64(epoch))
epoch := slot / d.accountManager.slotsPerEpoch
// Obtain the RANDAO reveal signature domain.
signatureDomain, err := d.signatureDomainProvider.SignatureDomain(ctx,
d.accountManager.randaoDomain,
domain, err := d.domainProvider.Domain(ctx,
d.accountManager.randaoDomainType,
epoch)
if err != nil {
return nil, errors.Wrap(err, "failed to obtain signature domain for RANDAO reveal")
return spec.BLSSignature{}, errors.Wrap(err, "failed to obtain signature domain for RANDAO reveal")
}
epochBytes := make([]byte, 32)
binary.LittleEndian.PutUint64(epochBytes, epoch)
binary.LittleEndian.PutUint64(epochBytes, uint64(epoch))
sig, err := d.account.(e2wtypes.AccountProtectingSigner).SignGeneric(ctx, epochBytes, signatureDomain)
sig, err := d.account.(e2wtypes.AccountProtectingSigner).SignGeneric(ctx, epochBytes, domain[:])
if err != nil {
return nil, errors.Wrap(err, "failed to sign RANDO reveal")
return spec.BLSSignature{}, errors.Wrap(err, "failed to sign RANDO reveal")
}
return sig.Marshal(), nil
var signature spec.BLSSignature
copy(signature[:], sig.Marshal())
return signature, nil
}
// SignBeaconBlockProposal signs a beacon block proposal item.
func (d *ValidatingAccount) SignBeaconBlockProposal(ctx context.Context,
slot uint64,
proposerIndex uint64,
parentRoot []byte,
stateRoot []byte,
bodyRoot []byte) ([]byte, error) {
slot spec.Slot,
proposerIndex spec.ValidatorIndex,
parentRoot spec.Root,
stateRoot spec.Root,
bodyRoot spec.Root) (spec.BLSSignature, error) {
// Fetch the signature domain.
signatureDomain, err := d.signatureDomainProvider.SignatureDomain(ctx,
d.accountManager.beaconProposerDomain,
slot/d.accountManager.slotsPerEpoch)
// Fetch the domain.
domain, err := d.domainProvider.Domain(ctx,
d.accountManager.beaconProposerDomainType,
spec.Epoch(slot/d.accountManager.slotsPerEpoch))
if err != nil {
return nil, errors.Wrap(err, "failed to obtain signature domain for beacon proposal")
return spec.BLSSignature{}, errors.Wrap(err, "failed to obtain signature domain for beacon proposal")
}
sig, err := d.account.(e2wtypes.AccountProtectingSigner).SignBeaconProposal(ctx,
slot,
proposerIndex,
parentRoot,
stateRoot,
bodyRoot,
signatureDomain)
uint64(slot),
uint64(proposerIndex),
parentRoot[:],
stateRoot[:],
bodyRoot[:],
domain[:])
if err != nil {
return nil, errors.Wrap(err, "failed to sign beacon block proposal")
return spec.BLSSignature{}, errors.Wrap(err, "failed to sign beacon block proposal")
}
return sig.Marshal(), nil
var signature spec.BLSSignature
copy(signature[:], sig.Marshal())
return signature, nil
}
// SignBeaconAttestation signs a beacon attestation item.
func (d *ValidatingAccount) SignBeaconAttestation(ctx context.Context,
slot uint64,
committeeIndex uint64,
blockRoot []byte,
sourceEpoch uint64,
sourceRoot []byte,
targetEpoch uint64,
targetRoot []byte) ([]byte, error) {
span, ctx := opentracing.StartSpanFromContext(ctx, "dirk.SignBeaconAttestation")
defer span.Finish()
slot spec.Slot,
committeeIndex spec.CommitteeIndex,
blockRoot spec.Root,
sourceEpoch spec.Epoch,
sourceRoot spec.Root,
targetEpoch spec.Epoch,
targetRoot spec.Root) (spec.BLSSignature, error) {
signatureDomain, err := d.signatureDomainProvider.SignatureDomain(ctx,
d.accountManager.beaconAttesterDomain,
slot/d.accountManager.slotsPerEpoch)
domain, err := d.domainProvider.Domain(ctx,
d.accountManager.beaconAttesterDomainType,
spec.Epoch(slot/d.accountManager.slotsPerEpoch))
if err != nil {
return nil, errors.Wrap(err, "failed to obtain signature domain for beacon attestation")
return spec.BLSSignature{}, errors.Wrap(err, "failed to obtain signature domain for beacon attestation")
}
sig, err := d.account.(e2wtypes.AccountProtectingSigner).SignBeaconAttestation(ctx,
slot,
committeeIndex,
blockRoot,
sourceEpoch,
sourceRoot,
targetEpoch,
targetRoot,
signatureDomain)
uint64(slot),
uint64(committeeIndex),
blockRoot[:],
uint64(sourceEpoch),
sourceRoot[:],
uint64(targetEpoch),
targetRoot[:],
domain[:])
if err != nil {
return nil, errors.Wrap(err, "failed to sign beacon attestation")
return spec.BLSSignature{}, errors.Wrap(err, "failed to sign beacon attestation")
}
return sig.Marshal(), nil
var signature spec.BLSSignature
copy(signature[:], sig.Marshal())
return signature, nil
}
// SignAggregateAndProof signs an aggregate and proof item.
func (d *ValidatingAccount) SignAggregateAndProof(ctx context.Context, slot uint64, aggregateAndProofRoot []byte) ([]byte, error) {
span, ctx := opentracing.StartSpanFromContext(ctx, "dirk.SignAggregateAndProof")
defer span.Finish()
// Fetch the signature domain.
signatureDomain, err := d.signatureDomainProvider.SignatureDomain(ctx,
d.accountManager.aggregateAndProofDomain,
slot)
func (d *ValidatingAccount) SignAggregateAndProof(ctx context.Context, slot spec.Slot, aggregateAndProofRoot spec.Root) (spec.BLSSignature, error) {
// Fetch the domain.
domain, err := d.domainProvider.Domain(ctx,
d.accountManager.aggregateAndProofDomainType,
spec.Epoch(slot/d.accountManager.slotsPerEpoch))
if err != nil {
return nil, errors.Wrap(err, "failed to obtain signature domain for beacon aggregate and proof")
return spec.BLSSignature{}, errors.Wrap(err, "failed to obtain signature domain for beacon aggregate and proof")
}
sig, err := d.account.(e2wtypes.AccountProtectingSigner).SignGeneric(ctx, aggregateAndProofRoot, signatureDomain)
sig, err := d.account.(e2wtypes.AccountProtectingSigner).SignGeneric(ctx, aggregateAndProofRoot[:], domain[:])
if err != nil {
return nil, errors.Wrap(err, "failed to aggregate and proof")
return spec.BLSSignature{}, errors.Wrap(err, "failed to aggregate and proof")
}
return sig.Marshal(), nil
var signature spec.BLSSignature
copy(signature[:], sig.Marshal())
return signature, nil
}

View File

@ -22,6 +22,7 @@ import (
"github.com/attestantio/dirk/testing/daemon"
api "github.com/attestantio/go-eth2-client/api/v1"
spec "github.com/attestantio/go-eth2-client/spec/phase0"
"github.com/attestantio/vouch/mock"
"github.com/attestantio/vouch/services/accountmanager"
"github.com/attestantio/vouch/services/accountmanager/dirk"
@ -57,30 +58,30 @@ func TestPubKey(t *testing.T) {
dirk.WithRANDAODomainProvider(mock.NewRANDAODomainProvider()),
dirk.WithSelectionProofDomainProvider(mock.NewSelectionProofDomainProvider()),
dirk.WithAggregateAndProofDomainProvider(mock.NewAggregateAndProofDomainProvider()),
dirk.WithSignatureDomainProvider(mock.NewSignatureDomainProvider()),
dirk.WithDomainProvider(mock.NewDomainProvider()),
)
require.Nil(t, err)
tests := []struct {
name string
index uint64
expected []byte
index spec.ValidatorIndex
expected spec.BLSPubKey
}{
{
name: "0",
index: 0,
expected: _byte("0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c"),
expected: _pubKey("0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c"),
},
{
name: "1",
index: 1,
expected: _byte("0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b"),
expected: _pubKey("0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b"),
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
accounts, err := s.AccountsByIndex(ctx, []uint64{test.index})
accounts, err := s.AccountsByIndex(ctx, []spec.ValidatorIndex{test.index})
require.NoError(t, err)
require.Equal(t, 1, len(accounts))
account := accounts[0]
@ -120,13 +121,13 @@ func TestState(t *testing.T) {
dirk.WithRANDAODomainProvider(mock.NewRANDAODomainProvider()),
dirk.WithSelectionProofDomainProvider(mock.NewSelectionProofDomainProvider()),
dirk.WithAggregateAndProofDomainProvider(mock.NewAggregateAndProofDomainProvider()),
dirk.WithSignatureDomainProvider(mock.NewSignatureDomainProvider()),
dirk.WithDomainProvider(mock.NewDomainProvider()),
)
require.Nil(t, err)
tests := []struct {
name string
index uint64
index spec.ValidatorIndex
expected api.ValidatorState
}{
{
@ -143,7 +144,7 @@ func TestState(t *testing.T) {
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
accounts, err := s.AccountsByIndex(ctx, []uint64{test.index})
accounts, err := s.AccountsByIndex(ctx, []spec.ValidatorIndex{test.index})
require.NoError(t, err)
require.Equal(t, 1, len(accounts))
account := accounts[0]
@ -182,30 +183,30 @@ func TestSignSlotSelection(t *testing.T) {
dirk.WithRANDAODomainProvider(mock.NewRANDAODomainProvider()),
dirk.WithSelectionProofDomainProvider(mock.NewSelectionProofDomainProvider()),
dirk.WithAggregateAndProofDomainProvider(mock.NewAggregateAndProofDomainProvider()),
dirk.WithSignatureDomainProvider(mock.NewSignatureDomainProvider()),
dirk.WithDomainProvider(mock.NewDomainProvider()),
)
require.Nil(t, err)
tests := []struct {
name string
index uint64
expected []byte
index spec.ValidatorIndex
expected spec.BLSSignature
}{
{
name: "0",
index: 0,
expected: _byte("0xa207bbed7d1e43585e5d42e3f09a5179f21a12a33b66ac9af47132c20f9b7b7caaa162420e095664ca3318fe365776e80bd0f9ef1e3b07a2e5340d0c07152234bf18f7596c8d94d72e11961ad8455f08c4417b0019246e24f570a166f86de2c5"),
expected: _sig("0xa207bbed7d1e43585e5d42e3f09a5179f21a12a33b66ac9af47132c20f9b7b7caaa162420e095664ca3318fe365776e80bd0f9ef1e3b07a2e5340d0c07152234bf18f7596c8d94d72e11961ad8455f08c4417b0019246e24f570a166f86de2c5"),
},
{
name: "1",
index: 1,
expected: _byte("0xa17b1a6decb1503b5b8eacb4ca48e2f1665e43c587088995bb7e2da0738268ad0e1f28519ed79fbb318b9b98c6e8b65805a005bca4c98656fefb9ec6753df29ad6ef92da5e3074c027caaaf738d37fd09e08d8d8f86531bd80cf4152709240f9"),
expected: _sig("0xa17b1a6decb1503b5b8eacb4ca48e2f1665e43c587088995bb7e2da0738268ad0e1f28519ed79fbb318b9b98c6e8b65805a005bca4c98656fefb9ec6753df29ad6ef92da5e3074c027caaaf738d37fd09e08d8d8f86531bd80cf4152709240f9"),
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
accounts, err := s.AccountsByIndex(ctx, []uint64{test.index})
accounts, err := s.AccountsByIndex(ctx, []spec.ValidatorIndex{test.index})
require.NoError(t, err)
require.Equal(t, 1, len(accounts))
account := accounts[0]
@ -245,30 +246,30 @@ func TestSignRANDAOReveal(t *testing.T) {
dirk.WithRANDAODomainProvider(mock.NewRANDAODomainProvider()),
dirk.WithSelectionProofDomainProvider(mock.NewSelectionProofDomainProvider()),
dirk.WithAggregateAndProofDomainProvider(mock.NewAggregateAndProofDomainProvider()),
dirk.WithSignatureDomainProvider(mock.NewSignatureDomainProvider()),
dirk.WithDomainProvider(mock.NewDomainProvider()),
)
require.Nil(t, err)
tests := []struct {
name string
index uint64
expected []byte
index spec.ValidatorIndex
expected spec.BLSSignature
}{
{
name: "0",
index: 0,
expected: _byte("0xb990eeca35dadda689f5561ac39bba9a27a0c41c40bd1ce584595ba2a44782a89e2630ced7b1fc348b2408d15fa6746c177c5227625e39031e6be1536387ae33e21ec3de6d1d0b46bada1b99b621f8d40eab81882400c028716b22d31999b177"),
expected: _sig("0xb990eeca35dadda689f5561ac39bba9a27a0c41c40bd1ce584595ba2a44782a89e2630ced7b1fc348b2408d15fa6746c177c5227625e39031e6be1536387ae33e21ec3de6d1d0b46bada1b99b621f8d40eab81882400c028716b22d31999b177"),
},
{
name: "1",
index: 1,
expected: _byte("0x840c144974632f09084b91ec7be5044c3fe9dd0dc7ce1031c0c78911807e264f36cb4fee0ddccf0ca93bada5d102cfb7118e6b75b5ecc5e18648a29f21f70727f3587b8d34bc7474d926fab4fb30eae4436153c336e6eb290d3d1cdd88ee9a58"),
expected: _sig("0x840c144974632f09084b91ec7be5044c3fe9dd0dc7ce1031c0c78911807e264f36cb4fee0ddccf0ca93bada5d102cfb7118e6b75b5ecc5e18648a29f21f70727f3587b8d34bc7474d926fab4fb30eae4436153c336e6eb290d3d1cdd88ee9a58"),
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
accounts, err := s.AccountsByIndex(ctx, []uint64{test.index})
accounts, err := s.AccountsByIndex(ctx, []spec.ValidatorIndex{test.index})
require.NoError(t, err)
require.Equal(t, 1, len(accounts))
account := accounts[0]
@ -308,30 +309,30 @@ func TestSignBeaconBlockProposal(t *testing.T) {
dirk.WithRANDAODomainProvider(mock.NewRANDAODomainProvider()),
dirk.WithSelectionProofDomainProvider(mock.NewSelectionProofDomainProvider()),
dirk.WithAggregateAndProofDomainProvider(mock.NewAggregateAndProofDomainProvider()),
dirk.WithSignatureDomainProvider(mock.NewSignatureDomainProvider()),
dirk.WithDomainProvider(mock.NewDomainProvider()),
)
require.Nil(t, err)
tests := []struct {
name string
index uint64
expected []byte
index spec.ValidatorIndex
expected spec.BLSSignature
}{
{
name: "0",
index: 0,
expected: _byte("0x83d91f4fe6dd962493f212a94dc62c81358ffbdb6c3f8567d96fbe31c5ab505db1a3d37b8c3d653225621bb34918d30b069bbc02daeea9e1b2e62166014563f271fdfbe9aad37f0d155754f63eb368dd853c0bf723ad64af371a04b7778e891a"),
expected: _sig("0x83d91f4fe6dd962493f212a94dc62c81358ffbdb6c3f8567d96fbe31c5ab505db1a3d37b8c3d653225621bb34918d30b069bbc02daeea9e1b2e62166014563f271fdfbe9aad37f0d155754f63eb368dd853c0bf723ad64af371a04b7778e891a"),
},
{
name: "1",
index: 1,
expected: _byte("0x9176ac06d426beb74bfb3969a619d364a5e214f0da511433b56f8dca47b93725c4ddd225c1cb81dd5a26fc321801a1d70b1c28c6cf705c010fadf9c4f139c044224680d8c60e425c9d6e6b8e8af21f12cffab38b393a9b7529527b92cf20e80a"),
expected: _sig("0x9176ac06d426beb74bfb3969a619d364a5e214f0da511433b56f8dca47b93725c4ddd225c1cb81dd5a26fc321801a1d70b1c28c6cf705c010fadf9c4f139c044224680d8c60e425c9d6e6b8e8af21f12cffab38b393a9b7529527b92cf20e80a"),
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
accounts, err := s.AccountsByIndex(ctx, []uint64{test.index})
accounts, err := s.AccountsByIndex(ctx, []spec.ValidatorIndex{test.index})
require.NoError(t, err)
require.Equal(t, 1, len(accounts))
account := accounts[0]
@ -341,9 +342,9 @@ func TestSignBeaconBlockProposal(t *testing.T) {
res, err := signer.SignBeaconBlockProposal(ctx,
1,
1,
_byte("0x0000000000000000000000000000000000000000000000000000000000000000"),
_byte("0x0000000000000000000000000000000000000000000000000000000000000000"),
_byte("0x0000000000000000000000000000000000000000000000000000000000000000"),
_root("0x0000000000000000000000000000000000000000000000000000000000000000"),
_root("0x0000000000000000000000000000000000000000000000000000000000000000"),
_root("0x0000000000000000000000000000000000000000000000000000000000000000"),
)
require.NoError(t, err)
require.Equal(t, test.expected, res)
@ -377,30 +378,30 @@ func TestBeaconAttestationsSigner(t *testing.T) {
dirk.WithRANDAODomainProvider(mock.NewRANDAODomainProvider()),
dirk.WithSelectionProofDomainProvider(mock.NewSelectionProofDomainProvider()),
dirk.WithAggregateAndProofDomainProvider(mock.NewAggregateAndProofDomainProvider()),
dirk.WithSignatureDomainProvider(mock.NewSignatureDomainProvider()),
dirk.WithDomainProvider(mock.NewDomainProvider()),
)
require.Nil(t, err)
tests := []struct {
name string
index uint64
expected []byte
index spec.ValidatorIndex
expected spec.BLSSignature
}{
{
name: "0",
index: 0,
expected: _byte("0x974fb6782c196c8e523b74ea3dbdfe7b122c6a18590992f2cb789358dcea6c28498ffa6cac68629bf83175cb55bb0d3910919eab48d2934c3a81655dcc27c91a996ca4a9880ffde7864f6aba3cd7c40111e3317c817032776d077d8d6a348bb2"),
expected: _sig("0x974fb6782c196c8e523b74ea3dbdfe7b122c6a18590992f2cb789358dcea6c28498ffa6cac68629bf83175cb55bb0d3910919eab48d2934c3a81655dcc27c91a996ca4a9880ffde7864f6aba3cd7c40111e3317c817032776d077d8d6a348bb2"),
},
{
name: "1",
index: 1,
expected: _byte("0x84a1c3c50d093901ea1b027b18598e4b9cf0f848f6bd49f2807a3f6ea37c0cbf3794556705863de0ae8ea7dd2da4d4d91436e2ca96fa1eb045a22fb7704cedf8a842fa881a416eaa02444454d9f7f8040b84fc3cd3d42817f6992c3c29e16007"),
expected: _sig("0x84a1c3c50d093901ea1b027b18598e4b9cf0f848f6bd49f2807a3f6ea37c0cbf3794556705863de0ae8ea7dd2da4d4d91436e2ca96fa1eb045a22fb7704cedf8a842fa881a416eaa02444454d9f7f8040b84fc3cd3d42817f6992c3c29e16007"),
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
accounts, err := s.AccountsByIndex(ctx, []uint64{test.index})
accounts, err := s.AccountsByIndex(ctx, []spec.ValidatorIndex{test.index})
require.NoError(t, err)
require.Equal(t, 1, len(accounts))
account := accounts[0]
@ -410,11 +411,11 @@ func TestBeaconAttestationsSigner(t *testing.T) {
res, err := signer.SignBeaconAttestation(ctx,
1,
1,
_byte("0x0000000000000000000000000000000000000000000000000000000000000000"),
_root("0x0000000000000000000000000000000000000000000000000000000000000000"),
0,
_byte("0x0000000000000000000000000000000000000000000000000000000000000000"),
_root("0x0000000000000000000000000000000000000000000000000000000000000000"),
1,
_byte("0x0000000000000000000000000000000000000000000000000000000000000000"),
_root("0x0000000000000000000000000000000000000000000000000000000000000000"),
)
require.NoError(t, err)
require.Equal(t, test.expected, res)
@ -448,30 +449,30 @@ func TestAggregateAndProofsigner(t *testing.T) {
dirk.WithRANDAODomainProvider(mock.NewRANDAODomainProvider()),
dirk.WithSelectionProofDomainProvider(mock.NewSelectionProofDomainProvider()),
dirk.WithAggregateAndProofDomainProvider(mock.NewAggregateAndProofDomainProvider()),
dirk.WithSignatureDomainProvider(mock.NewSignatureDomainProvider()),
dirk.WithDomainProvider(mock.NewDomainProvider()),
)
require.Nil(t, err)
tests := []struct {
name string
index uint64
expected []byte
index spec.ValidatorIndex
expected spec.BLSSignature
}{
{
name: "0",
index: 0,
expected: _byte("0xafd6b2ed80506b63e964820aba6523735d6156d4f2e3d53c88075f22b2a48447d6f083952e7d6c315a96dfde35b6959616591ac9d8b2d7f1c423b7f257e6f5eb4406b97b55270a9101cca809e76c7759aaf1235b028aa23da118697dfb9c34c5"),
expected: _sig("0xafd6b2ed80506b63e964820aba6523735d6156d4f2e3d53c88075f22b2a48447d6f083952e7d6c315a96dfde35b6959616591ac9d8b2d7f1c423b7f257e6f5eb4406b97b55270a9101cca809e76c7759aaf1235b028aa23da118697dfb9c34c5"),
},
{
name: "1",
index: 1,
expected: _byte("0xa006085be92bb0ee2cf2bba3da0d5e21630efb7e32a5e4fa7ca742ea0bd273f76a6336ef3a9817200bddbc0b4a6dbecf1303d9804806fa38ee05b7d5cfbba6e851c37ca587d66df935c296e6210db69f8b4c96f5e590cb83c7f82c06aee1d4c3"),
expected: _sig("0xa006085be92bb0ee2cf2bba3da0d5e21630efb7e32a5e4fa7ca742ea0bd273f76a6336ef3a9817200bddbc0b4a6dbecf1303d9804806fa38ee05b7d5cfbba6e851c37ca587d66df935c296e6210db69f8b4c96f5e590cb83c7f82c06aee1d4c3"),
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
accounts, err := s.AccountsByIndex(ctx, []uint64{test.index})
accounts, err := s.AccountsByIndex(ctx, []spec.ValidatorIndex{test.index})
require.NoError(t, err)
require.Equal(t, 1, len(accounts))
account := accounts[0]
@ -480,7 +481,7 @@ func TestAggregateAndProofsigner(t *testing.T) {
require.True(t, isSigner)
res, err := signer.SignAggregateAndProof(ctx,
1,
_byte("0x0000000000000000000000000000000000000000000000000000000000000000"),
_root("0x0000000000000000000000000000000000000000000000000000000000000000"),
)
require.NoError(t, err)
require.Equal(t, test.expected, res)

View File

@ -18,6 +18,7 @@ import (
"context"
api "github.com/attestantio/go-eth2-client/api/v1"
spec "github.com/attestantio/go-eth2-client/spec/phase0"
)
// Service is the generic accountmanager service.
@ -29,23 +30,23 @@ type ValidatingAccountsProvider interface {
Accounts(ctx context.Context) ([]ValidatingAccount, error)
// AccountsByIndex provides information about the specific accounts that are configured to validate through this instance.
AccountsByIndex(ctx context.Context, indices []uint64) ([]ValidatingAccount, error)
AccountsByIndex(ctx context.Context, indices []spec.ValidatorIndex) ([]ValidatingAccount, error)
// AccountsByPubKey provides information about the specific accounts that are configured to validate through this instance.
AccountsByPubKey(ctx context.Context, pubKeys [][]byte) ([]ValidatingAccount, error)
AccountsByPubKey(ctx context.Context, pubKeys []spec.BLSPubKey) ([]ValidatingAccount, error)
}
// ValidatingAccountPubKeyProvider provides methods for obtaining public keys from accounts.
type ValidatingAccountPubKeyProvider interface {
// PubKey() provides the public key for this account.
PubKey(ctx context.Context) ([]byte, error)
PubKey(ctx context.Context) (spec.BLSPubKey, error)
}
// ValidatingAccountIndexProvider provides methods for obtaining indices from accounts.
type ValidatingAccountIndexProvider interface {
// Index() provides the validator index for this account.
// Returns an error if there is no index for this validator.
Index(ctx context.Context) (uint64, error)
Index(ctx context.Context) (spec.ValidatorIndex, error)
}
// ValidatingAccountStateProvider provides methods for obtaining state from accounts.
@ -81,45 +82,44 @@ type IsAggregatorProvider interface {
type RANDAORevealSigner interface {
// SignRANDAOReveal returns a RANDAO signature.
// This signs an epoch with the "RANDAO" domain.
// N.B. This passes in a slot, not an epoch.
SignRANDAOReveal(ctx context.Context, slot uint64) ([]byte, error)
SignRANDAOReveal(ctx context.Context, slot spec.Slot) (spec.BLSSignature, error)
}
// SlotSelectionSigner provides methods to sign slot selections.
type SlotSelectionSigner interface {
// SignSlotSelection returns a slot selection signature.
// This signs a slot with the "selection proof" domain.
SignSlotSelection(ctx context.Context, slot uint64) ([]byte, error)
SignSlotSelection(ctx context.Context, slot spec.Slot) (spec.BLSSignature, error)
}
// BeaconBlockSigner provides methods to sign beacon blocks.
type BeaconBlockSigner interface {
// SignBeaconBlockProposal signs a beacon block proposal.
SignBeaconBlockProposal(ctx context.Context,
slot uint64,
proposerIndex uint64,
parentRoot []byte,
stateRoot []byte,
bodyRoot []byte) ([]byte, error)
slot spec.Slot,
proposerIndex spec.ValidatorIndex,
parentRoot spec.Root,
stateRoot spec.Root,
bodyRoot spec.Root) (spec.BLSSignature, error)
}
// BeaconAttestationSigner provides methods to sign beacon attestations.
type BeaconAttestationSigner interface {
// SignBeaconAttestation signs a beacon attestation.
SignBeaconAttestation(ctx context.Context,
slot uint64,
committeeIndex uint64,
blockRoot []byte,
sourceEpoch uint64,
sourceRoot []byte,
targetEpoch uint64,
targetRoot []byte) ([]byte, error)
slot spec.Slot,
committeeIndex spec.CommitteeIndex,
blockRoot spec.Root,
sourceEpoch spec.Epoch,
sourceRoot spec.Root,
targetEpoch spec.Epoch,
targetRoot spec.Root) (spec.BLSSignature, error)
}
// AggregateAndProofSigner provides methods to sign aggregate and proofs.
type AggregateAndProofSigner interface {
// SignAggregateAndProof signs an aggregate attestation for given slot and root.
SignAggregateAndProof(ctx context.Context, slot uint64, root []byte) ([]byte, error)
SignAggregateAndProof(ctx context.Context, slot spec.Slot, root spec.Root) (spec.BLSSignature, error)
}
// Signer is a composite interface for all signer operations.

View File

@ -1,17 +0,0 @@
// Copyright © 2020 Attestant Limited.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package wallet
// Need to `go get github.com/ferranbt/fastssz/sszgen` for this to work.
//go:generate sszgen --path . --objs SigningContainer

View File

@ -33,7 +33,7 @@ type parameters struct {
randaoDomainProvider eth2client.RANDAODomainProvider
selectionProofDomainProvider eth2client.SelectionProofDomainProvider
aggregateAndProofDomainProvider eth2client.AggregateAndProofDomainProvider
signatureDomainProvider eth2client.SignatureDomainProvider
domainProvider eth2client.DomainProvider
}
// Parameter is the interface for service parameters.
@ -131,10 +131,10 @@ func WithAggregateAndProofDomainProvider(provider eth2client.AggregateAndProofDo
})
}
// WithSignatureDomainProvider sets the signature domain provider.
func WithSignatureDomainProvider(provider eth2client.SignatureDomainProvider) Parameter {
// WithDomainProvider sets the domain provider.
func WithDomainProvider(provider eth2client.DomainProvider) Parameter {
return parameterFunc(func(p *parameters) {
p.signatureDomainProvider = provider
p.domainProvider = provider
})
}
@ -179,8 +179,8 @@ func parseAndCheckParameters(params ...Parameter) (*parameters, error) {
if parameters.aggregateAndProofDomainProvider == nil {
return nil, errors.New("no aggregate and proof domain provider specified")
}
if parameters.signatureDomainProvider == nil {
return nil, errors.New("no signature domain provider specified")
if parameters.domainProvider == nil {
return nil, errors.New("no domain provider specified")
}
return &parameters, nil

View File

@ -22,6 +22,7 @@ import (
eth2client "github.com/attestantio/go-eth2-client"
api "github.com/attestantio/go-eth2-client/api/v1"
spec "github.com/attestantio/go-eth2-client/spec/phase0"
"github.com/attestantio/vouch/services/accountmanager"
"github.com/attestantio/vouch/services/metrics"
"github.com/pkg/errors"
@ -40,15 +41,15 @@ type Service struct {
stores []e2wtypes.Store
accountPaths []string
passphrases [][]byte
accounts map[[48]byte]*ValidatingAccount
accounts map[spec.BLSPubKey]*ValidatingAccount
validatorsProvider eth2client.ValidatorsProvider
slotsPerEpoch uint64
beaconProposerDomain []byte
beaconAttesterDomain []byte
randaoDomain []byte
selectionProofDomain []byte
aggregateAndProofDomain []byte
signatureDomainProvider eth2client.SignatureDomainProvider
slotsPerEpoch spec.Slot
beaconProposerDomain spec.DomainType
beaconAttesterDomain spec.DomainType
randaoDomain spec.DomainType
selectionProofDomain spec.DomainType
aggregateAndProofDomain spec.DomainType
domainProvider eth2client.DomainProvider
}
// module-wide log.
@ -81,23 +82,23 @@ func New(ctx context.Context, params ...Parameter) (*Service, error) {
if err != nil {
return nil, errors.Wrap(err, "failed to obtain slots per epoch")
}
beaconAttesterDomain, err := parameters.beaconAttesterDomainProvider.BeaconAttesterDomain(ctx)
beaconAttesterDomainType, err := parameters.beaconAttesterDomainProvider.BeaconAttesterDomain(ctx)
if err != nil {
return nil, errors.Wrap(err, "failed to obtain beacon attester domain")
}
beaconProposerDomain, err := parameters.beaconProposerDomainProvider.BeaconProposerDomain(ctx)
beaconProposerDomainType, err := parameters.beaconProposerDomainProvider.BeaconProposerDomain(ctx)
if err != nil {
return nil, errors.Wrap(err, "failed to obtain beacon proposer domain")
}
randaoDomain, err := parameters.randaoDomainProvider.RANDAODomain(ctx)
randaoDomainType, err := parameters.randaoDomainProvider.RANDAODomain(ctx)
if err != nil {
return nil, errors.Wrap(err, "failed to obtain RANDAO domain")
}
selectionProofDomain, err := parameters.selectionProofDomainProvider.SelectionProofDomain(ctx)
selectionProofDomainType, err := parameters.selectionProofDomainProvider.SelectionProofDomain(ctx)
if err != nil {
return nil, errors.Wrap(err, "failed to obtain selection proof domain")
}
aggregateAndProofDomain, err := parameters.aggregateAndProofDomainProvider.AggregateAndProofDomain(ctx)
aggregateAndProofDomainType, err := parameters.aggregateAndProofDomainProvider.AggregateAndProofDomain(ctx)
if err != nil {
return nil, errors.Wrap(err, "failed to obtain aggregate and proof domain")
}
@ -107,13 +108,13 @@ func New(ctx context.Context, params ...Parameter) (*Service, error) {
accountPaths: parameters.accountPaths,
passphrases: parameters.passphrases,
validatorsProvider: parameters.validatorsProvider,
slotsPerEpoch: slotsPerEpoch,
beaconAttesterDomain: beaconAttesterDomain,
beaconProposerDomain: beaconProposerDomain,
randaoDomain: randaoDomain,
selectionProofDomain: selectionProofDomain,
aggregateAndProofDomain: aggregateAndProofDomain,
signatureDomainProvider: parameters.signatureDomainProvider,
slotsPerEpoch: spec.Slot(slotsPerEpoch),
beaconAttesterDomain: beaconAttesterDomainType,
beaconProposerDomain: beaconProposerDomainType,
randaoDomain: randaoDomainType,
selectionProofDomain: selectionProofDomainType,
aggregateAndProofDomain: aggregateAndProofDomainType,
domainProvider: parameters.domainProvider,
}
if err := s.RefreshAccounts(ctx); err != nil {
@ -126,22 +127,22 @@ func New(ctx context.Context, params ...Parameter) (*Service, error) {
// UpdateAccountsState updates account state with the latest information from the beacon chain.
// This should be run at the beginning of each epoch to ensure that any newly-activated accounts are registered.
func (s *Service) UpdateAccountsState(ctx context.Context) error {
validatorIDs := make([]uint64, 0, len(s.accounts))
validatorIndices := make([]spec.ValidatorIndex, 0, len(s.accounts))
for _, account := range s.accounts {
if !account.state.IsAttesting() {
index, err := account.Index(ctx)
if err != nil {
return errors.Wrap(err, "failed to obtain account index")
}
validatorIDs = append(validatorIDs, index)
validatorIndices = append(validatorIndices, index)
}
}
if len(validatorIDs) == 0 {
if len(validatorIndices) == 0 {
// Nothing to do.
log.Trace().Msg("No unactivated keys")
return nil
}
validators, err := s.validatorsProvider.Validators(ctx, "head", validatorIDs)
validators, err := s.validatorsProvider.Validators(ctx, "head", validatorIndices)
if err != nil {
return errors.Wrap(err, "failed to obtain validators")
}
@ -184,7 +185,7 @@ func (s *Service) RefreshAccounts(ctx context.Context) error {
verificationRegexes := accountPathsToVerificationRegexes(s.accountPaths)
// Fetch accounts for each wallet.
accounts := make(map[[48]byte]*ValidatingAccount)
accounts := make(map[spec.BLSPubKey]*ValidatingAccount)
for _, wallet := range wallets {
// if _, isProvider := wallet.(e2wtypes.WalletAccountsByPathProvider); isProvider {
// fmt.Printf("TODO: fetch accounts by path")
@ -194,7 +195,7 @@ func (s *Service) RefreshAccounts(ctx context.Context) error {
}
// Update indices for accounts.
pubKeys := make([][]byte, 0, len(accounts))
pubKeys := make([]spec.BLSPubKey, 0, len(accounts))
for _, account := range accounts {
pubKey, err := account.PubKey(ctx)
if err != nil {
@ -238,9 +239,9 @@ func (s *Service) Accounts(ctx context.Context) ([]accountmanager.ValidatingAcco
}
// AccountsByIndex returns attesting accounts.
func (s *Service) AccountsByIndex(ctx context.Context, indices []uint64) ([]accountmanager.ValidatingAccount, error) {
indexMap := make(map[uint64]bool)
for _, index := range indices {
func (s *Service) AccountsByIndex(ctx context.Context, validatorIndices []spec.ValidatorIndex) ([]accountmanager.ValidatingAccount, error) {
indexMap := make(map[spec.ValidatorIndex]bool)
for _, index := range validatorIndices {
indexMap[index] = true
}
@ -267,12 +268,10 @@ func (s *Service) AccountsByIndex(ctx context.Context, indices []uint64) ([]acco
}
// AccountsByPubKey returns validating accounts.
func (s *Service) AccountsByPubKey(ctx context.Context, pubKeys [][]byte) ([]accountmanager.ValidatingAccount, error) {
pubKeyMap := make(map[[48]byte]bool)
func (s *Service) AccountsByPubKey(ctx context.Context, pubKeys []spec.BLSPubKey) ([]accountmanager.ValidatingAccount, error) {
pubKeyMap := make(map[spec.BLSPubKey]bool)
for _, pubKey := range pubKeys {
var mapKey [48]byte
copy(mapKey[:], pubKey)
pubKeyMap[mapKey] = true
pubKeyMap[pubKey] = true
}
s.mutex.RLock()
@ -321,12 +320,10 @@ func accountPathsToVerificationRegexes(paths []string) []*regexp.Regexp {
return regexes
}
func (s *Service) updateAccountStates(ctx context.Context, accounts map[[48]byte]*ValidatingAccount, validators map[uint64]*api.Validator) {
validatorsByPubKey := make(map[[48]byte]*api.Validator, len(validators))
func (s *Service) updateAccountStates(ctx context.Context, accounts map[spec.BLSPubKey]*ValidatingAccount, validators map[spec.ValidatorIndex]*api.Validator) {
validatorsByPubKey := make(map[spec.BLSPubKey]*api.Validator, len(validators))
for _, validator := range validators {
var pubKey [48]byte
copy(pubKey[:], validator.Validator.PublicKey)
validatorsByPubKey[pubKey] = validator
validatorsByPubKey[validator.Validator.PublicKey] = validator
}
validatorStateCounts := make(map[string]uint64)
@ -353,7 +350,7 @@ func (s *Service) updateAccountStates(ctx context.Context, accounts map[[48]byte
}
}
func (s *Service) fetchAccountsForWallet(ctx context.Context, wallet e2wtypes.Wallet, accounts map[[48]byte]*ValidatingAccount, verificationRegexes []*regexp.Regexp) {
func (s *Service) fetchAccountsForWallet(ctx context.Context, wallet e2wtypes.Wallet, accounts map[spec.BLSPubKey]*ValidatingAccount, verificationRegexes []*regexp.Regexp) {
for account := range wallet.Accounts(ctx) {
// Ensure the name matches one of our account paths.
name := fmt.Sprintf("%s/%s", wallet.Name(), account.Name())
@ -393,9 +390,9 @@ func (s *Service) fetchAccountsForWallet(ctx context.Context, wallet e2wtypes.Wa
// Set up account as unknown to beacon chain.
accounts[bytesutil.ToBytes48(pubKey)] = &ValidatingAccount{
account: account,
accountManager: s,
signatureDomainProvider: s.signatureDomainProvider,
account: account,
accountManager: s,
domainProvider: s.domainProvider,
}
}
}

View File

@ -1,20 +0,0 @@
// Copyright © 2020 Attestant Limited.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package wallet
// SigningContainer is the container for signing roots with a domain.
type SigningContainer struct {
Root []byte `ssz-size:"32"`
Domain []byte `ssz-size:"32"`
}

View File

@ -1,88 +0,0 @@
// Code generated by fastssz. DO NOT EDIT.
package wallet
import (
ssz "github.com/ferranbt/fastssz"
)
// MarshalSSZ ssz marshals the SigningContainer object
func (s *SigningContainer) MarshalSSZ() ([]byte, error) {
return ssz.MarshalSSZ(s)
}
// MarshalSSZTo ssz marshals the SigningContainer object to a target array
func (s *SigningContainer) MarshalSSZTo(buf []byte) (dst []byte, err error) {
dst = buf
// Field (0) 'Root'
if len(s.Root) != 32 {
err = ssz.ErrBytesLength
return
}
dst = append(dst, s.Root...)
// Field (1) 'Domain'
if len(s.Domain) != 32 {
err = ssz.ErrBytesLength
return
}
dst = append(dst, s.Domain...)
return
}
// UnmarshalSSZ ssz unmarshals the SigningContainer object
func (s *SigningContainer) UnmarshalSSZ(buf []byte) error {
var err error
size := uint64(len(buf))
if size != 64 {
return ssz.ErrSize
}
// Field (0) 'Root'
if cap(s.Root) == 0 {
s.Root = make([]byte, 0, len(buf[0:32]))
}
s.Root = append(s.Root, buf[0:32]...)
// Field (1) 'Domain'
if cap(s.Domain) == 0 {
s.Domain = make([]byte, 0, len(buf[32:64]))
}
s.Domain = append(s.Domain, buf[32:64]...)
return err
}
// SizeSSZ returns the ssz encoded size in bytes for the SigningContainer object
func (s *SigningContainer) SizeSSZ() (size int) {
size = 64
return
}
// HashTreeRoot ssz hashes the SigningContainer object
func (s *SigningContainer) HashTreeRoot() ([32]byte, error) {
return ssz.HashWithDefaultHasher(s)
}
// HashTreeRootWith ssz hashes the SigningContainer object with a hasher
func (s *SigningContainer) HashTreeRootWith(hh *ssz.Hasher) (err error) {
indx := hh.Index()
// Field (0) 'Root'
if len(s.Root) != 32 {
err = ssz.ErrBytesLength
return
}
hh.PutBytes(s.Root)
// Field (1) 'Domain'
if len(s.Domain) != 32 {
err = ssz.ErrBytesLength
return
}
hh.PutBytes(s.Domain)
hh.Merkleize(indx)
return
}

View File

@ -21,28 +21,32 @@ import (
api "github.com/attestantio/go-eth2-client/api/v1"
spec "github.com/attestantio/go-eth2-client/spec/phase0"
"github.com/pkg/errors"
e2types "github.com/wealdtech/go-eth2-types/v2"
e2wtypes "github.com/wealdtech/go-eth2-wallet-types/v2"
)
// ValidatingAccount is a wrapper around the wallet account that implements ValidatingAccount.
type ValidatingAccount struct {
account e2wtypes.Account
index uint64
state api.ValidatorState
accountManager *Service
signatureDomainProvider eth2client.SignatureDomainProvider
account e2wtypes.Account
index spec.ValidatorIndex
state api.ValidatorState
accountManager *Service
domainProvider eth2client.DomainProvider
}
// PubKey returns the public key of the validating account.
func (d *ValidatingAccount) PubKey(ctx context.Context) ([]byte, error) {
func (d *ValidatingAccount) PubKey(ctx context.Context) (spec.BLSPubKey, error) {
var pubKey spec.BLSPubKey
if provider, isProvider := d.account.(e2wtypes.AccountCompositePublicKeyProvider); isProvider {
return provider.CompositePublicKey().Marshal(), nil
copy(pubKey[:], provider.CompositePublicKey().Marshal())
} else {
copy(pubKey[:], d.account.PublicKey().Marshal())
}
return d.account.PublicKey().Marshal(), nil
return pubKey, nil
}
// Index returns the index of the validating account.
func (d *ValidatingAccount) Index(ctx context.Context) (uint64, error) {
func (d *ValidatingAccount) Index(ctx context.Context) (spec.ValidatorIndex, error) {
return d.index, nil
}
@ -53,16 +57,16 @@ func (d *ValidatingAccount) State() api.ValidatorState {
// SignSlotSelection returns a slot selection signature.
// This signs a slot with the "selection proof" domain.
func (d *ValidatingAccount) SignSlotSelection(ctx context.Context, slot uint64) ([]byte, error) {
messageRoot := make([]byte, 32)
binary.LittleEndian.PutUint64(messageRoot, slot)
func (d *ValidatingAccount) SignSlotSelection(ctx context.Context, slot spec.Slot) (spec.BLSSignature, error) {
var messageRoot spec.Root
binary.LittleEndian.PutUint64(messageRoot[:], uint64(slot))
// Calculate the signature domain.
domain, err := d.signatureDomainProvider.SignatureDomain(ctx,
// Calculate the domain.
domain, err := d.domainProvider.Domain(ctx,
d.accountManager.selectionProofDomain,
slot/d.accountManager.slotsPerEpoch)
spec.Epoch(slot/d.accountManager.slotsPerEpoch))
if err != nil {
return nil, errors.Wrap(err, "failed to obtain signature domain for selection proof")
return spec.BLSSignature{}, errors.Wrap(err, "failed to obtain domain for selection proof")
}
return d.sign(ctx, messageRoot, domain)
@ -70,30 +74,32 @@ func (d *ValidatingAccount) SignSlotSelection(ctx context.Context, slot uint64)
// SignRANDAOReveal returns a RANDAO reveal signature.
// This signs an epoch with the "RANDAO reveal" domain.
// N.B. This passes in a slot, not an epoch.
func (d *ValidatingAccount) SignRANDAOReveal(ctx context.Context, slot uint64) ([]byte, error) {
messageRoot := make([]byte, 32)
epoch := slot / d.accountManager.slotsPerEpoch
binary.LittleEndian.PutUint64(messageRoot, epoch)
func (d *ValidatingAccount) SignRANDAOReveal(ctx context.Context, slot spec.Slot) (spec.BLSSignature, error) {
var messageRoot spec.Root
epoch := spec.Epoch(slot / d.accountManager.slotsPerEpoch)
binary.LittleEndian.PutUint64(messageRoot[:], uint64(epoch))
// Obtain the RANDAO reveal signature domain.
domain, err := d.signatureDomainProvider.SignatureDomain(ctx,
domain, err := d.domainProvider.Domain(ctx,
d.accountManager.randaoDomain,
epoch)
if err != nil {
return nil, errors.Wrap(err, "failed to obtain signature domain for RANDAO reveal")
return spec.BLSSignature{}, errors.Wrap(err, "failed to obtain signature domain for RANDAO reveal")
}
return d.sign(ctx, messageRoot, domain)
var epochBytes spec.Root
binary.LittleEndian.PutUint64(epochBytes[:], uint64(epoch))
return d.sign(ctx, epochBytes, domain)
}
// SignBeaconBlockProposal signs a beacon block proposal item.
func (d *ValidatingAccount) SignBeaconBlockProposal(ctx context.Context,
slot uint64,
proposerIndex uint64,
parentRoot []byte,
stateRoot []byte,
bodyRoot []byte) ([]byte, error) {
slot spec.Slot,
proposerIndex spec.ValidatorIndex,
parentRoot spec.Root,
stateRoot spec.Root,
bodyRoot spec.Root) (spec.BLSSignature, error) {
message := &spec.BeaconBlockHeader{
Slot: slot,
@ -104,29 +110,29 @@ func (d *ValidatingAccount) SignBeaconBlockProposal(ctx context.Context,
}
messageRoot, err := message.HashTreeRoot()
if err != nil {
return nil, errors.Wrap(err, "failed to obtain hash tree root of block")
return spec.BLSSignature{}, errors.Wrap(err, "failed to obtain hash tree root of block")
}
// Obtain the signature domain.
domain, err := d.signatureDomainProvider.SignatureDomain(ctx,
// Fetch the domain.
domain, err := d.domainProvider.Domain(ctx,
d.accountManager.beaconProposerDomain,
slot/d.accountManager.slotsPerEpoch)
spec.Epoch(slot/d.accountManager.slotsPerEpoch))
if err != nil {
return nil, errors.Wrap(err, "failed to obtain signature domain for beacon proposal")
return spec.BLSSignature{}, errors.Wrap(err, "failed to obtain signature domain for beacon proposal")
}
return d.sign(ctx, messageRoot[:], domain)
return d.sign(ctx, messageRoot, domain)
}
// SignBeaconAttestation signs a beacon attestation item.
func (d *ValidatingAccount) SignBeaconAttestation(ctx context.Context,
slot uint64,
committeeIndex uint64,
blockRoot []byte,
sourceEpoch uint64,
sourceRoot []byte,
targetEpoch uint64,
targetRoot []byte) ([]byte, error) {
slot spec.Slot,
committeeIndex spec.CommitteeIndex,
blockRoot spec.Root,
sourceEpoch spec.Epoch,
sourceRoot spec.Root,
targetEpoch spec.Epoch,
targetRoot spec.Root) (spec.BLSSignature, error) {
message := &spec.AttestationData{
Slot: slot,
@ -143,46 +149,56 @@ func (d *ValidatingAccount) SignBeaconAttestation(ctx context.Context,
}
messageRoot, err := message.HashTreeRoot()
if err != nil {
return nil, errors.Wrap(err, "failed to obtain hash tree root of attestation data")
return spec.BLSSignature{}, errors.Wrap(err, "failed to obtain hash tree root of attestation data")
}
domain, err := d.signatureDomainProvider.SignatureDomain(ctx,
domain, err := d.domainProvider.Domain(ctx,
d.accountManager.beaconAttesterDomain,
slot/d.accountManager.slotsPerEpoch)
spec.Epoch(slot/d.accountManager.slotsPerEpoch))
if err != nil {
return nil, errors.Wrap(err, "failed to obtain signature domain for beacon attestation")
return spec.BLSSignature{}, errors.Wrap(err, "failed to obtain signature domain for beacon attestation")
}
return d.sign(ctx, messageRoot[:], domain)
return d.sign(ctx, messageRoot, domain)
}
// SignAggregateAndProof signs an aggregate and proof item.
func (d *ValidatingAccount) SignAggregateAndProof(ctx context.Context, slot uint64, aggregateAndProofRoot []byte) ([]byte, error) {
func (d *ValidatingAccount) SignAggregateAndProof(ctx context.Context, slot spec.Slot, aggregateAndProofRoot spec.Root) (spec.BLSSignature, error) {
// Fetch the signature domain.
domain, err := d.signatureDomainProvider.SignatureDomain(ctx,
domain, err := d.domainProvider.Domain(ctx,
d.accountManager.aggregateAndProofDomain,
slot)
spec.Epoch(slot/d.accountManager.slotsPerEpoch))
if err != nil {
return nil, errors.Wrap(err, "failed to obtain signature domain for beacon aggregate and proof")
return spec.BLSSignature{}, errors.Wrap(err, "failed to obtain signature domain for beacon aggregate and proof")
}
return d.sign(ctx, aggregateAndProofRoot, domain)
}
func (d *ValidatingAccount) sign(ctx context.Context, messageRoot []byte, domain []byte) ([]byte, error) {
container := &SigningContainer{
Root: messageRoot,
Domain: domain,
func (d *ValidatingAccount) sign(ctx context.Context, message spec.Root, domain spec.Domain) (spec.BLSSignature, error) {
var sig e2types.Signature
var err error
if protectingSigner, isProtectingSigner := d.account.(e2wtypes.AccountProtectingSigner); isProtectingSigner {
sig, err = protectingSigner.SignGeneric(ctx, message[:], domain[:])
} else {
// Create the root manually.
container := &spec.SigningData{
ObjectRoot: message,
Domain: domain,
}
var signingRoot spec.Root
signingRoot, err = container.HashTreeRoot()
if err != nil {
return spec.BLSSignature{}, errors.Wrap(err, "failed to generate hash tree root for signing container")
}
sig, err = d.account.(e2wtypes.AccountSigner).Sign(ctx, signingRoot[:])
}
signingRoot, err := container.HashTreeRoot()
if err != nil {
return nil, errors.Wrap(err, "failed to generate hash tree root for signing container")
return spec.BLSSignature{}, errors.Wrap(err, "failed to sign")
}
sig, err := d.account.(e2wtypes.AccountSigner).Sign(ctx, signingRoot[:])
if err != nil {
return nil, errors.Wrap(err, "failed to sign beacon block proposal")
}
return sig.Marshal(), nil
var signature spec.BLSSignature
copy(signature[:], sig.Marshal())
return signature, nil
}

View File

@ -15,24 +15,26 @@ package attestationaggregator
import (
"context"
spec "github.com/attestantio/go-eth2-client/spec/phase0"
)
// Duty contains information about an attestation aggregation duty.
type Duty struct {
// Slot is the slot of the attestation aggregation; required for obtaining the aggregate.
Slot uint64
Slot spec.Slot
// Attestation data root is the root of the attestation to be aggregated; required for obtaining the aggregate.
AttestationDataRoot []byte
AttestationDataRoot spec.Root
// ValidatorIndex is the index of the validator carrying out the aggregation; reuqired for submitting the aggregate.
ValidatorIndex uint64
ValidatorIndex spec.ValidatorIndex
// SlotSignature is the signature of the slot by the validator carrying out the aggregation; reuqired for submitting the aggregate.
SlotSignature []byte
SlotSignature spec.BLSSignature
}
// IsAggregatorProvider provides information about if a validator is an aggregator.
type IsAggregatorProvider interface {
// IsAggregator returns true if the given validator is an aggregator for the given committee at the given slot.
IsAggregator(ctx context.Context, validatorIndex uint64, committeeIndex uint64, slot uint64, committeeSize uint64) (bool, []byte, error)
IsAggregator(ctx context.Context, validatorIndex spec.ValidatorIndex, committeeIndex spec.CommitteeIndex, slot spec.Slot, committeeSize uint64) (bool, spec.BLSSignature, error)
}
// Service is the attestation aggregation service.

View File

@ -28,6 +28,7 @@ type parameters struct {
targetAggregatorsPerCommitteeProvider eth2client.TargetAggregatorsPerCommitteeProvider
validatingAccountsProvider accountmanager.ValidatingAccountsProvider
aggregateAttestationProvider eth2client.AggregateAttestationProvider
prysmAggregateAttestationProvider eth2client.PrysmAggregateAttestationProvider
aggregateAttestationsSubmitter submitter.AggregateAttestationsSubmitter
}
@ -77,6 +78,13 @@ func WithAggregateAttestationDataProvider(provider eth2client.AggregateAttestati
})
}
// WithPrysmAggregateAttestationDataProvider sets the non-spec aggregate attestation provider.
func WithPrysmAggregateAttestationDataProvider(provider eth2client.PrysmAggregateAttestationProvider) Parameter {
return parameterFunc(func(p *parameters) {
p.prysmAggregateAttestationProvider = provider
})
}
// WithAggregateAttestationsSubmitter sets the aggregate attestation submitter.
func WithAggregateAttestationsSubmitter(submitter submitter.AggregateAttestationsSubmitter) Parameter {
return parameterFunc(func(p *parameters) {
@ -104,7 +112,7 @@ func parseAndCheckParameters(params ...Parameter) (*parameters, error) {
if parameters.validatingAccountsProvider == nil {
return nil, errors.New("no validating accounts provider specified")
}
if parameters.aggregateAttestationProvider == nil {
if parameters.aggregateAttestationProvider == nil && parameters.prysmAggregateAttestationProvider == nil {
return nil, errors.New("no aggregate attestation provider specified")
}
if parameters.aggregateAttestationsSubmitter == nil {

View File

@ -33,11 +33,12 @@ import (
// Service is an attestation aggregator.
type Service struct {
monitor metrics.AttestationAggregationMonitor
targetAggregatorsPerCommittee uint64
validatingAccountsProvider accountmanager.ValidatingAccountsProvider
aggregateAttestationProvider eth2client.AggregateAttestationProvider
aggregateAttestationsSubmitter submitter.AggregateAttestationsSubmitter
monitor metrics.AttestationAggregationMonitor
targetAggregatorsPerCommittee uint64
validatingAccountsProvider accountmanager.ValidatingAccountsProvider
aggregateAttestationProvider eth2client.AggregateAttestationProvider
prysmAggregateAttestationProvider eth2client.PrysmAggregateAttestationProvider
aggregateAttestationsSubmitter submitter.AggregateAttestationsSubmitter
}
// module-wide log.
@ -62,11 +63,12 @@ func New(ctx context.Context, params ...Parameter) (*Service, error) {
}
s := &Service{
monitor: parameters.monitor,
targetAggregatorsPerCommittee: targetAggregatorsPerCommittee,
validatingAccountsProvider: parameters.validatingAccountsProvider,
aggregateAttestationProvider: parameters.aggregateAttestationProvider,
aggregateAttestationsSubmitter: parameters.aggregateAttestationsSubmitter,
monitor: parameters.monitor,
targetAggregatorsPerCommittee: targetAggregatorsPerCommittee,
validatingAccountsProvider: parameters.validatingAccountsProvider,
aggregateAttestationProvider: parameters.aggregateAttestationProvider,
prysmAggregateAttestationProvider: parameters.prysmAggregateAttestationProvider,
aggregateAttestationsSubmitter: parameters.aggregateAttestationsSubmitter,
}
return s, nil
@ -82,20 +84,32 @@ func (s *Service) Aggregate(ctx context.Context, data interface{}) {
s.monitor.AttestationAggregationCompleted(started, "failed")
return
}
log := log.With().Uint64("slot", duty.Slot).Str("attestation_data_root", fmt.Sprintf("%#x", duty.AttestationDataRoot)).Logger()
log := log.With().Uint64("slot", uint64(duty.Slot)).Str("attestation_data_root", fmt.Sprintf("%#x", duty.AttestationDataRoot)).Logger()
log.Trace().Msg("Aggregating")
// Obtain the aggregate attestation.
aggregateAttestation, err := s.aggregateAttestationProvider.AggregateAttestation(ctx, duty.Slot, duty.AttestationDataRoot)
var aggregateAttestation *spec.Attestation
var err error
if s.aggregateAttestationProvider != nil {
aggregateAttestation, err = s.aggregateAttestationProvider.AggregateAttestation(ctx, duty.Slot, duty.AttestationDataRoot)
} else {
// TODO
log.Debug().Msg("Not aggregating for non-spec beacon node")
return
}
if err != nil {
log.Error().Err(err).Msg("Failed to obtain aggregate attestation")
s.monitor.AttestationAggregationCompleted(started, "failed")
return
}
log.Trace().Dur("elapsed", time.Since(started)).Msg("Obtained aggregate attestation")
if aggregateAttestation == nil {
log.Debug().Msg("Obtained nil aggregate attestation")
return
}
// Fetch the validating account.
accounts, err := s.validatingAccountsProvider.AccountsByIndex(ctx, []uint64{duty.ValidatorIndex})
accounts, err := s.validatingAccountsProvider.AccountsByIndex(ctx, []spec.ValidatorIndex{duty.ValidatorIndex})
if err != nil {
log.Error().Err(err).Msg("Failed to obtain proposing validator account")
s.monitor.AttestationAggregationCompleted(started, "failed")
@ -126,7 +140,7 @@ func (s *Service) Aggregate(ctx context.Context, data interface{}) {
if err != nil {
log.Error().Err(err).Msg("Failed to generate hash tree root of aggregate and proof")
}
sig, err := signer.SignAggregateAndProof(ctx, duty.Slot, aggregateAndProofRoot[:])
sig, err := signer.SignAggregateAndProof(ctx, duty.Slot, spec.Root(aggregateAndProofRoot))
if err != nil {
log.Error().Err(err).Msg("Failed to sign aggregate and proof")
s.monitor.AttestationAggregationCompleted(started, "failed")
@ -155,7 +169,12 @@ func (s *Service) Aggregate(ctx context.Context, data interface{}) {
}
// IsAggregator reports if we are an attestation aggregator for a given validator/committee/slot combination.
func (s *Service) IsAggregator(ctx context.Context, validatorIndex uint64, committeeIndex uint64, slot uint64, committeeSize uint64) (bool, []byte, error) {
func (s *Service) IsAggregator(ctx context.Context,
validatorIndex spec.ValidatorIndex,
committeeIndex spec.CommitteeIndex,
slot spec.Slot,
committeeSize uint64,
) (bool, spec.BLSSignature, error) {
modulo := committeeSize / s.targetAggregatorsPerCommittee
if modulo == 0 {
// Modulo must be at least 1.
@ -163,34 +182,34 @@ func (s *Service) IsAggregator(ctx context.Context, validatorIndex uint64, commi
}
// Fetch the validator from the account manager.
accounts, err := s.validatingAccountsProvider.AccountsByIndex(ctx, []uint64{validatorIndex})
accounts, err := s.validatingAccountsProvider.AccountsByIndex(ctx, []spec.ValidatorIndex{validatorIndex})
if err != nil {
return false, nil, errors.Wrap(err, "failed to obtain validator")
return false, spec.BLSSignature{}, errors.Wrap(err, "failed to obtain validator")
}
if len(accounts) == 0 {
return false, nil, errors.New("validator unknown")
return false, spec.BLSSignature{}, errors.New("validator unknown")
}
account := accounts[0]
slotSelectionSigner, isSlotSelectionSigner := account.(accountmanager.SlotSelectionSigner)
if !isSlotSelectionSigner {
return false, nil, errors.New("validating account is not a slot selection signer")
return false, spec.BLSSignature{}, errors.New("validating account is not a slot selection signer")
}
// Sign the slot.
signature, err := slotSelectionSigner.SignSlotSelection(ctx, slot)
if err != nil {
return false, nil, errors.Wrap(err, "failed to sign the slot")
return false, spec.BLSSignature{}, errors.Wrap(err, "failed to sign the slot")
}
// Hash the signature.
sigHash := sha256.New()
n, err := sigHash.Write(signature)
n, err := sigHash.Write(signature[:])
if err != nil {
return false, nil, errors.Wrap(err, "failed to hash the slot signature")
return false, spec.BLSSignature{}, errors.Wrap(err, "failed to hash the slot signature")
}
if n != len(signature) {
return false, nil, errors.New("failed to write all bytes of the slot signature to the hash")
return false, spec.BLSSignature{}, errors.New("failed to write all bytes of the slot signature to the hash")
}
hash := sigHash.Sum(nil)

View File

@ -18,6 +18,7 @@ import (
"sort"
api "github.com/attestantio/go-eth2-client/api/v1"
spec "github.com/attestantio/go-eth2-client/spec/phase0"
)
// MergeDuties merges attester duties given by an Ethereum 2 client into vouch's per-slot structure.
@ -27,11 +28,11 @@ func MergeDuties(ctx context.Context, attesterDuties []*api.AttesterDuty) ([]*Du
return duties, nil
}
validatorIndices := make(map[uint64][]uint64)
committeeIndices := make(map[uint64][]uint64)
validatorCommitteeIndices := make(map[uint64][]uint64)
committeeLengths := make(map[uint64]map[uint64]uint64)
committeesAtSlots := make(map[uint64]uint64)
validatorIndices := make(map[spec.Slot][]spec.ValidatorIndex)
committeeIndices := make(map[spec.Slot][]spec.CommitteeIndex)
validatorCommitteeIndices := make(map[spec.Slot][]uint64)
committeeLengths := make(map[spec.Slot]map[spec.CommitteeIndex]uint64)
committeesAtSlots := make(map[spec.Slot]uint64)
// Set the base capacity for our arrays based on the number of attester duties.
// This is much higher than we need, but is overall minimal and avoids reallocations.
@ -62,9 +63,9 @@ func MergeDuties(ctx context.Context, attesterDuties []*api.AttesterDuty) ([]*Du
_, exists := validatorIndices[duty.Slot]
if !exists {
validatorIndices[duty.Slot] = make([]uint64, 0, arrayCap)
committeeIndices[duty.Slot] = make([]uint64, 0, arrayCap)
committeeLengths[duty.Slot] = make(map[uint64]uint64)
validatorIndices[duty.Slot] = make([]spec.ValidatorIndex, 0, arrayCap)
committeeIndices[duty.Slot] = make([]spec.CommitteeIndex, 0, arrayCap)
committeeLengths[duty.Slot] = make(map[spec.CommitteeIndex]uint64)
committeesAtSlots[duty.Slot] = duty.CommitteesAtSlot
}
validatorIndices[duty.Slot] = append(validatorIndices[duty.Slot], duty.ValidatorIndex)

View File

@ -22,16 +22,23 @@ import (
// Duty contains information about a beacon block attester duty.
type Duty struct {
slot uint64
slot spec.Slot
committeesAtSlot uint64
validatorIndices []uint64
committeeIndices []uint64
validatorIndices []spec.ValidatorIndex
committeeIndices []spec.CommitteeIndex
validatorCommitteeIndices []uint64
committeeLengths map[uint64]uint64
committeeLengths map[spec.CommitteeIndex]uint64
}
// NewDuty creates a new beacon block attester duty.
func NewDuty(ctx context.Context, slot uint64, committeesAtSlot uint64, validatorIndices []uint64, committeeIndices []uint64, validatorCommitteeIndices []uint64, committeeLengths map[uint64]uint64) (*Duty, error) {
func NewDuty(ctx context.Context,
slot spec.Slot,
committeesAtSlot uint64,
validatorIndices []spec.ValidatorIndex,
committeeIndices []spec.CommitteeIndex,
validatorCommitteeIndices []uint64,
committeeLengths map[spec.CommitteeIndex]uint64,
) (*Duty, error) {
// Ensure there is a matching committee size for each committee index.
for i := range committeeIndices {
if _, exists := committeeLengths[committeeIndices[i]]; !exists {
@ -50,7 +57,7 @@ func NewDuty(ctx context.Context, slot uint64, committeesAtSlot uint64, validato
}
// Slot provides the slot for the beacon block attester.
func (d *Duty) Slot() uint64 {
func (d *Duty) Slot() spec.Slot {
return d.slot
}
@ -60,12 +67,12 @@ func (d *Duty) CommitteesAtSlot() uint64 {
}
// ValidatorIndices provides the validator indices for the beacon block attester.
func (d *Duty) ValidatorIndices() []uint64 {
func (d *Duty) ValidatorIndices() []spec.ValidatorIndex {
return d.validatorIndices
}
// CommitteeIndices provides the committee indices for the beacon block attester.
func (d *Duty) CommitteeIndices() []uint64 {
func (d *Duty) CommitteeIndices() []spec.CommitteeIndex {
return d.committeeIndices
}
@ -75,7 +82,7 @@ func (d *Duty) ValidatorCommitteeIndices() []uint64 {
}
// CommitteeSize provides the committee size for a given index.
func (d *Duty) CommitteeSize(committeeIndex uint64) uint64 {
func (d *Duty) CommitteeSize(committeeIndex spec.CommitteeIndex) uint64 {
return d.committeeLengths[committeeIndex]
}
@ -84,6 +91,20 @@ func (d *Duty) String() string {
return fmt.Sprintf("beacon block attester for slot %d with validators %v committee indices %v", d.slot, d.validatorIndices, d.committeeIndices)
}
// Tuples returns a slice of (validator index, committee index, validator position in committee) strings.
// Useful for logging the
func (d *Duty) Tuples() []string {
tuples := make([]string, len(d.committeeIndices))
for i := range d.committeeIndices {
tuples[i] = fmt.Sprintf("(%d,%d,%d)",
d.validatorIndices[i],
d.committeeIndices[i],
d.validatorCommitteeIndices[i],
)
}
return tuples
}
// Service is the beacon block attester service.
type Service interface {
// Attest carries out attestations for a slot.

View File

@ -85,8 +85,8 @@ func (s *Service) Attest(ctx context.Context, data interface{}) ([]*spec.Attesta
s.monitor.AttestationCompleted(started, "failed")
return nil, errors.New("passed invalid data structure")
}
log := log.With().Uint64("slot", duty.Slot()).Logger()
log.Trace().Uints64("validator_indices", duty.ValidatorIndices()).Msg("Attesting")
log := log.With().Uint64("slot", uint64(duty.Slot())).Logger()
log.Trace().Strs("duties", duty.Tuples()).Msg("Attesting")
attestations := make([]*spec.Attestation, 0, len(duty.ValidatorIndices()))
var attestationsMutex sync.Mutex
@ -110,10 +110,10 @@ func (s *Service) Attest(ctx context.Context, data interface{}) ([]*spec.Attesta
s.monitor.AttestationCompleted(started, "failed")
return nil, errors.New("failed to obtain attesting validator accounts")
}
log.Trace().Dur("elapsed", time.Since(started)).Uints64("validator_indices", duty.ValidatorIndices()).Msg("Obtained validating accounts")
log.Trace().Dur("elapsed", time.Since(started)).Strs("tuples", duty.Tuples()).Msg("Obtained validating accounts")
// Run the attestations in parallel, up to a concurrency limit.
validatorIndexToArrayIndexMap := make(map[uint64]int)
validatorIndexToArrayIndexMap := make(map[spec.ValidatorIndex]int)
for i := range duty.ValidatorIndices() {
validatorIndexToArrayIndexMap[duty.ValidatorIndices()[i]] = i
}
@ -134,7 +134,7 @@ func (s *Service) Attest(ctx context.Context, data interface{}) ([]*spec.Attesta
log.Warn().Err(err).Msg("Failed to obtain validator index")
return
}
log := log.With().Uint64("validator_index", validatorIndex).Logger()
log := log.With().Uint64("validator_index", uint64(validatorIndex)).Logger()
attestation, err := s.attest(ctx,
duty.Slot(),
duty.CommitteeIndices()[validatorIndexToArrayIndexMap[validatorIndex]],
@ -163,8 +163,8 @@ func (s *Service) Attest(ctx context.Context, data interface{}) ([]*spec.Attesta
func (s *Service) attest(
ctx context.Context,
slot uint64,
committeeIndex uint64,
slot spec.Slot,
committeeIndex spec.CommitteeIndex,
validatorCommitteeIndex uint64,
committeeSize uint64,
account accountmanager.ValidatingAccount,

View File

@ -16,20 +16,26 @@ package beaconblockproposer
import (
"context"
"fmt"
spec "github.com/attestantio/go-eth2-client/spec/phase0"
"github.com/attestantio/vouch/services/accountmanager"
)
// Duty contains information about a beacon block proposal duty.
type Duty struct {
// Details for the duty.
slot uint64
validatorIndex uint64
slot spec.Slot
validatorIndex spec.ValidatorIndex
// randaoReveal is required to be passed to the beacon node when proposing the block; can be pre-calculated.
randaoReveal []byte
randaoReveal spec.BLSSignature
// account is used to sign the proposal; can be pre-fetched.
account accountmanager.ValidatingAccount
}
// NewDuty creates a new beacon block proposer duty.
func NewDuty(ctx context.Context, slot uint64, validatorIndex uint64) (*Duty, error) {
func NewDuty(ctx context.Context, slot spec.Slot, validatorIndex spec.ValidatorIndex) (*Duty, error) {
return &Duty{
slot: slot,
validatorIndex: validatorIndex,
@ -37,12 +43,12 @@ func NewDuty(ctx context.Context, slot uint64, validatorIndex uint64) (*Duty, er
}
// Slot provides the slot for the beacon block proposer.
func (d *Duty) Slot() uint64 {
func (d *Duty) Slot() spec.Slot {
return d.slot
}
// ValidatorIndex provides the validator index for the beacon block proposer.
func (d *Duty) ValidatorIndex() uint64 {
func (d *Duty) ValidatorIndex() spec.ValidatorIndex {
return d.validatorIndex
}
@ -52,15 +58,25 @@ func (d *Duty) String() string {
}
// SetRandaoReveal sets the RANDAO reveal.
func (d *Duty) SetRandaoReveal(randaoReveal []byte) {
func (d *Duty) SetRandaoReveal(randaoReveal spec.BLSSignature) {
d.randaoReveal = randaoReveal
}
// RANDAOReveal provides the RANDAO reveal.
func (d *Duty) RANDAOReveal() []byte {
func (d *Duty) RANDAOReveal() spec.BLSSignature {
return d.randaoReveal
}
// SetAccount sets the account.
func (d *Duty) SetAccount(account accountmanager.ValidatingAccount) {
d.account = account
}
// Account provides the account.
func (d *Duty) Account() accountmanager.ValidatingAccount {
return d.account
}
// Service is the beacon block proposer service.
type Service interface {
// Prepare prepares the proposal for a slot.

View File

@ -26,7 +26,6 @@ import (
"github.com/attestantio/vouch/services/metrics"
"github.com/attestantio/vouch/services/submitter"
"github.com/pkg/errors"
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
"github.com/rs/zerolog"
zerologger "github.com/rs/zerolog/log"
)
@ -76,11 +75,11 @@ func (s *Service) Prepare(ctx context.Context, data interface{}) error {
if !ok {
return errors.New("passed invalid data structure")
}
log := log.With().Uint64("slot", duty.Slot()).Uint64("validator_index", duty.ValidatorIndex()).Logger()
log := log.With().Uint64("slot", uint64(duty.Slot())).Uint64("validator_index", uint64(duty.ValidatorIndex())).Logger()
log.Trace().Msg("Preparing")
// Fetch the validating account.
accounts, err := s.validatingAccountsProvider.AccountsByIndex(ctx, []uint64{duty.ValidatorIndex()})
accounts, err := s.validatingAccountsProvider.AccountsByIndex(ctx, []spec.ValidatorIndex{duty.ValidatorIndex()})
if err != nil {
return errors.Wrap(err, "failed to obtain proposing validator account")
}
@ -89,6 +88,7 @@ func (s *Service) Prepare(ctx context.Context, data interface{}) error {
}
account := accounts[0]
log.Trace().Dur("elapsed", time.Since(started)).Msg("Obtained proposing account")
duty.SetAccount(account)
revealSigner, isRevealSigner := account.(accountmanager.RANDAORevealSigner)
if !isRevealSigner {
@ -114,25 +114,11 @@ func (s *Service) Propose(ctx context.Context, data interface{}) {
s.monitor.BeaconBlockProposalCompleted(started, "failed")
return
}
log := log.With().Uint64("slot", duty.Slot()).Uint64("validator_index", duty.ValidatorIndex()).Logger()
log := log.With().Uint64("slot", uint64(duty.Slot())).Uint64("validator_index", uint64(duty.ValidatorIndex())).Logger()
log.Trace().Msg("Proposing")
// Fetch the validating account.
accounts, err := s.validatingAccountsProvider.AccountsByIndex(ctx, []uint64{duty.ValidatorIndex()})
if err != nil {
log.Error().Err(err).Msg("Failed to obtain proposing validator account")
s.monitor.BeaconBlockProposalCompleted(started, "failed")
return
}
if len(accounts) != 1 {
log.Error().Err(err).Msg("Unknown proposing validator account")
s.monitor.BeaconBlockProposalCompleted(started, "failed")
return
}
account := accounts[0]
log.Trace().Dur("elapsed", time.Since(started)).Msg("Obtained account")
var graffiti []byte
var err error
if s.graffitiProvider != nil {
graffiti, err = s.graffitiProvider.Graffiti(ctx, duty.Slot(), duty.ValidatorIndex())
if err != nil {
@ -156,7 +142,7 @@ func (s *Service) Propose(ctx context.Context, data interface{}) {
log.Trace().Dur("elapsed", time.Since(started)).Msg("Obtained proposal")
if proposal.Slot != duty.Slot() {
log.Error().Uint64("proposal_slot", proposal.Slot).Msg("Proposal data for incorrect slot; not proceeding")
log.Error().Uint64("proposal_slot", uint64(proposal.Slot)).Msg("Proposal data for incorrect slot; not proceeding")
s.monitor.BeaconBlockProposalCompleted(started, "failed")
return
}
@ -167,27 +153,20 @@ func (s *Service) Propose(ctx context.Context, data interface{}) {
s.monitor.BeaconBlockProposalCompleted(started, "failed")
return
}
proposalData := &ethpb.BeaconBlockHeader{
Slot: proposal.Slot,
ProposerIndex: duty.ValidatorIndex(),
ParentRoot: proposal.ParentRoot,
StateRoot: proposal.StateRoot,
BodyRoot: bodyRoot[:],
}
// Sign the block.
signer, isSigner := account.(accountmanager.BeaconBlockSigner)
signer, isSigner := duty.Account().(accountmanager.BeaconBlockSigner)
if !isSigner {
log.Error().Msg("Account is not a beacon block signer")
s.monitor.BeaconBlockProposalCompleted(started, "failed")
return
}
sig, err := signer.SignBeaconBlockProposal(ctx,
proposalData.Slot,
proposalData.ProposerIndex,
proposalData.ParentRoot,
proposalData.StateRoot,
proposalData.BodyRoot)
proposal.Slot,
duty.ValidatorIndex(),
proposal.ParentRoot,
proposal.StateRoot,
bodyRoot)
if err != nil {
log.Error().Err(err).Msg("Failed to sign beacon block proposal")
s.monitor.BeaconBlockProposalCompleted(started, "failed")

View File

@ -18,6 +18,7 @@ import (
"context"
api "github.com/attestantio/go-eth2-client/api/v1"
spec "github.com/attestantio/go-eth2-client/spec/phase0"
"github.com/attestantio/vouch/services/accountmanager"
)
@ -26,12 +27,11 @@ type Subscription struct {
Duty *api.AttesterDuty
IsAggregator bool
// TODO is this in the correct place?
Signature []byte
Signature spec.BLSSignature
}
// Service is the beacon committee subscriber service.
type Service interface {
// Subscribe subscribes to beacon committees for a given epoch.
// It returns a map of slot => committee => subscription info.
Subscribe(ctx context.Context, epoch uint64, accounts []accountmanager.ValidatingAccount) (map[uint64]map[uint64]*Subscription, error)
Subscribe(ctx context.Context, epoch spec.Epoch, accounts []accountmanager.ValidatingAccount) (map[spec.Slot]map[spec.CommitteeIndex]*Subscription, error)
}

View File

@ -20,6 +20,7 @@ import (
eth2client "github.com/attestantio/go-eth2-client"
api "github.com/attestantio/go-eth2-client/api/v1"
spec "github.com/attestantio/go-eth2-client/spec/phase0"
"github.com/attestantio/vouch/services/accountmanager"
"github.com/attestantio/vouch/services/attestationaggregator"
"github.com/attestantio/vouch/services/attester"
@ -71,13 +72,16 @@ func New(ctx context.Context, params ...Parameter) (*Service, error) {
// Subscribe subscribes to beacon committees for a given epoch.
// This returns data about the subnets to which we are subscribing.
func (s *Service) Subscribe(ctx context.Context, epoch uint64, accounts []accountmanager.ValidatingAccount) (map[uint64]map[uint64]*beaconcommitteesubscriber.Subscription, error) {
func (s *Service) Subscribe(ctx context.Context,
epoch spec.Epoch,
accounts []accountmanager.ValidatingAccount,
) (map[spec.Slot]map[spec.CommitteeIndex]*beaconcommitteesubscriber.Subscription, error) {
started := time.Now()
log := log.With().Uint64("epoch", epoch).Logger()
log := log.With().Uint64("epoch", uint64(epoch)).Logger()
log.Trace().Msg("Subscribing")
validatorIDs := make([]uint64, len(accounts))
validatorIDs := make([]spec.ValidatorIndex, len(accounts))
var err error
for i, account := range accounts {
validatorIDs[i], err = account.Index(ctx)
@ -149,17 +153,17 @@ func (s *Service) Subscribe(ctx context.Context, epoch uint64, accounts []accoun
// calculateSubscriptionInfo calculates our beacon block attesation subnet requirements given a set of duties.
// It returns a map of slot => committee => subscription information.
func (s *Service) calculateSubscriptionInfo(ctx context.Context,
epoch uint64,
epoch spec.Epoch,
accounts []accountmanager.ValidatingAccount,
duties []*attester.Duty,
) (map[uint64]map[uint64]*beaconcommitteesubscriber.Subscription, error) {
) (map[spec.Slot]map[spec.CommitteeIndex]*beaconcommitteesubscriber.Subscription, error) {
// Map is slot => committee => info.
subscriptionInfo := make(map[uint64]map[uint64]*beaconcommitteesubscriber.Subscription)
subscriptionInfo := make(map[spec.Slot]map[spec.CommitteeIndex]*beaconcommitteesubscriber.Subscription)
subscriptionInfoMutex := deadlock.RWMutex{}
// Map is validator ID => account.
accountMap := make(map[uint64]accountmanager.ValidatingAccount, len(accounts))
accountMap := make(map[spec.ValidatorIndex]accountmanager.ValidatingAccount, len(accounts))
for _, account := range accounts {
index, err := account.Index(ctx)
if err != nil {
@ -211,7 +215,7 @@ func (s *Service) calculateSubscriptionInfo(ctx context.Context,
}
subscriptionInfoMutex.Lock()
if _, exists := subscriptionInfo[duty.Slot()]; !exists {
subscriptionInfo[duty.Slot()] = make(map[uint64]*beaconcommitteesubscriber.Subscription)
subscriptionInfo[duty.Slot()] = make(map[spec.CommitteeIndex]*beaconcommitteesubscriber.Subscription)
}
subscriptionInfo[duty.Slot()][duty.CommitteeIndices()[i]] = &beaconcommitteesubscriber.Subscription{
Duty: &api.AttesterDuty{

View File

@ -13,22 +13,26 @@
package chaintime
import "time"
import (
"time"
spec "github.com/attestantio/go-eth2-client/spec/phase0"
)
// Service provides a number of functions for calculating chain-related times.
type Service interface {
// GenesisTime provides the time of the chain's genesis.
GenesisTime() time.Time
// StartOfSlot provides the time at which a given slot starts.
StartOfSlot(slot uint64) time.Time
StartOfSlot(slot spec.Slot) time.Time
// StartOfEpoch provides the time at which a given epoch starts.
StartOfEpoch(epoch uint64) time.Time
StartOfEpoch(epoch spec.Epoch) time.Time
// CurrentSlot provides the current slot.
CurrentSlot() uint64
CurrentSlot() spec.Slot
// CurrentEpoch provides the current epoch.
CurrentEpoch() uint64
CurrentEpoch() spec.Epoch
// SlotToEpoch provides the epoch of the given slot.
SlotToEpoch(slot uint64) uint64
SlotToEpoch(slot spec.Slot) spec.Epoch
// FirstSlotOfEpoch provides the first slot of the given epoch.
FirstSlotOfEpoch(epoch uint64) uint64
FirstSlotOfEpoch(epoch spec.Epoch) spec.Slot
}

View File

@ -17,6 +17,7 @@ import (
"context"
"time"
spec "github.com/attestantio/go-eth2-client/spec/phase0"
"github.com/pkg/errors"
"github.com/rs/zerolog"
zerologger "github.com/rs/zerolog/log"
@ -78,37 +79,37 @@ func (s *Service) GenesisTime() time.Time {
}
// StartOfSlot provides the time at which a given slot starts.
func (s *Service) StartOfSlot(slot uint64) time.Time {
func (s *Service) StartOfSlot(slot spec.Slot) time.Time {
return s.genesisTime.Add(time.Duration(slot) * s.slotDuration)
}
// StartOfEpoch provides the time at which a given epoch starts.
func (s *Service) StartOfEpoch(epoch uint64) time.Time {
return s.genesisTime.Add(time.Duration(epoch*s.slotsPerEpoch) * s.slotDuration)
func (s *Service) StartOfEpoch(epoch spec.Epoch) time.Time {
return s.genesisTime.Add(time.Duration(uint64(epoch)*s.slotsPerEpoch) * s.slotDuration)
}
// CurrentSlot provides the current slot.
func (s *Service) CurrentSlot() uint64 {
func (s *Service) CurrentSlot() spec.Slot {
if s.genesisTime.After(time.Now()) {
return 0
return spec.Slot(0)
}
return uint64(time.Since(s.genesisTime).Seconds()) / uint64(s.slotDuration.Seconds())
return spec.Slot(uint64(time.Since(s.genesisTime).Seconds()) / uint64(s.slotDuration.Seconds()))
}
// CurrentEpoch provides the current epoch.
func (s *Service) CurrentEpoch() uint64 {
func (s *Service) CurrentEpoch() spec.Epoch {
if s.genesisTime.After(time.Now()) {
return 0
return spec.Epoch(0)
}
return uint64(time.Since(s.genesisTime).Seconds()) / (uint64(s.slotDuration.Seconds()) * s.slotsPerEpoch)
return spec.Epoch(uint64(time.Since(s.genesisTime).Seconds()) / (uint64(s.slotDuration.Seconds()) * s.slotsPerEpoch))
}
// SlotToEpoch provides the epoch of a given slot.
func (s *Service) SlotToEpoch(slot uint64) uint64 {
return slot / s.slotsPerEpoch
func (s *Service) SlotToEpoch(slot spec.Slot) spec.Epoch {
return spec.Epoch(uint64(slot) / s.slotsPerEpoch)
}
// FirstSlotOfEpoch provides the first slot of the given epoch.
func (s *Service) FirstSlotOfEpoch(epoch uint64) uint64 {
return epoch * s.slotsPerEpoch
func (s *Service) FirstSlotOfEpoch(epoch spec.Epoch) spec.Slot {
return spec.Slot(uint64(epoch) * s.slotsPerEpoch)
}

View File

@ -18,6 +18,7 @@ import (
"testing"
"time"
spec "github.com/attestantio/go-eth2-client/spec/phase0"
"github.com/attestantio/vouch/mock"
"github.com/attestantio/vouch/services/chaintime"
"github.com/attestantio/vouch/services/chaintime/standard"
@ -143,7 +144,7 @@ func TestCurrentSlot(t *testing.T) {
s, err := createMockService(slotDuration, slotsPerEpoch, genesisTime)
require.NoError(t, err)
require.Equal(t, uint64(5), s.CurrentSlot())
require.Equal(t, spec.Slot(5), s.CurrentSlot())
}
func TestCurrentSlotPreGenesis(t *testing.T) {
@ -154,7 +155,7 @@ func TestCurrentSlotPreGenesis(t *testing.T) {
s, err := createMockService(slotDuration, slotsPerEpoch, genesisTime)
require.NoError(t, err)
require.Equal(t, uint64(0), s.CurrentSlot())
require.Equal(t, spec.Slot(0), s.CurrentSlot())
}
func TestCurrentEpoch(t *testing.T) {
@ -165,7 +166,7 @@ func TestCurrentEpoch(t *testing.T) {
s, err := createMockService(slotDuration, slotsPerEpoch, genesisTime)
require.NoError(t, err)
require.Equal(t, uint64(2), s.CurrentEpoch())
require.Equal(t, spec.Epoch(2), s.CurrentEpoch())
}
func TestCurrentEpochPreGenesis(t *testing.T) {
@ -176,14 +177,14 @@ func TestCurrentEpochPreGenesis(t *testing.T) {
s, err := createMockService(slotDuration, slotsPerEpoch, genesisTime)
require.NoError(t, err)
require.Equal(t, uint64(0), s.CurrentEpoch())
require.Equal(t, spec.Epoch(0), s.CurrentEpoch())
}
func TestSlotToEpoch(t *testing.T) {
tests := []struct {
name string
slot uint64
epoch uint64
slot spec.Slot
epoch spec.Epoch
}{
{
name: "ZeroFirstSlot",
@ -220,8 +221,8 @@ func TestSlotToEpoch(t *testing.T) {
func TestFirstSlotOfEpoch(t *testing.T) {
tests := []struct {
name string
epoch uint64
slot uint64
epoch spec.Epoch
slot spec.Slot
}{
{
name: "Zero",

View File

@ -18,6 +18,7 @@ import (
"fmt"
api "github.com/attestantio/go-eth2-client/api/v1"
spec "github.com/attestantio/go-eth2-client/spec/phase0"
"github.com/attestantio/vouch/services/accountmanager"
"github.com/attestantio/vouch/services/attestationaggregator"
"github.com/attestantio/vouch/services/attester"
@ -25,12 +26,12 @@ import (
// createAttesterJobs creates attestation jobs for the given epoch provided accounts.
func (s *Service) createAttesterJobs(ctx context.Context,
epoch uint64,
epoch spec.Epoch,
accounts []accountmanager.ValidatingAccount,
firstRun bool) {
log.Trace().Msg("Creating attester jobs")
validatorIDs := make([]uint64, len(accounts))
validatorIDs := make([]spec.ValidatorIndex, len(accounts))
var err error
for i, account := range accounts {
validatorIDs[i], err = account.Index(ctx)
@ -47,11 +48,11 @@ func (s *Service) createAttesterJobs(ctx context.Context,
// Filter bad responses.
filteredDuties := make([]*api.AttesterDuty, 0, len(resp))
firstSlot := epoch * s.slotsPerEpoch
lastSlot := (epoch+1)*s.slotsPerEpoch - 1
firstSlot := spec.Slot(uint64(epoch) * s.slotsPerEpoch)
lastSlot := spec.Slot((uint64(epoch)+1)*s.slotsPerEpoch - 1)
for _, duty := range resp {
if duty.Slot < firstSlot || duty.Slot > lastSlot {
log.Warn().Uint64("epoch", epoch).Uint64("duty_slot", duty.Slot).Msg("Attester duty has invalid slot for requested epoch; ignoring")
log.Warn().Uint64("epoch", uint64(epoch)).Uint64("duty_slot", uint64(duty.Slot)).Msg("Attester duty has invalid slot for requested epoch; ignoring")
continue
}
filteredDuties = append(filteredDuties, duty)
@ -63,24 +64,24 @@ func (s *Service) createAttesterJobs(ctx context.Context,
return
}
for _, duty := range duties {
log.
Trace().
Uint64("slot", duty.Slot()).
Uints64("committee_indices", duty.CommitteeIndices()).
Uints64("validator_indices", duty.ValidatorCommitteeIndices()).
Msg("Received attester duty")
if e := log.Trace(); e.Enabled() {
for _, duty := range duties {
log.Trace().
Uint64("slot", uint64(duty.Slot())).
Strs("duties", duty.Tuples()).
Msg("Received attester duties")
}
}
currentSlot := s.chainTimeService.CurrentSlot()
for _, duty := range duties {
// Do not schedule attestations for past slots (or the current slot if we've just started).
if duty.Slot() < currentSlot {
log.Debug().Uint64("attestation_slot", duty.Slot()).Uint64("current_slot", currentSlot).Msg("Attestation in the past; not scheduling")
log.Debug().Uint64("attestation_slot", uint64(duty.Slot())).Uint64("current_slot", uint64(currentSlot)).Msg("Attestation for a past slot; not scheduling")
continue
}
if firstRun && duty.Slot() == currentSlot {
log.Debug().Uint64("attestation_slot", duty.Slot()).Uint64("current_slot", currentSlot).Msg("Attestation in the current slot and this is our first run; not scheduling")
log.Debug().Uint64("attestation_slot", uint64(duty.Slot())).Uint64("current_slot", uint64(currentSlot)).Msg("Attestation for the current slot and this is our first run; not scheduling")
continue
}
if err := s.scheduler.ScheduleJob(ctx,
@ -114,29 +115,30 @@ func (s *Service) AttestAndScheduleAggregate(ctx context.Context, data interface
return
}
epoch := attestations[0].Data.Slot / s.slotsPerEpoch
epoch := s.chainTimeService.SlotToEpoch(attestations[0].Data.Slot)
s.subscriptionInfosMutex.Lock()
subscriptionInfoMap, exists := s.subscriptionInfos[epoch]
s.subscriptionInfosMutex.Unlock()
if !exists {
log.Warn().Msg("No subscription info for this epoch; cannot aggregate")
log.Debug().Uint64("epoch", uint64(epoch)).Msg("No subscription info for this epoch; not aggregating")
return
}
for _, attestation := range attestations {
log := log.With().Uint64("attestation_slot", uint64(attestation.Data.Slot)).Logger()
slotInfoMap, exists := subscriptionInfoMap[attestation.Data.Slot]
if !exists {
log.Debug().Uint64("attestation_slot", attestation.Data.Slot).Msg("No slot info; cannot aggregate")
log.Debug().Msg("No slot info; not aggregating")
continue
}
// Do not schedule aggregations for past slots.
if attestation.Data.Slot < s.chainTimeService.CurrentSlot() {
log.Debug().Uint64("aggregation_slot", attestation.Data.Slot).Uint64("current_slot", s.chainTimeService.CurrentSlot()).Msg("Aggregation in the past; not scheduling")
log.Debug().Uint64("current_slot", uint64(s.chainTimeService.CurrentSlot())).Msg("Aggregation in the past; not scheduling")
continue
}
info, exists := slotInfoMap[attestation.Data.Index]
if !exists {
log.Debug().Uint64("attestation_slot", attestation.Data.Slot).Uint64("committee_index", attestation.Data.Index).Msg("No committee info; cannot aggregate")
log.Debug().Uint64("committee_index", uint64(attestation.Data.Index)).Msg("No committee info; not aggregating")
continue
}
if info.IsAggregator {
@ -148,7 +150,7 @@ func (s *Service) AttestAndScheduleAggregate(ctx context.Context, data interface
}
aggregatorDuty := &attestationaggregator.Duty{
Slot: info.Duty.Slot,
AttestationDataRoot: attestationDataRoot[:],
AttestationDataRoot: attestationDataRoot,
ValidatorIndex: info.Duty.ValidatorIndex,
SlotSignature: info.Signature,
}

View File

@ -25,20 +25,25 @@ import (
func (s *Service) HandleHeadEvent(event *api.Event) {
ctx := context.Background()
data := event.Data.(*api.HeadEvent)
log.Trace().Uint64("slot", data.Slot).Msg("Received head event")
log.Trace().Uint64("slot", uint64(data.Slot)).Msg("Received head event")
if data.Slot != s.chainTimeService.CurrentSlot() {
return
}
s.monitor.BlockDelay(time.Since(s.chainTimeService.StartOfSlot(data.Slot)))
// Kick off attestations for the block's slot immediately.
jobName := fmt.Sprintf("Beacon block attestations for slot %d", data.Slot)
if s.scheduler.JobExists(ctx, jobName) {
log.Trace().Uint64("slot", data.Slot).Msg("Kicking off attestations for slot early due to receiving relevant block")
log.Trace().Uint64("slot", uint64(data.Slot)).Msg("Kicking off attestations for slot early due to receiving relevant block")
if err := s.scheduler.RunJobIfExists(ctx, jobName); err != nil {
log.Error().Str("job", jobName).Err(err).Msg("Failed to run attester job")
}
}
// If the head is in a new fork it may result in different attester duties.
// TODO
// Remove old subscriptions if present.
delete(s.subscriptionInfos, s.chainTimeService.SlotToEpoch(data.Slot)-2)
}

View File

@ -17,18 +17,19 @@ import (
"context"
"fmt"
spec "github.com/attestantio/go-eth2-client/spec/phase0"
"github.com/attestantio/vouch/services/accountmanager"
"github.com/attestantio/vouch/services/beaconblockproposer"
)
// createProposerJobs creates proposal jobs for the given epoch.
func (s *Service) createProposerJobs(ctx context.Context,
epoch uint64,
epoch spec.Epoch,
accounts []accountmanager.ValidatingAccount,
firstRun bool) {
log.Trace().Msg("Creating proposer jobs")
validatorIDs := make([]uint64, len(accounts))
validatorIDs := make([]spec.ValidatorIndex, len(accounts))
var err error
for i, account := range accounts {
validatorIDs[i], err = account.Index(ctx)
@ -46,11 +47,11 @@ func (s *Service) createProposerJobs(ctx context.Context,
// Filter bad responses.
duties := make([]*beaconblockproposer.Duty, 0, len(resp))
firstSlot := epoch * s.slotsPerEpoch
lastSlot := (epoch+1)*s.slotsPerEpoch - 1
firstSlot := s.chainTimeService.FirstSlotOfEpoch(epoch)
lastSlot := s.chainTimeService.FirstSlotOfEpoch(epoch+1) - 1
for _, respDuty := range resp {
if respDuty.Slot < firstSlot || respDuty.Slot > lastSlot {
log.Warn().Uint64("epoch", epoch).Uint64("duty_slot", respDuty.Slot).Msg("Proposer duty has invalid slot for requested epoch; ignoring")
log.Warn().Uint64("epoch", uint64(epoch)).Uint64("duty_slot", uint64(respDuty.Slot)).Msg("Proposer duty has invalid slot for requested epoch; ignoring")
continue
}
duty, err := beaconblockproposer.NewDuty(ctx, respDuty.Slot, respDuty.ValidatorIndex)
@ -65,12 +66,12 @@ func (s *Service) createProposerJobs(ctx context.Context,
for _, duty := range duties {
// Do not schedule proposals for past slots (or the current slot if we've just started).
if duty.Slot() < currentSlot || firstRun && duty.Slot() == currentSlot {
log.Debug().Uint64("proposal_slot", duty.Slot()).Uint64("current_slot", currentSlot).Msg("Proposal in the past; not scheduling")
log.Debug().Uint64("proposal_slot", uint64(duty.Slot())).Uint64("current_slot", uint64(currentSlot)).Msg("Proposal in the past; not scheduling")
continue
}
go func(duty *beaconblockproposer.Duty) {
if err := s.beaconBlockProposer.Prepare(ctx, duty); err != nil {
log.Error().Uint64("proposal_slot", duty.Slot()).Err(err).Msg("Failed to prepare proposal")
log.Error().Uint64("proposal_slot", uint64(duty.Slot())).Err(err).Msg("Failed to prepare proposal")
return
}
if err := s.scheduler.ScheduleJob(ctx,

View File

@ -20,6 +20,7 @@ import (
"time"
eth2client "github.com/attestantio/go-eth2-client"
spec "github.com/attestantio/go-eth2-client/spec/phase0"
"github.com/attestantio/vouch/services/accountmanager"
"github.com/attestantio/vouch/services/attestationaggregator"
"github.com/attestantio/vouch/services/attester"
@ -50,9 +51,8 @@ type Service struct {
attestationAggregator attestationaggregator.Service
beaconCommitteeSubscriber beaconcommitteesubscriber.Service
activeAccounts int
// Epoch => slot => committee => subscription info cache.
subscriptionInfos map[uint64]map[uint64]map[uint64]*beaconcommitteesubscriber.Subscription
subscriptionInfosMutex sync.Mutex
subscriptionInfos map[spec.Epoch]map[spec.Slot]map[spec.CommitteeIndex]*beaconcommitteesubscriber.Subscription
subscriptionInfosMutex sync.Mutex
}
// module-wide log.
@ -94,16 +94,15 @@ func New(ctx context.Context, params ...Parameter) (*Service, error) {
beaconBlockProposer: parameters.beaconBlockProposer,
attestationAggregator: parameters.attestationAggregator,
beaconCommitteeSubscriber: parameters.beaconCommitteeSubscriber,
subscriptionInfos: make(map[uint64]map[uint64]map[uint64]*beaconcommitteesubscriber.Subscription),
subscriptionInfos: make(map[spec.Epoch]map[spec.Slot]map[spec.CommitteeIndex]*beaconcommitteesubscriber.Subscription),
}
// Subscribe to head events.
// Subscribe to head events. This allows us to go early for attestations if a block arrives, as well as
// re-request duties if there is a change in beacon block.
if err := parameters.eventsProvider.Events(ctx, []string{"head"}, s.HandleHeadEvent); err != nil {
return nil, errors.Wrap(err, "failed to add head event handler")
}
// TODO subscribe to reorg events.
// Subscriptions are usually updated one epoch in advance, but as we're
// just starting we don't have subscriptions (or subscription information)
// for this or the next epoch; fetch them now.
@ -208,10 +207,10 @@ func (s *Service) epochTicker(ctx context.Context, data interface{}) {
epochTickerData := data.(*epochTickerData)
currentEpoch := s.chainTimeService.CurrentEpoch()
firstRun := epochTickerData.latestEpochRan == -1
log.Trace().Uint64("epoch", currentEpoch).Bool("first_run", firstRun).Msg("Starting per-epoch duties")
log.Trace().Uint64("epoch", uint64(currentEpoch)).Bool("first_run", firstRun).Msg("Starting per-epoch duties")
epochTickerData.mutex.Lock()
if epochTickerData.latestEpochRan >= int64(currentEpoch) {
log.Trace().Uint64("epoch", currentEpoch).Msg("Already ran for this epoch; skipping")
log.Trace().Uint64("epoch", uint64(currentEpoch)).Msg("Already ran for this epoch; skipping")
epochTickerData.mutex.Unlock()
return
}
@ -265,7 +264,6 @@ func (s *Service) epochTicker(ctx context.Context, data interface{}) {
epochTickerData.atGenesis = false
}
// TODO REMOVE
// // OnBeaconChainHeadUpdated runs attestations for a slot immediately, if the update is for the current slot.
// func (s *Service) OnBeaconChainHeadUpdated(ctx context.Context, slot uint64, stateRoot []byte, bodyRoot []byte, epochTransitioni bool) {
// if slot != s.chainTimeService.CurrentSlot() {

View File

@ -20,6 +20,7 @@ import (
"strings"
"time"
spec "github.com/attestantio/go-eth2-client/spec/phase0"
"github.com/pkg/errors"
"github.com/rs/zerolog"
zerologger "github.com/rs/zerolog/log"
@ -60,7 +61,7 @@ func New(ctx context.Context, params ...Parameter) (*Service, error) {
}
// Graffiti provides graffiti.
func (s *Service) Graffiti(ctx context.Context, slot uint64, validatorIndex uint64) ([]byte, error) {
func (s *Service) Graffiti(ctx context.Context, slot spec.Slot, validatorIndex spec.ValidatorIndex) ([]byte, error) {
// Replace location parameters with values.
location := strings.ReplaceAll(s.location, "{{SLOT}}", fmt.Sprintf("%d", slot))
location = strings.ReplaceAll(location, "{{VALIDATORINDEX}}", fmt.Sprintf("%d", validatorIndex))

View File

@ -21,6 +21,7 @@ import (
"path/filepath"
"testing"
spec "github.com/attestantio/go-eth2-client/spec/phase0"
"github.com/attestantio/vouch/services/graffitiprovider/dynamic"
"github.com/rs/zerolog"
"github.com/stretchr/testify/require"
@ -182,7 +183,7 @@ func TestReplacement(t *testing.T) {
require.NoError(t, err)
for validatorIndex := uint64(0); validatorIndex < 16; validatorIndex++ {
for slot := uint64(0); slot < 16; slot++ {
graffiti, err := svc.Graffiti(ctx, slot, validatorIndex)
graffiti, err := svc.Graffiti(ctx, spec.Slot(slot), spec.ValidatorIndex(validatorIndex))
require.NoError(t, err)
delete(expectedGraffitis, string(graffiti))
}
@ -298,7 +299,7 @@ func TestMultiline(t *testing.T) {
require.NoError(t, err)
for validatorIndex := uint64(0); validatorIndex < 16; validatorIndex++ {
for slot := uint64(0); slot < 16; slot++ {
graffiti, err := svc.Graffiti(ctx, slot, validatorIndex)
graffiti, err := svc.Graffiti(ctx, spec.Slot(slot), spec.ValidatorIndex(validatorIndex))
require.NoError(t, err)
require.Contains(t, test.expectedGraffitis, string(graffiti))
delete(obtainedGraffitis, string(graffiti))

View File

@ -16,10 +16,12 @@ package graffitiprovider
import (
"context"
spec "github.com/attestantio/go-eth2-client/spec/phase0"
)
// Service is the graffiti provider service.
type Service interface {
// Graffiti returns the graffiti for a given slot and validator.
Graffiti(ctx context.Context, slot uint64, validatorIndex uint64) ([]byte, error)
Graffiti(ctx context.Context, slot spec.Slot, validatorIndex spec.ValidatorIndex) ([]byte, error)
}

View File

@ -16,6 +16,7 @@ package static
import (
"context"
spec "github.com/attestantio/go-eth2-client/spec/phase0"
"github.com/pkg/errors"
"github.com/rs/zerolog"
zerologger "github.com/rs/zerolog/log"
@ -50,6 +51,6 @@ func New(ctx context.Context, params ...Parameter) (*Service, error) {
}
// Graffiti provides graffiti.
func (s *Service) Graffiti(ctx context.Context, slot uint64, validatorIndex uint64) ([]byte, error) {
func (s *Service) Graffiti(ctx context.Context, slot spec.Slot, validatorIndex spec.ValidatorIndex) ([]byte, error) {
return s.graffiti, nil
}

View File

@ -42,7 +42,7 @@ func (s *Service) SubmitAggregateAttestations(ctx context.Context, aggregates []
submitter eth2client.AggregateAttestationsSubmitter,
) {
defer wg.Done()
log := log.With().Str("beacon_node_address", name).Uint64("slot", aggregates[0].Message.Aggregate.Data.Slot).Logger()
log := log.With().Str("beacon_node_address", name).Uint64("slot", uint64(aggregates[0].Message.Aggregate.Data.Slot)).Logger()
if err := sem.Acquire(ctx, 1); err != nil {
log.Error().Err(err).Msg("Failed to acquire semaphore")
return

View File

@ -43,7 +43,7 @@ func (s *Service) SubmitAttestation(ctx context.Context, attestation *spec.Attes
submitter eth2client.AttestationSubmitter,
) {
defer wg.Done()
log := log.With().Str("beacon_node_address", name).Uint64("slot", attestation.Data.Slot).Logger()
log := log.With().Str("beacon_node_address", name).Uint64("slot", uint64(attestation.Data.Slot)).Logger()
if err := sem.Acquire(ctx, 1); err != nil {
log.Error().Err(err).Msg("Failed to acquire semaphore")
return

View File

@ -42,7 +42,7 @@ func (s *Service) SubmitBeaconBlock(ctx context.Context, block *spec.SignedBeaco
submitter eth2client.BeaconBlockSubmitter,
) {
defer wg.Done()
log := log.With().Str("beacon_node_address", name).Uint64("slot", block.Message.Slot).Logger()
log := log.With().Str("beacon_node_address", name).Uint64("slot", uint64(block.Message.Slot)).Logger()
if err := sem.Acquire(ctx, 1); err != nil {
log.Error().Err(err).Msg("Failed to acquire semaphore")
return

View File

@ -23,12 +23,13 @@ import (
"golang.org/x/sync/semaphore"
)
// BeaconBlockProposal provies the best beacon block proposal from a number of beacon nodes.
func (s *Service) BeaconBlockProposal(ctx context.Context, slot uint64, randaoReveal []byte, graffiti []byte) (*spec.BeaconBlock, error) {
// BeaconBlockProposal provides the best beacon block proposal from a number of beacon nodes.
func (s *Service) BeaconBlockProposal(ctx context.Context, slot spec.Slot, randaoReveal spec.BLSSignature, graffiti []byte) (*spec.BeaconBlock, error) {
var mu sync.Mutex
bestScore := float64(0)
var bestProposal *spec.BeaconBlock
started := time.Now()
sem := semaphore.NewWeighted(s.processConcurrency)
var wg sync.WaitGroup
for name, provider := range s.beaconBlockProposalProviders {
@ -41,10 +42,10 @@ func (s *Service) BeaconBlockProposal(ctx context.Context, slot uint64, randaoRe
return
}
defer sem.Release(1)
log := log.With().Str("provider", name).Uint64("slot", slot).Logger()
log := log.With().Str("provider", name).Uint64("slot", uint64(slot)).Logger()
log.Trace().Dur("elapsed", time.Since(started)).Msg("Obtained semaphore")
opCtx, cancel := context.WithTimeout(ctx, s.timeout)
started := time.Now()
proposal, err := provider.BeaconBlockProposal(opCtx, slot, randaoReveal, graffiti)
s.clientMonitor.ClientOperation(name, "beacon block proposal", err == nil, time.Since(started))
if err != nil {

View File

@ -18,6 +18,7 @@ import (
"testing"
eth2client "github.com/attestantio/go-eth2-client"
spec "github.com/attestantio/go-eth2-client/spec/phase0"
"github.com/attestantio/vouch/mock"
"github.com/attestantio/vouch/services/metrics/null"
"github.com/attestantio/vouch/strategies/beaconblockproposal/best"
@ -42,10 +43,14 @@ func TestBeaconBlockProposal(t *testing.T) {
block, err := service.BeaconBlockProposal(ctx,
12345,
[]byte{
spec.BLSSignature([96]byte{
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
},
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
}),
nil,
)
require.NoError(t, err)

View File

@ -35,11 +35,11 @@ func scoreBeaconBlockProposal(ctx context.Context, name string, blockProposal *s
// We need to avoid duplicates in attestations.
// Map is slot -> committee index -> validator committee index -> attested.
attested := make(map[uint64]map[uint64]map[uint64]bool)
attested := make(map[spec.Slot]map[spec.CommitteeIndex]map[uint64]bool)
for _, attestation := range blockProposal.Body.Attestations {
slotAttested, exists := attested[attestation.Data.Slot]
if !exists {
slotAttested = make(map[uint64]map[uint64]bool)
slotAttested = make(map[spec.CommitteeIndex]map[uint64]bool)
attested[attestation.Data.Slot] = slotAttested
}
committeeAttested, exists := slotAttested[attestation.Data.Index]
@ -84,7 +84,7 @@ func scoreBeaconBlockProposal(ctx context.Context, name string, blockProposal *s
attesterSlashingScore := slashingWeight * float64(indicesSlashed)
log.Trace().
Uint64("slot", blockProposal.Slot).
Uint64("slot", uint64(blockProposal.Slot)).
Str("provider", name).
Float64("immediate_attestations", immediateAttestationScore).
Float64("attestations", attestationScore).

View File

@ -1,5 +1,5 @@
// Copyright © 2020 Attestant Limited.
// Licensed under the Apache License, Version 2.0 (the "License");
// Licensed )junder the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
@ -58,7 +58,7 @@ func New(ctx context.Context, params ...Parameter) (*Service, error) {
}
// BeaconBlockProposal provies the best beacon block proposal from a number of beacon nodes.
func (s *Service) BeaconBlockProposal(ctx context.Context, slot uint64, randaoReveal []byte, graffiti []byte) (*spec.BeaconBlock, error) {
func (s *Service) BeaconBlockProposal(ctx context.Context, slot spec.Slot, randaoReveal spec.BLSSignature, graffiti []byte) (*spec.BeaconBlock, error) {
// We create a cancelable context with a timeout. As soon as the first provider has responded we
// cancel the context to cancel the other requests.
ctx, cancel := context.WithTimeout(ctx, s.timeout)
@ -66,7 +66,7 @@ func (s *Service) BeaconBlockProposal(ctx context.Context, slot uint64, randaoRe
proposalCh := make(chan *spec.BeaconBlock, 1)
for name, provider := range s.beaconBlockProposalProviders {
go func(ctx context.Context, name string, provider eth2client.BeaconBlockProposalProvider, ch chan *spec.BeaconBlock) {
log := log.With().Str("provider", name).Uint64("slot", slot).Logger()
log := log.With().Str("provider", name).Uint64("slot", uint64(slot)).Logger()
started := time.Now()
proposal, err := provider.BeaconBlockProposal(ctx, slot, randaoReveal, graffiti)

85
testutil/bytes.go Normal file
View File

@ -0,0 +1,85 @@
// Copyright © 2020 Attestant Limited
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package testutil
import (
"encoding/hex"
"strings"
spec "github.com/attestantio/go-eth2-client/spec/phase0"
)
// HexToBytes converts a hex string to a byte array.
// This should only be used for pre-defined test strings; it will panic if the input is invalid.
func HexToBytes(input string) []byte {
res, err := hex.DecodeString(strings.TrimPrefix(input, "0x"))
if err != nil {
panic(err)
}
return res
}
// HexToPubKey converts a hex string to a spec public key.
// This should only be used for pre-defined test strings; it will panic if the input is invalid.
func HexToPubKey(input string) spec.BLSPubKey {
data := HexToBytes(input)
var res spec.BLSPubKey
copy(res[:], data)
return res
}
// HexToSignature converts a hex string to a spec signature.
// This should only be used for pre-defined test strings; it will panic if the input is invalid.
func HexToSignature(input string) spec.BLSSignature {
data := HexToBytes(input)
var res spec.BLSSignature
copy(res[:], data)
return res
}
// HexToDomainType converts a hex string to a spec domain type.
// This should only be used for pre-defined test strings; it will panic if the input is invalid.
func HexToDomainType(input string) spec.DomainType {
data := HexToBytes(input)
var res spec.DomainType
copy(res[:], data)
return res
}
// HexToDomain converts a hex string to a spec domain.
// This should only be used for pre-defined test strings; it will panic if the input is invalid.
func HexToDomain(input string) spec.Domain {
data := HexToBytes(input)
var res spec.Domain
copy(res[:], data)
return res
}
// HexToVersion converts a hex string to a spec version.
// This should only be used for pre-defined test strings; it will panic if the input is invalid.
func HexToVersion(input string) spec.Version {
data := HexToBytes(input)
var res spec.Version
copy(res[:], data)
return res
}
// HexToRoot converts a hex string to a spec root.
// This should only be used for pre-defined test strings; it will panic if the input is invalid.
func HexToRoot(input string) spec.Root {
data := HexToBytes(input)
var res spec.Root
copy(res[:], data)
return res
}