diff --git a/deps.bzl b/deps.bzl index 75131341171b..36543241f446 100644 --- a/deps.bzl +++ b/deps.bzl @@ -332,8 +332,8 @@ def prysm_deps(): go_repository( name = "com_github_coreos_go_systemd", importpath = "github.com/coreos/go-systemd", - sum = "h1:t5Wuyh53qYyg9eqn4BbnlIT+vmhyww0TatL+zT3uWgI=", - version = "v0.0.0-20181012123002-c6f51f82210d", + sum = "h1:iW4rZ826su+pqaw19uhpSCzhj44qo35pNgKFGqzDKkU=", + version = "v0.0.0-20191104093116-d3cd4ed1dbcf", ) go_repository( name = "com_github_cpuguy83_go_md2man", @@ -590,8 +590,8 @@ def prysm_deps(): go_repository( name = "com_github_go_sql_driver_mysql", importpath = "github.com/go-sql-driver/mysql", - sum = "h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=", - version = "v1.5.0", + sum = "h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA=", + version = "v1.4.1", ) go_repository( name = "com_github_golang_protobuf", @@ -784,8 +784,8 @@ def prysm_deps(): go_repository( name = "com_github_jmespath_go_jmespath", importpath = "github.com/jmespath/go-jmespath", - sum = "h1:OS12ieG61fsCg5+qLJ+SsW9NicxNkg3b25OyT2yCeUc=", - version = "v0.3.0", + sum = "h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM=", + version = "v0.0.0-20180206201540-c2b33e8439af", ) go_repository( name = "com_github_jrick_logrotate", @@ -868,8 +868,8 @@ def prysm_deps(): go_repository( name = "com_github_kr_pty", importpath = "github.com/kr/pty", - sum = "h1:/Um6a/ZmD5tF7peoOJ5oN5KMQ0DrGVQSXLNwyckutPk=", - version = "v1.1.3", + sum = "h1:VkoXIwSboBpnk99O/KFauAEILuNHv5DVFKZMBN/gUgw=", + version = "v1.1.1", ) go_repository( name = "com_github_kr_text", @@ -980,8 +980,8 @@ def prysm_deps(): go_repository( name = "com_github_mailru_easyjson", importpath = "github.com/mailru/easyjson", - sum = "h1:W/GaMY0y69G4cFlmsC6B9sbuo2fP8OFP1ABjt4kPz+w=", - version = "v0.0.0-20190312143242-1de009706dbe", + sum = "h1:2gxZ0XQIU/5z3Z3bUBu+FXuk2pFbkN6tcwi/pjyaDic=", + version = "v0.0.0-20180823135443-60711f1a8329", ) go_repository( name = "com_github_marten_seemann_qpack", @@ -1916,8 +1916,8 @@ def prysm_deps(): go_repository( name = "com_github_aws_aws_sdk_go", importpath = "github.com/aws/aws-sdk-go", - sum = "h1:JiYid0lBDcM12HNOND5EcaBd1namBuB5BJ4Iex0DFMw=", - version = "v1.33.15", + sum = "h1:J82DYDGZHOKHdhx6hD24Tm30c2C3GchYGfN0mf9iKUk=", + version = "v1.25.48", ) go_repository( name = "com_github_beorn7_perks", @@ -1976,8 +1976,8 @@ def prysm_deps(): go_repository( name = "com_github_golang_lint", importpath = "github.com/golang/lint", - sum = "h1:2hRPrmiwPrp3fQX967rNJIhQPtiGXdlQWAxKbKw3VHA=", - version = "v0.0.0-20180702182130-06c8688daad7", + sum = "h1:ior8LN6127GsA53E9mD9nH/oP/LVbJplmLH5V8o+/Uk=", + version = "v0.0.0-20170918230701-e5d664eb928e", ) go_repository( name = "com_github_golang_snappy", diff --git a/go.mod b/go.mod index 414d43847516..6fc8380143d7 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,6 @@ require ( contrib.go.opencensus.io/exporter/jaeger v0.2.0 github.com/allegro/bigcache v1.2.1 // indirect github.com/aristanetworks/goarista v0.0.0-20200521140103-6c3304613b30 - github.com/aws/aws-sdk-go v1.33.15 // indirect github.com/bazelbuild/buildtools v0.0.0-20200528175155-f4e8394f069d github.com/bazelbuild/rules_go v0.23.2 github.com/cespare/cp v1.1.1 // indirect @@ -99,14 +98,9 @@ require ( github.com/supranational/blst v0.1.2-alpha.1.0.20200917144033-cd0847a7580b github.com/tyler-smith/go-bip39 v1.0.2 github.com/urfave/cli/v2 v2.2.0 - github.com/wealdtech/eth2-signer-api v1.3.0 github.com/wealdtech/go-bytesutil v1.1.1 github.com/wealdtech/go-eth2-util v1.5.0 - github.com/wealdtech/go-eth2-wallet v1.12.0 github.com/wealdtech/go-eth2-wallet-encryptor-keystorev4 v1.1.0 - github.com/wealdtech/go-eth2-wallet-nd/v2 v2.3.0 - github.com/wealdtech/go-eth2-wallet-store-filesystem v1.16.1 - github.com/wealdtech/go-eth2-wallet-types/v2 v2.6.0 github.com/wercker/journalhook v0.0.0-20180428041537-5d0a5ae867b3 github.com/x-cray/logrus-prefixed-formatter v0.5.2 go.etcd.io/bbolt v1.3.4 diff --git a/go.sum b/go.sum index 6078a2d2e9a2..368a5074258b 100644 --- a/go.sum +++ b/go.sum @@ -73,10 +73,6 @@ github.com/aristanetworks/goarista v0.0.0-20200521140103-6c3304613b30/go.mod h1: github.com/aristanetworks/splunk-hec-go v0.3.3/go.mod h1:1VHO9r17b0K7WmOlLb9nTk/2YanvOEnLMUgsFrxBROc= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/aws/aws-sdk-go v1.25.48/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= -github.com/aws/aws-sdk-go v1.33.5 h1:p2fr1ryvNTU6avUWLI+/H7FGv0TBIjzVM5WDgXBBv4U= -github.com/aws/aws-sdk-go v1.33.5/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0= -github.com/aws/aws-sdk-go v1.33.15 h1:JiYid0lBDcM12HNOND5EcaBd1namBuB5BJ4Iex0DFMw= -github.com/aws/aws-sdk-go v1.33.15/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0= github.com/bazelbuild/buildtools v0.0.0-20200528175155-f4e8394f069d h1:lXjj6ngxx9PVxg6TtlMCbkPATwLFf5dcl9z5Jr3WqGg= github.com/bazelbuild/buildtools v0.0.0-20200528175155-f4e8394f069d/go.mod h1:5JP0TXzWDHXv8qvxRC4InIazwdyDseBDbzESUMKk1yU= github.com/bazelbuild/rules_go v0.23.2 h1:Wxu7JjqnF78cKZbsBsARLSXx/jlGaSLCnUV3mTlyHvM= @@ -246,7 +242,6 @@ github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dp github.com/go-sourcemap/sourcemap v2.1.2+incompatible h1:0b/xya7BKGhXuqFESKM4oIiRo9WOt2ebz7KxfreD6ug= github.com/go-sourcemap/sourcemap v2.1.2+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg= github.com/go-sql-driver/mysql v1.4.1/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.6.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= @@ -284,7 +279,6 @@ github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaW github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= -github.com/golang/protobuf v1.4.0-rc.4/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= @@ -448,8 +442,6 @@ github.com/jcmturner/gofork v1.0.0/go.mod h1:MK8+TM0La+2rjBD4jE12Kj1pCCxK7d2LK/U github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= -github.com/jmespath/go-jmespath v0.3.0 h1:OS12ieG61fsCg5+qLJ+SsW9NicxNkg3b25OyT2yCeUc= -github.com/jmespath/go-jmespath v0.3.0/go.mod h1:9QtRXoHjLGCJ5IBSaohpXITPlowMeeYCZ7fLUTSywik= github.com/joonix/log v0.0.0-20200409080653-9c1d2ceb5f1d h1:k+SfYbN66Ev/GDVq39wYOXVW5RNd5kzzairbCe9dK5Q= github.com/joonix/log v0.0.0-20200409080653-9c1d2ceb5f1d/go.mod h1:fS54ONkjDV71zS9CDx3V9K21gJg7byKSvI4ajuWFNJw= github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= @@ -947,8 +939,6 @@ github.com/schollz/progressbar/v3 v3.3.4/go.mod h1:Rp5lZwpgtYmlvmGo1FyDwXMqagyRB github.com/segmentio/kafka-go v0.1.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfPOCvTvk+EJo= github.com/segmentio/kafka-go v0.2.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfPOCvTvk+EJo= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= -github.com/shibukawa/configdir v0.0.0-20170330084843-e180dbdc8da0 h1:Xuk8ma/ibJ1fOy4Ee11vHhUFHQNpHhrBneOCNHVXS5w= -github.com/shibukawa/configdir v0.0.0-20170330084843-e180dbdc8da0/go.mod h1:7AwjWCpdPhkSmNAgUv5C7EJ4AbmjEB3r047r3DXWu3Y= github.com/shirou/gopsutil v2.20.5+incompatible h1:tYH07UPoQt0OCQdgWWMgYHy3/a9bcxNpBIysykNIP7I= github.com/shirou/gopsutil v2.20.5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= @@ -1020,38 +1010,14 @@ github.com/urfave/cli v1.22.1 h1:+mkCCcOFKPnCmVYVcURKps1Xe+3zP90gSYGNfRkjoIY= github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli/v2 v2.2.0 h1:JTTnM6wKzdA0Jqodd966MVj4vWbbquZykeX1sKbe2C4= github.com/urfave/cli/v2 v2.2.0/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ= -github.com/wealdtech/eth2-signer-api v1.3.0 h1:Fs0GfrdhboBKW7zaMvIvUHJaOB1ibpAmRG3lkB53in4= -github.com/wealdtech/eth2-signer-api v1.3.0/go.mod h1:H8OpAoTBl6CaBvZEnhxWDjjWXNc3kwVFKWMAZd6sHlk= -github.com/wealdtech/go-bytesutil v1.0.1/go.mod h1:jENeMqeTEU8FNZyDFRVc7KqBdRKSnJ9CCh26TcuNb9s= github.com/wealdtech/go-bytesutil v1.1.1 h1:ocEg3Ke2GkZ4vQw5lp46rmO+pfqCCTgq35gqOy8JKVc= github.com/wealdtech/go-bytesutil v1.1.1/go.mod h1:jENeMqeTEU8FNZyDFRVc7KqBdRKSnJ9CCh26TcuNb9s= -github.com/wealdtech/go-ecodec v1.1.0 h1:yggrTSckcPJRaxxOxQF7FPm21kgE8WA6+f5jdq5Kr8o= -github.com/wealdtech/go-ecodec v1.1.0/go.mod h1:PSdBFEB6cltdT7V4E1jbboufMZTZXcQOKG/2PeEjKK4= github.com/wealdtech/go-eth2-types/v2 v2.5.0 h1:L8sl3yoICAbn3134CBLNUt0o5h2voe0Es2KD5O9r8YQ= github.com/wealdtech/go-eth2-types/v2 v2.5.0/go.mod h1:321w9X26lAnNa/lQJi2A6Lap5IsNORoLwFPoJ1i8QvY= github.com/wealdtech/go-eth2-util v1.5.0 h1:b3fgyvoq/WocW9LkWT7zcO5VCKzKLCc97rPrk/B9oIc= github.com/wealdtech/go-eth2-util v1.5.0/go.mod h1:0PGWeWWc6qjky/aNjdPdguJdZ2HSEHHCA+3cTjvT+Hk= -github.com/wealdtech/go-eth2-wallet v1.12.0 h1:nrwI3jPhehUhJGlBtNv/UmIo/57llvuVZZavLnfdQHI= -github.com/wealdtech/go-eth2-wallet v1.12.0/go.mod h1:ouV+YSMbzk2dyecmofm8jhaMKdSigdIPMSnSqmWEfW8= -github.com/wealdtech/go-eth2-wallet-distributed v1.1.0 h1:OZjjuxcIYo+EhAfph7lYP1z+VeNs9ruOI32kqtYe1Jg= -github.com/wealdtech/go-eth2-wallet-distributed v1.1.0/go.mod h1:8r06Vpg/315/7Hl9CXq0ShQP8/cgUrBGzKKo6ywA4yQ= github.com/wealdtech/go-eth2-wallet-encryptor-keystorev4 v1.1.0 h1:CWb82xeNaZQt1Z829RyDALUy7UZbc6VOfTS+82jRdEQ= github.com/wealdtech/go-eth2-wallet-encryptor-keystorev4 v1.1.0/go.mod h1:JelKMM10UzDJNXdIcojMj6SCIsHC8NYn4c1S2FFk7OQ= -github.com/wealdtech/go-eth2-wallet-hd/v2 v2.3.0 h1:UORXUYRoUYgYF96Y+QiBq33OKQVtn/nEjnSoQbe1UOA= -github.com/wealdtech/go-eth2-wallet-hd/v2 v2.3.0/go.mod h1:Kc/8WcqMTczfH2xy5mDfCRd0NI/ca/j2jXmqJ7gz8yk= -github.com/wealdtech/go-eth2-wallet-nd/v2 v2.3.0 h1:L1aPK9nc+8Ctcw+8I05vM6408weFc4a5RtLQDUeS0eE= -github.com/wealdtech/go-eth2-wallet-nd/v2 v2.3.0/go.mod h1:e2q2uuEdq5+B3GE7jk+Mi9oz9V5nPPKXcXRg1XYavsU= -github.com/wealdtech/go-eth2-wallet-store-filesystem v1.16.1 h1:l9YV6OBqcxp5fjscK63lzuCUIye8ANACjJdpm5ULGS8= -github.com/wealdtech/go-eth2-wallet-store-filesystem v1.16.1/go.mod h1:Zxhj/4i8nRpk4LTTqFKbfI2KyvO3uqLMerNXqKZKDK0= -github.com/wealdtech/go-eth2-wallet-store-s3 v1.8.0 h1:+q7p58NvOEfEDw8NgEoNaSG/s1eFHpyg91NEobA6RF0= -github.com/wealdtech/go-eth2-wallet-store-s3 v1.8.0/go.mod h1:OxYD+d79StAOHigNaI5bWuvjhanEyrD4MqTj8hIvt2Y= -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-types/v2 v2.5.0/go.mod h1:X9kYUH/E5YMqFMZ4xL6MJanABUkJGaH/yPZRT2o+yYA= -github.com/wealdtech/go-eth2-wallet-types/v2 v2.6.0 h1:vBrH5icPPSeb14cdShA7/P2PBZOgZscJ2IhBlTIaFrA= -github.com/wealdtech/go-eth2-wallet-types/v2 v2.6.0/go.mod h1:X9kYUH/E5YMqFMZ4xL6MJanABUkJGaH/yPZRT2o+yYA= -github.com/wealdtech/go-indexer v1.0.0 h1:/S4rfWQbSOnnYmwnvuTVatDibZ8o1s9bmTCHO16XINg= -github.com/wealdtech/go-indexer v1.0.0/go.mod h1:u1cjsbsOXsm5jzJDyLmZY7GsrdX8KYXKBXkZcAmk3Zg= github.com/wercker/journalhook v0.0.0-20180428041537-5d0a5ae867b3 h1:shC1HB1UogxN5Ech3Yqaaxj1X/P656PPCB4RbojIJqc= github.com/wercker/journalhook v0.0.0-20180428041537-5d0a5ae867b3/go.mod h1:XCsSkdKK4gwBMNrOCZWww0pX6AOt+2gYc5Z6jBRrNVg= github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1 h1:EKhdznlJHPMoKr0XTrX+IlJs1LH3lyx2nfr1dOlZ79k= @@ -1117,14 +1083,12 @@ golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190618222545-ea8f1a30c443/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20191105034135-c7e5f84aec59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20191219195013-becbf705a915/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200204104054-c9f3fb736b72/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200423211502-4bdfaf469ed5/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200602180216-279210d13fed/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899 h1:DZhuSZLsGlFL4CmhA8BcRA0mnthyA/nZ00AqCUo7vHg= golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= @@ -1375,7 +1339,6 @@ google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQ google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= google.golang.org/grpc v1.28.1/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= google.golang.org/grpc v1.29.1 h1:EC2SB8S04d2r73uptxphDSUG+kTKVgjRPF+N3xpxRB4= google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= @@ -1383,7 +1346,6 @@ google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLY 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= google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= -google.golang.org/protobuf v1.20.1/go.mod h1:KqelGeouBkcbcuB3HCk4/YH2tmNLk6YSWA5LIWeI/lY= google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= diff --git a/shared/featureconfig/config.go b/shared/featureconfig/config.go index 8201d266fee7..7fed1bd302f1 100644 --- a/shared/featureconfig/config.go +++ b/shared/featureconfig/config.go @@ -53,7 +53,6 @@ type Flags struct { DisableUpdateHeadPerAttestation bool // DisableUpdateHeadPerAttestation will disabling update head on per attestation basis. EnableNoise bool // EnableNoise enables the beacon node to use NOISE instead of SECIO when performing a handshake with another peer. WaitForSynced bool // WaitForSynced uses WaitForSynced in validator startup to ensure it can communicate with the beacon node as soon as possible. - EnableAccountsV2 bool // EnableAccountsV2 for Prysm validator clients. InitSyncVerbose bool // InitSyncVerbose logs every processed block during initial syncing. EnableFinalizedDepositsCache bool // EnableFinalizedDepositsCache enables utilization of cached finalized deposits. EnableEth1DataMajorityVote bool // EnableEth1DataMajorityVote uses the Voting With The Majority algorithm to vote for eth1data. @@ -259,16 +258,6 @@ func ConfigureValidator(ctx *cli.Context) { } else { log.Warn("Validator slashing protection not enabled!") } - cfg.EnableAccountsV2 = true - if ctx.Bool(disableAccountsV2.Name) { - log.Warn("Disabling v2 of Prysm validator accounts") - log.Error( - "Accounts v1 will be fully deprecated in Prysm within the next 2 releases! If you are still " + - "using this functionality, please begin to upgrade by creating a v2 wallet. More information can be " + - "found in our docs portal https://docs.prylabs.network/docs/wallet/introduction/", - ) - cfg.EnableAccountsV2 = false - } if ctx.Bool(enableExternalSlasherProtectionFlag.Name) { log.Warn("Enabled validator attestation and block slashing protection using an external slasher.") cfg.SlasherProtection = true diff --git a/validator/BUILD.bazel b/validator/BUILD.bazel index e2c6a9f722ee..dc62c0e0502c 100644 --- a/validator/BUILD.bazel +++ b/validator/BUILD.bazel @@ -20,19 +20,14 @@ go_library( "//shared/journald:go_default_library", "//shared/logutil:go_default_library", "//shared/maxprocs:go_default_library", - "//shared/params:go_default_library", "//shared/version:go_default_library", - "//validator/accounts/v1:go_default_library", "//validator/accounts/v2:go_default_library", - "//validator/client:go_default_library", "//validator/flags:go_default_library", "//validator/node:go_default_library", "@com_github_joonix_log//:go_default_library", - "@com_github_prysmaticlabs_ethereumapis//eth/v1alpha1:go_default_library", "@com_github_sirupsen_logrus//:go_default_library", "@com_github_urfave_cli_v2//:go_default_library", "@com_github_x_cray_logrus_prefixed_formatter//:go_default_library", - "@org_golang_google_grpc//:go_default_library", ], ) @@ -63,7 +58,6 @@ go_image( "//shared/logutil:go_default_library", "//shared/params:go_default_library", "//shared/version:go_default_library", - "//validator/accounts/v1:go_default_library", "//validator/accounts/v2:go_default_library", "//validator/client:go_default_library", "//validator/flags:go_default_library", diff --git a/validator/accounts/v1/BUILD.bazel b/validator/accounts/v1/BUILD.bazel deleted file mode 100644 index eee3c9812146..000000000000 --- a/validator/accounts/v1/BUILD.bazel +++ /dev/null @@ -1,57 +0,0 @@ -load("@prysm//tools/go:def.bzl", "go_library") -load("@io_bazel_rules_go//go:def.bzl", "go_test") - -go_library( - name = "go_default_library", - srcs = [ - "account.go", - "status.go", - ], - importpath = "github.com/prysmaticlabs/prysm/validator/accounts/v1", - visibility = [ - "//validator:__pkg__", - "//validator:__subpackages__", - ], - deps = [ - "//contracts/deposit-contract:go_default_library", - "//shared/cmd:go_default_library", - "//shared/depositutil:go_default_library", - "//shared/fileutil:go_default_library", - "//shared/keystore:go_default_library", - "//shared/params:go_default_library", - "//validator/db/kv:go_default_library", - "//validator/flags:go_default_library", - "@com_github_pkg_errors//:go_default_library", - "@com_github_prysmaticlabs_ethereumapis//eth/v1alpha1:go_default_library", - "@com_github_sirupsen_logrus//:go_default_library", - "@com_github_urfave_cli_v2//:go_default_library", - "@io_opencensus_go//trace:go_default_library", - ], -) - -go_test( - name = "go_default_test", - size = "small", - srcs = [ - "account_test.go", - "status_test.go", - ], - embed = [":go_default_library"], - deps = [ - "//proto/slashing:go_default_library", - "//shared/keystore:go_default_library", - "//shared/mock:go_default_library", - "//shared/params:go_default_library", - "//shared/testutil:go_default_library", - "//shared/testutil/assert:go_default_library", - "//shared/testutil/require:go_default_library", - "//validator/db/kv:go_default_library", - "//validator/db/testing:go_default_library", - "//validator/flags:go_default_library", - "@com_github_golang_mock//gomock:go_default_library", - "@com_github_pkg_errors//:go_default_library", - "@com_github_prysmaticlabs_ethereumapis//eth/v1alpha1:go_default_library", - "@com_github_prysmaticlabs_go_bitfield//:go_default_library", - "@com_github_urfave_cli_v2//:go_default_library", - ], -) diff --git a/validator/accounts/v1/account.go b/validator/accounts/v1/account.go deleted file mode 100644 index 4e59bef7431f..000000000000 --- a/validator/accounts/v1/account.go +++ /dev/null @@ -1,354 +0,0 @@ -// Package accounts defines tools to manage an encrypted validator keystore. -package accounts - -import ( - "bufio" - "context" - "encoding/hex" - "fmt" - "io" - "os" - "path/filepath" - "runtime" - "strings" - - "github.com/pkg/errors" - contract "github.com/prysmaticlabs/prysm/contracts/deposit-contract" - "github.com/prysmaticlabs/prysm/shared/cmd" - "github.com/prysmaticlabs/prysm/shared/depositutil" - "github.com/prysmaticlabs/prysm/shared/fileutil" - "github.com/prysmaticlabs/prysm/shared/keystore" - "github.com/prysmaticlabs/prysm/shared/params" - "github.com/prysmaticlabs/prysm/validator/db/kv" - "github.com/prysmaticlabs/prysm/validator/flags" - "github.com/sirupsen/logrus" - "github.com/urfave/cli/v2" -) - -var log = logrus.WithField("prefix", "accounts") - -var errFailedToCloseDb = errors.New("failed to close the database") -var errFailedToCloseManyDb = errors.New("failed to close one or more databases") - -// DecryptKeysFromKeystore extracts a set of validator private keys from -// an encrypted keystore directory and a password string. -func DecryptKeysFromKeystore(directory, filePrefix, password string) (map[string]*keystore.Key, error) { - ks := keystore.New(directory) - validatorKeys, err := ks.GetKeys(directory, filePrefix, password, true) - if err != nil { - return nil, errors.Wrap(err, "could not get private key") - } - return validatorKeys, nil -} - -// VerifyAccountNotExists checks if a validator has not yet created an account -// and keystore in the provided directory string. -func VerifyAccountNotExists(directory, password string) error { - if directory == "" || password == "" { - return errors.New("expected a path to the validator keystore and password to be provided, received nil") - } - shardWithdrawalKeyFile := params.BeaconConfig().WithdrawalPrivkeyFileName - validatorKeyFile := params.BeaconConfig().ValidatorPrivkeyFileName - // First, if the keystore already exists, throws an error as there can only be - // one keystore per validator client. - ks := keystore.New(directory) - if _, err := ks.GetKeys(directory, shardWithdrawalKeyFile, password, false); err == nil { - return fmt.Errorf("keystore at path already exists: %s", shardWithdrawalKeyFile) - } - if _, err := ks.GetKeys(directory, validatorKeyFile, password, false); err == nil { - return fmt.Errorf("keystore at path already exists: %s", validatorKeyFile) - } - return nil -} - -// NewValidatorAccount sets up a validator client's secrets and generates the necessary deposit data -// parameters needed to deposit into the deposit contract on the ETH1.0 chain. Specifically, this -// generates a BLS private and public key, and then logs the serialized deposit input hex string -// to be used in an ETH1.0 transaction by the validator. -func NewValidatorAccount(directory, password string) error { - if password == "" { - return errors.New("empty passphrase is not allowed") - } - log.Info(`Thanks, we are generating your keystore now, this could take a while...`) - shardWithdrawalKeyFile := directory + params.BeaconConfig().WithdrawalPrivkeyFileName - validatorKeyFile := directory + params.BeaconConfig().ValidatorPrivkeyFileName - ks := keystore.New(directory) - // If the keystore does not exists at the path, we create a new one for the validator. - shardWithdrawalKey, err := keystore.NewKey() - if err != nil { - return err - } - shardWithdrawalKeyFile = shardWithdrawalKeyFile + hex.EncodeToString(shardWithdrawalKey.PublicKey.Marshal())[:12] - if err := ks.StoreKey(shardWithdrawalKeyFile, shardWithdrawalKey, password); err != nil { - return errors.Wrap(err, "unable to store key") - } - log.WithField( - "path", - shardWithdrawalKeyFile, - ).Info("Keystore generated for shard withdrawals at path") - validatorKey, err := keystore.NewKey() - if err != nil { - return err - } - validatorKeyFile = validatorKeyFile + hex.EncodeToString(validatorKey.PublicKey.Marshal())[:12] - if err := ks.StoreKey(validatorKeyFile, validatorKey, password); err != nil { - return errors.Wrap(err, "unable to store key") - } - log.WithField( - "path", - validatorKeyFile, - ).Info("Keystore generated for validator signatures at path") - - log.Info(`Generating deposit data now, please wait...`) - data, depositRoot, err := depositutil.DepositInput( - validatorKey.SecretKey, - shardWithdrawalKey.SecretKey, - params.BeaconConfig().MaxEffectiveBalance, - ) - if err != nil { - return errors.Wrap(err, "unable to generate deposit data") - } - testAcc, err := contract.Setup() - if err != nil { - return errors.Wrap(err, "unable to create simulated backend") - } - testAcc.TxOpts.GasLimit = 1000000 - - tx, err := testAcc.Contract.Deposit(testAcc.TxOpts, data.PublicKey, data.WithdrawalCredentials, data.Signature, depositRoot) - if err != nil { - return errors.Wrap(err, "unable to create deposit transaction") - } - log.Info(`Account creation complete! Copy and paste the raw deposit data shown below when issuing a transaction into the ETH1.0 deposit contract to activate your validator client`) - fmt.Printf(` -========================Deposit Data======================= - -%#x - -=================================================================== -`, tx.Data()) - fmt.Println("***Enter the above deposit data into step 3 on https://prylabs.net/participate***") - publicKey := validatorKey.PublicKey.Marshal() - log.Infof("Public key: %#x", publicKey) - return nil -} - -// Exists checks if a validator account at a given keystore path exists. -// assertNonEmpty is a boolean used to determine whether to check that -// the provided directory exists. -func Exists(keystorePath string, assertNonEmpty bool) (bool, error) { - /* #nosec */ - f, err := os.Open(keystorePath) - if err != nil { - return false, nil - } - defer func() { - if err := f.Close(); err != nil { - log.Fatal(err) - } - }() - - if assertNonEmpty { - _, err = f.Readdirnames(1) // Or f.Readdir(1) - if errors.Is(err, io.EOF) { - return false, nil - } - } - - return true, err -} - -// CreateValidatorAccount creates a validator account from the given cli context. -func CreateValidatorAccount(path, passphrase string) (string, string, error) { - // Forces user to create directory if using non-default path. - if path != DefaultValidatorDir() { - exists, err := Exists(path, false /* assertNonEmpty */) - if err != nil { - return path, passphrase, err - } - if !exists { - return path, passphrase, fmt.Errorf("path %q does not exist", path) - } - } - if err := NewValidatorAccount(path, passphrase); err != nil { - return "", "", errors.Wrapf(err, "could not initialize validator account") - } - return path, passphrase, nil -} - -// PrintPublicAndPrivateKeys uses the passed in path and prints out the public and private keys in that directory. -func PrintPublicAndPrivateKeys(path, passphrase string) error { - keystores, err := DecryptKeysFromKeystore(path, params.BeaconConfig().ValidatorPrivkeyFileName, passphrase) - if err != nil { - return errors.Wrapf(err, "failed to decrypt keystore keys at path %s", path) - } - for _, v := range keystores { - fmt.Printf("Public key: %#x private key: %#x\n", v.PublicKey.Marshal(), v.SecretKey.Marshal()) - } - return nil -} - -// DefaultValidatorDir returns OS-specific default keystore directory. -func DefaultValidatorDir() string { - // Try to place the data folder in the user's home dir - home := fileutil.HomeDir() - if home != "" { - if runtime.GOOS == "darwin" { - return filepath.Join(home, "Library", "Eth2Validators") - } else if runtime.GOOS == "windows" { - return filepath.Join(home, "AppData", "Roaming", "Eth2Validators") - } else { - return filepath.Join(home, ".eth2validators") - } - } - // As we cannot guess a stable location, return empty and handle later - return "" -} - -// HandleEmptyKeystoreFlags checks what the set flags are and allows the user to manually enter them if they're empty. -func HandleEmptyKeystoreFlags(cliCtx *cli.Context, confirmPassword bool) (string, string, error) { - path := cliCtx.String(flags.KeystorePathFlag.Name) - passphrase := cliCtx.String(flags.PasswordFlag.Name) - - if path == "" { - path = DefaultValidatorDir() - log.Infof("Please specify the keystore path for your private keys (default: %q):", path) - reader := bufio.NewReader(os.Stdin) - text, err := reader.ReadString('\n') - if err != nil { - return path, passphrase, errors.Wrap(err, "could not read input path") - } - if text = strings.ReplaceAll(text, "\n", ""); text != "" { - path = text - } - if text = strings.ReplaceAll(text, "\r", ""); text != "" { - path = text - } - } - - if passphrase == "" { - log.Info("Please enter the password for your private keys") - enteredPassphrase, err := cmd.EnterPassword(confirmPassword, cmd.StdInPasswordReader{}) - if err != nil { - return path, enteredPassphrase, errors.Wrap(err, "could not read entered passphrase") - } - passphrase = enteredPassphrase - } - - return path, passphrase, nil -} - -// Merge merges data from validator databases in sourceDirectories into a new store, which is created in targetDirectory. -func Merge(ctx context.Context, sourceDirectories []string, targetDirectory string) (err error) { - var sourceStores []*kv.Store - defer func() { - failedToClose := false - for _, store := range sourceStores { - if deferErr := store.Close(); deferErr != nil { - failedToClose = true - } - } - if failedToClose { - if err != nil { - err = errors.Wrapf(err, errFailedToCloseManyDb.Error()) - } else { - err = errFailedToCloseManyDb - } - } - }() - - for _, dir := range sourceDirectories { - store, err := kv.GetKVStore(dir) - if err != nil { - return errors.Wrapf(err, "failed to prepare the database in %s for merging", dir) - } - if store == nil { - continue - } - sourceStores = append(sourceStores, store) - } - - if len(sourceStores) == 0 { - return errors.New("no validator databases found in source directories") - } - - return kv.Merge(ctx, sourceStores, targetDirectory) -} - -// Split splits data from one validator database in sourceDirectory into several validator databases. -// Each validator database is created in its own subdirectory inside targetDirectory. -func Split(ctx context.Context, sourceDirectory, targetDirectory string) (err error) { - var sourceStore *kv.Store - sourceStore, err = kv.GetKVStore(sourceDirectory) - if err != nil { - return errors.Wrap(err, "failed to prepare the source database for splitting") - } - if sourceStore == nil { - return errors.New("no database found in source directory") - } - defer func() { - if sourceStore != nil { - if deferErr := sourceStore.Close(); deferErr != nil { - if err != nil { - err = errors.Wrap(err, errFailedToCloseDb.Error()) - } else { - err = errors.Wrap(deferErr, errFailedToCloseDb.Error()) - } - } - } - }() - - return kv.Split(ctx, sourceStore, targetDirectory) -} - -// ChangePassword changes the password for all keys located in a keystore. -// Password is changed only for keys that can be decrypted using the old password. -func ChangePassword(keystorePath, oldPassword, newPassword string) error { - err := changePasswordForKeyType( - keystorePath, - params.BeaconConfig().ValidatorPrivkeyFileName, - oldPassword, - newPassword) - if err != nil { - return err - } - - return changePasswordForKeyType( - keystorePath, - params.BeaconConfig().WithdrawalPrivkeyFileName, - oldPassword, - newPassword) -} - -func changePasswordForKeyType(keystorePath, filePrefix, oldPassword, newPassword string) error { - keys, err := DecryptKeysFromKeystore(keystorePath, filePrefix, oldPassword) - if err != nil { - return errors.Wrap(err, "failed to decrypt keys") - } - - keyStore := keystore.New(keystorePath) - for _, key := range keys { - keyFileName := keystorePath + filePrefix + hex.EncodeToString(key.PublicKey.Marshal())[:12] - if err := keyStore.StoreKey(keyFileName, key, newPassword); err != nil { - return errors.Wrapf(err, "failed to encrypt key %s with the new password", keyFileName) - } - } - - return nil -} - -// ExtractPublicKeysFromKeyStore extracts only the public keys from the decrypted keys from the keystore. -func ExtractPublicKeysFromKeyStore(keystorePath, passphrase string) ([][]byte, error) { - decryptedKeys, err := DecryptKeysFromKeystore(keystorePath, params.BeaconConfig().ValidatorPrivkeyFileName, passphrase) - if err != nil { - return nil, errors.Wrapf(err, "could not decrypt keys from keystore in path %s", keystorePath) - } - - i := 0 - pubkeys := make([][]byte, len(decryptedKeys)) - for _, key := range decryptedKeys { - pubkeys[i] = key.PublicKey.Marshal() - i++ - } - - return pubkeys, nil -} diff --git a/validator/accounts/v1/account_test.go b/validator/accounts/v1/account_test.go deleted file mode 100644 index 1814c32af042..000000000000 --- a/validator/accounts/v1/account_test.go +++ /dev/null @@ -1,301 +0,0 @@ -package accounts - -import ( - "context" - "encoding/hex" - "flag" - "fmt" - "io/ioutil" - "os" - "testing" - - "github.com/pkg/errors" - "github.com/prysmaticlabs/go-bitfield" - slashpb "github.com/prysmaticlabs/prysm/proto/slashing" - "github.com/prysmaticlabs/prysm/shared/keystore" - "github.com/prysmaticlabs/prysm/shared/params" - "github.com/prysmaticlabs/prysm/shared/testutil" - "github.com/prysmaticlabs/prysm/shared/testutil/assert" - "github.com/prysmaticlabs/prysm/shared/testutil/require" - "github.com/prysmaticlabs/prysm/validator/db/kv" - dbTest "github.com/prysmaticlabs/prysm/validator/db/testing" - "github.com/prysmaticlabs/prysm/validator/flags" - "github.com/urfave/cli/v2" -) - -type sourceStoresHistory struct { - ProposalEpoch uint64 - FirstStorePubKeyProposals bitfield.Bitlist - SecondStorePubKeyProposals bitfield.Bitlist - FirstStorePubKeyAttestations map[uint64]uint64 - SecondStorePubKeyAttestations map[uint64]uint64 -} - -func TestNewValidatorAccount_AccountExists(t *testing.T) { - directory := testutil.TempDir() + "/testkeystore" - defer func() { - assert.NoError(t, os.RemoveAll(directory)) - }() - validatorKey, err := keystore.NewKey() - require.NoError(t, err, "Cannot create new key") - ks := keystore.New(directory) - err = ks.StoreKey(directory+params.BeaconConfig().ValidatorPrivkeyFileName, validatorKey, "") - require.NoError(t, err, "Unable to store key") - require.NoError(t, NewValidatorAccount(directory, "passsword123"), "Should support multiple keys") - files, err := ioutil.ReadDir(directory) - assert.NoError(t, err) - if len(files) != 3 { - t.Errorf("multiple validators were not created only %v files in directory", len(files)) - for _, f := range files { - t.Errorf("%v\n", f.Name()) - } - } -} - -func TestNewValidatorAccount_CreateValidatorAccount(t *testing.T) { - t.Run("custom non-existent path", func(t *testing.T) { - _, _, err := CreateValidatorAccount("foobar", "foobar") - wantErrString := fmt.Sprintf("path %q does not exist", "foobar") - assert.ErrorContains(t, wantErrString, err) - }) - - t.Run("empty existing dir", func(t *testing.T) { - directory := testutil.TempDir() + "/testkeystore" - defer func() { - assert.NoError(t, os.RemoveAll(directory), "Could not remove directory") - }() - - // Make sure that empty existing directory doesn't trigger any errors. - require.NoError(t, os.Mkdir(directory, 0777)) - _, _, err := CreateValidatorAccount(directory, "foobar") - assert.NoError(t, err) - }) - - t.Run("empty string as password", func(t *testing.T) { - directory := testutil.TempDir() + "/testkeystore" - defer func() { - assert.NoError(t, os.RemoveAll(directory), "Could not remove directory") - }() - require.NoError(t, os.Mkdir(directory, 0777)) - _, _, err := CreateValidatorAccount(directory, "") - wantErrString := "empty passphrase is not allowed" - assert.ErrorContains(t, wantErrString, err) - }) -} - -func TestHandleEmptyFlags_FlagsSet(t *testing.T) { - passedPath := "~/path/given" - passedPassword := "password" - - app := &cli.App{} - set := flag.NewFlagSet("test", 0) - set.String(flags.KeystorePathFlag.Name, passedPath, "set keystore path") - set.String(flags.PasswordFlag.Name, passedPassword, "set keystore password") - ctx := cli.NewContext(app, set, nil) - path, passphrase, err := HandleEmptyKeystoreFlags(ctx, false) - require.NoError(t, err) - - assert.Equal(t, passedPath, path, "Expected set path to be unchanged") - assert.Equal(t, passedPassword, passphrase, "Expected set password to be unchanged") -} - -func TestChangePassword_KeyEncryptedWithNewPassword(t *testing.T) { - directory := testutil.TempDir() + "/testkeystore" - defer func() { - assert.NoError(t, os.RemoveAll(directory), "Could not remove directory") - }() - - oldPassword := "old" - newPassword := "new" - - validatorKey, err := keystore.NewKey() - require.NoError(t, err, "Cannot create new key") - ks := keystore.New(directory) - err = ks.StoreKey(directory+params.BeaconConfig().ValidatorPrivkeyFileName, validatorKey, oldPassword) - require.NoError(t, err, "Unable to store key") - - require.NoError(t, ChangePassword(directory, oldPassword, newPassword)) - - keys, err := DecryptKeysFromKeystore(directory, params.BeaconConfig().ValidatorPrivkeyFileName, newPassword) - require.NoError(t, err) - - _, ok := keys[hex.EncodeToString(validatorKey.PublicKey.Marshal())] - assert.Equal(t, true, ok, "Key not encrypted using the new password") -} - -func TestChangePassword_KeyNotMatchingOldPasswordNotEncryptedWithNewPassword(t *testing.T) { - directory := testutil.TempDir() + "/testkeystore" - defer func() { - assert.NoError(t, os.RemoveAll(directory), "Could not remove directory") - }() - - oldPassword := "old" - newPassword := "new" - - validatorKey, err := keystore.NewKey() - require.NoError(t, err, "Cannot create new key") - ks := keystore.New(directory) - err = ks.StoreKey(directory+params.BeaconConfig().ValidatorPrivkeyFileName, validatorKey, "notmatching") - require.NoError(t, err, "Unable to store key") - - require.NoError(t, ChangePassword(directory, oldPassword, newPassword)) - - keys, err := DecryptKeysFromKeystore(directory, params.BeaconConfig().ValidatorPrivkeyFileName, newPassword) - require.NoError(t, err) - _, ok := keys[hex.EncodeToString(validatorKey.PublicKey.Marshal())] - assert.Equal(t, false, ok, "Key incorrectly encrypted using the new password") -} - -func TestMerge_SucceedsWhenNoDatabaseExistsInSomeSourceDirectory(t *testing.T) { - firstStorePubKey := [48]byte{1} - firstStore := dbTest.SetupDB(t, [][48]byte{firstStorePubKey}) - secondStorePubKey := [48]byte{2} - secondStore := dbTest.SetupDB(t, [][48]byte{secondStorePubKey}) - history, err := prepareSourcesForMerging(firstStorePubKey, firstStore.(*kv.Store), secondStorePubKey, secondStore.(*kv.Store)) - require.NoError(t, err) - - require.NoError(t, firstStore.Close(), "Closing source store failed") - require.NoError(t, secondStore.Close(), "Closing source store failed") - - sourceDirectoryWithoutStore := testutil.TempDir() + "/nodb" - require.NoError(t, os.MkdirAll(sourceDirectoryWithoutStore, 0700), "Could not create directory") - targetDirectory := testutil.TempDir() + "/target" - t.Cleanup(func() { - assert.NoError(t, os.RemoveAll(targetDirectory), "Could not remove target directory") - }) - - err = Merge( - context.Background(), - []string{firstStore.DatabasePath(), secondStore.DatabasePath(), sourceDirectoryWithoutStore}, targetDirectory) - require.NoError(t, err, "Merging failed") - mergedStore, err := kv.GetKVStore(targetDirectory) - require.NoError(t, err, "Retrieving the merged store failed") - - assertMergedStore(t, mergedStore, firstStorePubKey, secondStorePubKey, history) -} - -func TestMerge_FailsWhenNoDatabaseExistsInAllSourceDirectories(t *testing.T) { - sourceDirectory1 := testutil.TempDir() + "/source1" - sourceDirectory2 := testutil.TempDir() + "/source2" - targetDirectory := testutil.TempDir() + "/target" - require.NoError(t, os.MkdirAll(sourceDirectory1, 0700), "Could not create directory") - require.NoError(t, os.MkdirAll(sourceDirectory2, 0700), "Could not create directory") - require.NoError(t, os.MkdirAll(targetDirectory, 0700), "Could not create directory") - t.Cleanup(func() { - for _, dir := range []string{sourceDirectory1, sourceDirectory2, targetDirectory} { - assert.NoError(t, os.RemoveAll(dir), "Could not remove directory") - } - }) - - err := Merge(context.Background(), []string{sourceDirectory1, sourceDirectory2}, targetDirectory) - expected := "no validator databases found in source directories" - assert.ErrorContains(t, expected, err) -} - -func TestSplit(t *testing.T) { - pubKeys := [][48]byte{{1}, {2}} - sourceStore := dbTest.SetupDB(t, pubKeys) - - proposalEpoch := uint64(0) - proposalHistory1 := bitfield.Bitlist{0x01, 0x00, 0x00, 0x00, 0x01} - err := sourceStore.SaveProposalHistoryForEpoch(context.Background(), pubKeys[0][:], proposalEpoch, proposalHistory1) - require.NoError(t, err, "Saving proposal history failed") - proposalHistory2 := bitfield.Bitlist{0x02, 0x00, 0x00, 0x00, 0x01} - err = sourceStore.SaveProposalHistoryForEpoch(context.Background(), pubKeys[1][:], proposalEpoch, proposalHistory2) - require.NoError(t, err, "Saving proposal history failed") - - attestationHistoryMap1 := make(map[uint64]uint64) - attestationHistoryMap1[0] = 0 - pubKeyAttestationHistory1 := &slashpb.AttestationHistory{ - TargetToSource: attestationHistoryMap1, - LatestEpochWritten: 0, - } - attestationHistoryMap2 := make(map[uint64]uint64) - attestationHistoryMap2[0] = 1 - pubKeyAttestationHistory2 := &slashpb.AttestationHistory{ - TargetToSource: attestationHistoryMap2, - LatestEpochWritten: 0, - } - dbAttestationHistory := make(map[[48]byte]*slashpb.AttestationHistory) - dbAttestationHistory[pubKeys[0]] = pubKeyAttestationHistory1 - dbAttestationHistory[pubKeys[1]] = pubKeyAttestationHistory2 - err = sourceStore.SaveAttestationHistoryForPubKeys(context.Background(), dbAttestationHistory) - require.NoError(t, err, "Saving attestation history failed %v") - - require.NoError(t, sourceStore.Close(), "Closing source store failed") - - targetDirectory := testutil.TempDir() + "/target" - t.Cleanup(func() { - assert.NoError(t, os.RemoveAll(targetDirectory), "Could not remove target directory") - }) - - require.NoError(t, Split(context.Background(), sourceStore.DatabasePath(), targetDirectory), "Splitting failed") -} - -func prepareSourcesForMerging(firstStorePubKey [48]byte, firstStore *kv.Store, secondStorePubKey [48]byte, secondStore *kv.Store) (*sourceStoresHistory, error) { - proposalEpoch := uint64(0) - proposalHistory1 := bitfield.Bitlist{0x01, 0x00, 0x00, 0x00, 0x01} - if err := firstStore.SaveProposalHistoryForEpoch(context.Background(), firstStorePubKey[:], proposalEpoch, proposalHistory1); err != nil { - return nil, errors.Wrapf(err, "Saving proposal history failed") - } - proposalHistory2 := bitfield.Bitlist{0x02, 0x00, 0x00, 0x00, 0x01} - if err := secondStore.SaveProposalHistoryForEpoch(context.Background(), secondStorePubKey[:], proposalEpoch, proposalHistory2); err != nil { - return nil, errors.Wrapf(err, "Saving proposal history failed") - } - - attestationHistoryMap1 := make(map[uint64]uint64) - attestationHistoryMap1[0] = 0 - pubKeyAttestationHistory1 := &slashpb.AttestationHistory{ - TargetToSource: attestationHistoryMap1, - LatestEpochWritten: 0, - } - dbAttestationHistory1 := make(map[[48]byte]*slashpb.AttestationHistory) - dbAttestationHistory1[firstStorePubKey] = pubKeyAttestationHistory1 - if err := firstStore.SaveAttestationHistoryForPubKeys(context.Background(), dbAttestationHistory1); err != nil { - return nil, errors.Wrapf(err, "Saving attestation history failed") - } - attestationHistoryMap2 := make(map[uint64]uint64) - attestationHistoryMap2[0] = 1 - pubKeyAttestationHistory2 := &slashpb.AttestationHistory{ - TargetToSource: attestationHistoryMap2, - LatestEpochWritten: 0, - } - dbAttestationHistory2 := make(map[[48]byte]*slashpb.AttestationHistory) - dbAttestationHistory2[secondStorePubKey] = pubKeyAttestationHistory2 - if err := secondStore.SaveAttestationHistoryForPubKeys(context.Background(), dbAttestationHistory2); err != nil { - return nil, errors.Wrapf(err, "Saving attestation history failed") - } - - mergeHistory := &sourceStoresHistory{ - ProposalEpoch: proposalEpoch, - FirstStorePubKeyProposals: proposalHistory1, - SecondStorePubKeyProposals: proposalHistory2, - FirstStorePubKeyAttestations: attestationHistoryMap1, - SecondStorePubKeyAttestations: attestationHistoryMap2, - } - - return mergeHistory, nil -} - -func assertMergedStore( - t *testing.T, - mergedStore *kv.Store, - firstStorePubKey, secondStorePubKey [48]byte, - history *sourceStoresHistory) { - - mergedProposalHistory1, err := mergedStore.ProposalHistoryForEpoch( - context.Background(), firstStorePubKey[:], history.ProposalEpoch) - require.NoError(t, err, "Retrieving merged proposal history failed for public key %v", firstStorePubKey) - require.DeepEqual(t, history.FirstStorePubKeyProposals, mergedProposalHistory1, "Proposals not merged correctly") - mergedProposalHistory2, err := mergedStore.ProposalHistoryForEpoch( - context.Background(), secondStorePubKey[:], history.ProposalEpoch) - require.NoError(t, err, "Retrieving merged proposal history failed for public key %v", secondStorePubKey) - require.DeepEqual(t, history.SecondStorePubKeyProposals, mergedProposalHistory2, "Proposals not merged correctly") - - mergedAttestationHistory, err := mergedStore.AttestationHistoryForPubKeys( - context.Background(), - [][48]byte{firstStorePubKey, secondStorePubKey}) - require.NoError(t, err, "Retrieving merged attestation history failed") - assert.Equal(t, history.FirstStorePubKeyAttestations[0], mergedAttestationHistory[firstStorePubKey].TargetToSource[0]) - assert.Equal(t, history.SecondStorePubKeyAttestations[0], mergedAttestationHistory[secondStorePubKey].TargetToSource[0]) -} diff --git a/validator/accounts/v1/status.go b/validator/accounts/v1/status.go deleted file mode 100644 index c7e091aa58e7..000000000000 --- a/validator/accounts/v1/status.go +++ /dev/null @@ -1,95 +0,0 @@ -package accounts - -import ( - "context" - "fmt" - "sort" - "time" - - "github.com/pkg/errors" - ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1" - "github.com/prysmaticlabs/prysm/shared/params" - "github.com/sirupsen/logrus" - "go.opencensus.io/trace" -) - -// statusTimeout defines a period after which request to fetch account statuses is cancelled. -const statusTimeout = 30 * time.Second - -// ValidatorStatusMetadata holds all status information about a validator. -type ValidatorStatusMetadata struct { - PublicKey []byte - Index uint64 - Metadata *ethpb.ValidatorStatusResponse -} - -// RunStatusCommand is the entry point to the `validator status` command. -func RunStatusCommand(ctx context.Context, pubKeys [][]byte, beaconNodeRPCProvider ethpb.BeaconNodeValidatorClient) error { - statuses, err := FetchAccountStatuses(ctx, beaconNodeRPCProvider, pubKeys) - if err != nil { - return errors.Wrap(err, "could not fetch account statuses from the beacon node") - } - printStatuses(statuses) - return nil -} - -// FetchAccountStatuses fetches validator statuses from the BeaconNodeValidatorClient -// for each validator public key. -func FetchAccountStatuses( - ctx context.Context, - beaconClient ethpb.BeaconNodeValidatorClient, - pubKeys [][]byte, -) ([]ValidatorStatusMetadata, error) { - ctx, span := trace.StartSpan(ctx, "accounts.FetchAccountStatuses") - defer span.End() - ctx, cancel := context.WithTimeout(ctx, statusTimeout) - defer cancel() - - req := ðpb.MultipleValidatorStatusRequest{PublicKeys: pubKeys} - resp, err := beaconClient.MultipleValidatorStatus(ctx, req) - if err != nil { - return nil, err - } - - statuses := make([]ValidatorStatusMetadata, len(resp.Statuses)) - for i, status := range resp.Statuses { - statuses[i] = ValidatorStatusMetadata{ - PublicKey: resp.PublicKeys[i], - Index: resp.Indices[i], - Metadata: status, - } - } - sort.Slice(statuses, func(i, j int) bool { - return statuses[i].Metadata.Status < statuses[j].Metadata.Status - }) - - return statuses, nil -} - -func printStatuses(validatorStatuses []ValidatorStatusMetadata) { - nonexistentIndex := ^uint64(0) - for _, v := range validatorStatuses { - m := v.Metadata - key := v.PublicKey - fields := logrus.Fields{ - "publicKey": fmt.Sprintf("%#x", key), - } - if v.Index != nonexistentIndex { - fields["index"] = v.Index - } - if m.Status == ethpb.ValidatorStatus_PENDING || m.Status == ethpb.ValidatorStatus_ACTIVE { - fields["activationEpoch"] = m.ActivationEpoch - if m.ActivationEpoch == params.BeaconConfig().FarFutureEpoch { - fields["positionInActivationQueue"] = m.PositionInActivationQueue - } - } else if m.Status == ethpb.ValidatorStatus_DEPOSITED { - if m.PositionInActivationQueue != 0 { - fields["depositInclusionSlot"] = m.DepositInclusionSlot - fields["eth1DepositBlockNumber"] = m.Eth1DepositBlockNumber - } else { - fields["positionInActivationQueue"] = m.PositionInActivationQueue - } - } - log.WithFields(fields).Infof("Status: %s", m.Status.String()) - } -} diff --git a/validator/accounts/v1/status_test.go b/validator/accounts/v1/status_test.go deleted file mode 100644 index 68f44046fa41..000000000000 --- a/validator/accounts/v1/status_test.go +++ /dev/null @@ -1,31 +0,0 @@ -package accounts - -import ( - "context" - "testing" - - "github.com/golang/mock/gomock" - ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1" - "github.com/prysmaticlabs/prysm/shared/mock" - "github.com/prysmaticlabs/prysm/shared/testutil/require" -) - -func TestFetchAccountStatuses_OK(t *testing.T) { - ctx := context.Background() - ctrl := gomock.NewController(t) - defer ctrl.Finish() - pubkeys := make([][]byte, 10000) - indices := make([]uint64, 10000) - for i := 0; i < 10000; i++ { - pubkeys[i] = []byte{byte(i)} - indices[i] = uint64(i) - } - - mockClient := mock.NewMockBeaconNodeValidatorClient(ctrl) - mockClient.EXPECT().MultipleValidatorStatus( - gomock.Any(), - ðpb.MultipleValidatorStatusRequest{PublicKeys: pubkeys}, - ).Return(ðpb.MultipleValidatorStatusResponse{PublicKeys: pubkeys, Indices: indices}, nil /*err*/) - _, err := FetchAccountStatuses(ctx, mockClient, pubkeys) - require.NoError(t, err, "FetchAccountStatuses failed with error") -} diff --git a/validator/accounts/v2/cmd_accounts.go b/validator/accounts/v2/cmd_accounts.go index c62eea29dd21..a92bdd9ffe94 100644 --- a/validator/accounts/v2/cmd_accounts.go +++ b/validator/accounts/v2/cmd_accounts.go @@ -24,9 +24,7 @@ this command outputs a deposit data string which is required to become a validat Flags: cmd.WrapFlags([]cli.Flag{ flags.WalletDirFlag, flags.WalletPasswordFileFlag, - flags.AccountPasswordFileFlag, flags.NumAccountsFlag, - flags.DeprecatedPasswordsDirFlag, featureconfig.AltonaTestnet, featureconfig.OnyxTestnet, featureconfig.MedallaTestnet, @@ -50,7 +48,6 @@ this command outputs a deposit data string which is required to become a validat Flags: cmd.WrapFlags([]cli.Flag{ flags.WalletDirFlag, flags.WalletPasswordFileFlag, - flags.AccountPasswordFileFlag, flags.DeletePublicKeysFlag, featureconfig.AltonaTestnet, featureconfig.OnyxTestnet, @@ -81,7 +78,6 @@ this command outputs a deposit data string which is required to become a validat featureconfig.MedallaTestnet, featureconfig.SpadinaTestnet, featureconfig.ZinkenTestnet, - flags.DeprecatedPasswordsDirFlag, }), Before: func(cliCtx *cli.Context) error { return cmd.LoadFlagsFromConfig(cliCtx, cliCtx.Command.Flags) @@ -137,7 +133,6 @@ this command outputs a deposit data string which is required to become a validat featureconfig.MedallaTestnet, featureconfig.SpadinaTestnet, featureconfig.ZinkenTestnet, - flags.DeprecatedPasswordsDirFlag, }), Before: func(cliCtx *cli.Context) error { return cmd.LoadFlagsFromConfig(cliCtx, cliCtx.Command.Flags) diff --git a/validator/accounts/v2/cmd_wallet.go b/validator/accounts/v2/cmd_wallet.go index 0eb2872ffc41..655dead079cd 100644 --- a/validator/accounts/v2/cmd_wallet.go +++ b/validator/accounts/v2/cmd_wallet.go @@ -29,7 +29,6 @@ var WalletCommands = &cli.Command{ featureconfig.MedallaTestnet, featureconfig.SpadinaTestnet, featureconfig.ZinkenTestnet, - flags.DeprecatedPasswordsDirFlag, }, Action: func(cliCtx *cli.Context) error { featureconfig.ConfigureValidator(cliCtx) @@ -53,7 +52,6 @@ var WalletCommands = &cli.Command{ featureconfig.MedallaTestnet, featureconfig.SpadinaTestnet, featureconfig.ZinkenTestnet, - flags.DeprecatedPasswordsDirFlag, }, Action: func(cliCtx *cli.Context) error { featureconfig.ConfigureValidator(cliCtx) @@ -76,7 +74,6 @@ var WalletCommands = &cli.Command{ featureconfig.MedallaTestnet, featureconfig.SpadinaTestnet, featureconfig.ZinkenTestnet, - flags.DeprecatedPasswordsDirFlag, }, Action: func(cliCtx *cli.Context) error { featureconfig.ConfigureValidator(cliCtx) diff --git a/validator/accounts/v2/wallet/wallet_test.go b/validator/accounts/v2/wallet/wallet_test.go index 9565fd738857..9b48fc426278 100644 --- a/validator/accounts/v2/wallet/wallet_test.go +++ b/validator/accounts/v2/wallet/wallet_test.go @@ -58,7 +58,6 @@ func setupWalletCtx( app := cli.App{} set := flag.NewFlagSet("test", 0) set.String(flags.WalletDirFlag.Name, cfg.walletDir, "") - set.String(flags.DeprecatedPasswordsDirFlag.Name, cfg.passwordsDir, "") set.String(flags.KeysDirFlag.Name, cfg.keysDir, "") set.String(flags.KeymanagerKindFlag.Name, cfg.keymanagerKind.String(), "") set.String(flags.DeletePublicKeysFlag.Name, cfg.deletePublicKeys, "") @@ -76,7 +75,6 @@ func setupWalletCtx( assert.NoError(tb, set.Set(flags.ImportPrivateKeyFileFlag.Name, cfg.privateKeyFile)) } assert.NoError(tb, set.Set(flags.WalletDirFlag.Name, cfg.walletDir)) - assert.NoError(tb, set.Set(flags.DeprecatedPasswordsDirFlag.Name, cfg.passwordsDir)) assert.NoError(tb, set.Set(flags.KeysDirFlag.Name, cfg.keysDir)) assert.NoError(tb, set.Set(flags.KeymanagerKindFlag.Name, cfg.keymanagerKind.String())) assert.NoError(tb, set.Set(flags.DeletePublicKeysFlag.Name, cfg.deletePublicKeys)) diff --git a/validator/accounts/v2/wallet_create_test.go b/validator/accounts/v2/wallet_create_test.go index 9475bb495c7d..ee20c0ea044f 100644 --- a/validator/accounts/v2/wallet_create_test.go +++ b/validator/accounts/v2/wallet_create_test.go @@ -66,7 +66,6 @@ func setupWalletCtx( app := cli.App{} set := flag.NewFlagSet("test", 0) set.String(flags.WalletDirFlag.Name, cfg.walletDir, "") - set.String(flags.DeprecatedPasswordsDirFlag.Name, cfg.passwordsDir, "") set.String(flags.KeysDirFlag.Name, cfg.keysDir, "") set.String(flags.KeymanagerKindFlag.Name, cfg.keymanagerKind.String(), "") set.String(flags.DeletePublicKeysFlag.Name, cfg.deletePublicKeys, "") @@ -84,7 +83,6 @@ func setupWalletCtx( assert.NoError(tb, set.Set(flags.ImportPrivateKeyFileFlag.Name, cfg.privateKeyFile)) } assert.NoError(tb, set.Set(flags.WalletDirFlag.Name, cfg.walletDir)) - assert.NoError(tb, set.Set(flags.DeprecatedPasswordsDirFlag.Name, cfg.passwordsDir)) assert.NoError(tb, set.Set(flags.KeysDirFlag.Name, cfg.keysDir)) assert.NoError(tb, set.Set(flags.KeymanagerKindFlag.Name, cfg.keymanagerKind.String())) assert.NoError(tb, set.Set(flags.DeletePublicKeysFlag.Name, cfg.deletePublicKeys)) diff --git a/validator/client/BUILD.bazel b/validator/client/BUILD.bazel index 073fb7225460..94c3a57544f2 100644 --- a/validator/client/BUILD.bazel +++ b/validator/client/BUILD.bazel @@ -35,12 +35,10 @@ go_library( "//shared/timeutils:go_default_library", "//validator/accounts/v2/wallet:go_default_library", "//validator/db:go_default_library", - "//validator/keymanager/v1:go_default_library", "//validator/keymanager/v2:go_default_library", "//validator/keymanager/v2/direct:go_default_library", "//validator/slashing-protection:go_default_library", "@com_github_dgraph_io_ristretto//:go_default_library", - "@com_github_ferranbt_fastssz//:go_default_library", "@com_github_gogo_protobuf//proto:go_default_library", "@com_github_gogo_protobuf//types:go_default_library", "@com_github_grpc_ecosystem_go_grpc_middleware//:go_default_library", @@ -53,7 +51,6 @@ go_library( "@com_github_prometheus_client_golang//prometheus/promauto:go_default_library", "@com_github_prysmaticlabs_ethereumapis//eth/v1alpha1:go_default_library", "@com_github_prysmaticlabs_go_bitfield//:go_default_library", - "@com_github_prysmaticlabs_go_ssz//:go_default_library", "@com_github_sirupsen_logrus//:go_default_library", "@io_opencensus_go//plugin/ocgrpc:go_default_library", "@io_opencensus_go//trace:go_default_library", @@ -89,7 +86,6 @@ go_test( "//shared/bls:go_default_library", "//shared/bytesutil:go_default_library", "//shared/featureconfig:go_default_library", - "//shared/keystore:go_default_library", "//shared/mock:go_default_library", "//shared/params:go_default_library", "//shared/slotutil:go_default_library", @@ -97,9 +93,7 @@ go_test( "//shared/testutil/assert:go_default_library", "//shared/testutil/require:go_default_library", "//shared/timeutils:go_default_library", - "//validator/accounts/v1:go_default_library", "//validator/db/testing:go_default_library", - "//validator/keymanager/v1:go_default_library", "//validator/testing:go_default_library", "@com_github_gogo_protobuf//types:go_default_library", "@com_github_golang_mock//gomock:go_default_library", diff --git a/validator/client/aggregate.go b/validator/client/aggregate.go index 72a0690d1eca..d66bf7a13436 100644 --- a/validator/client/aggregate.go +++ b/validator/client/aggregate.go @@ -5,12 +5,10 @@ import ( "fmt" "time" - "github.com/pkg/errors" ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1" "github.com/prysmaticlabs/prysm/beacon-chain/core/helpers" validatorpb "github.com/prysmaticlabs/prysm/proto/validator/accounts/v2" "github.com/prysmaticlabs/prysm/shared/bls" - "github.com/prysmaticlabs/prysm/shared/featureconfig" "github.com/prysmaticlabs/prysm/shared/params" "github.com/prysmaticlabs/prysm/shared/slotutil" "github.com/prysmaticlabs/prysm/shared/timeutils" @@ -116,25 +114,18 @@ func (v *validator) signSlot(ctx context.Context, pubKey [48]byte, slot uint64) } var sig bls.Signature - if featureconfig.Get().EnableAccountsV2 { - root, err := helpers.ComputeSigningRoot(slot, domain.SignatureDomain) - if err != nil { - return nil, err - } - sig, err = v.keyManagerV2.Sign(ctx, &validatorpb.SignRequest{ - PublicKey: pubKey[:], - SigningRoot: root[:], - SignatureDomain: domain.SignatureDomain, - Object: &validatorpb.SignRequest_Slot{Slot: slot}, - }) - if err != nil { - return nil, err - } - } else { - sig, err = v.signObject(ctx, pubKey, slot, domain.SignatureDomain) - if err != nil { - return nil, errors.Wrap(err, "Failed to sign slot") - } + root, err := helpers.ComputeSigningRoot(slot, domain.SignatureDomain) + if err != nil { + return nil, err + } + sig, err = v.keyManagerV2.Sign(ctx, &validatorpb.SignRequest{ + PublicKey: pubKey[:], + SigningRoot: root[:], + SignatureDomain: domain.SignatureDomain, + Object: &validatorpb.SignRequest_Slot{Slot: slot}, + }) + if err != nil { + return nil, err } return sig.Marshal(), nil @@ -164,25 +155,18 @@ func (v *validator) aggregateAndProofSig(ctx context.Context, pubKey [48]byte, a return nil, err } var sig bls.Signature - if featureconfig.Get().EnableAccountsV2 { - root, err := helpers.ComputeSigningRoot(agg, d.SignatureDomain) - if err != nil { - return nil, err - } - sig, err = v.keyManagerV2.Sign(ctx, &validatorpb.SignRequest{ - PublicKey: pubKey[:], - SigningRoot: root[:], - SignatureDomain: d.SignatureDomain, - Object: &validatorpb.SignRequest_AggregateAttestationAndProof{AggregateAttestationAndProof: agg}, - }) - if err != nil { - return nil, err - } - } else { - sig, err = v.signObject(ctx, pubKey, agg, d.SignatureDomain) - if err != nil { - return nil, errors.Wrap(err, "Failed to sign slot") - } + root, err := helpers.ComputeSigningRoot(agg, d.SignatureDomain) + if err != nil { + return nil, err + } + sig, err = v.keyManagerV2.Sign(ctx, &validatorpb.SignRequest{ + PublicKey: pubKey[:], + SigningRoot: root[:], + SignatureDomain: d.SignatureDomain, + Object: &validatorpb.SignRequest_AggregateAttestationAndProof{AggregateAttestationAndProof: agg}, + }) + if err != nil { + return nil, err } return sig.Marshal(), nil diff --git a/validator/client/aggregate_test.go b/validator/client/aggregate_test.go index 45489a1dc9f1..ff368eccdc96 100644 --- a/validator/client/aggregate_test.go +++ b/validator/client/aggregate_test.go @@ -19,22 +19,26 @@ import ( func TestSubmitAggregateAndProof_GetDutiesRequestFailure(t *testing.T) { hook := logTest.NewGlobal() - validator, _, finish := setup(t) + validator, _, validatorKey, finish := setup(t) validator.duties = ðpb.DutiesResponse{Duties: []*ethpb.DutiesResponse_Duty{}} defer finish() - validator.SubmitAggregateAndProof(context.Background(), 0, validatorPubKey) + pubKey := [48]byte{} + copy(pubKey[:], validatorKey.PublicKey().Marshal()) + validator.SubmitAggregateAndProof(context.Background(), 0, pubKey) require.LogsContain(t, hook, "Could not fetch validator assignment") } func TestSubmitAggregateAndProof_SignFails(t *testing.T) { - validator, m, finish := setup(t) + validator, m, validatorKey, finish := setup(t) defer finish() + pubKey := [48]byte{} + copy(pubKey[:], validatorKey.PublicKey().Marshal()) validator.duties = ðpb.DutiesResponse{ Duties: []*ethpb.DutiesResponse_Duty{ { - PublicKey: validatorKey.PublicKey.Marshal(), + PublicKey: validatorKey.PublicKey().Marshal(), }, }, } @@ -68,16 +72,18 @@ func TestSubmitAggregateAndProof_SignFails(t *testing.T) { gomock.Any(), // epoch ).Return(ðpb.DomainResponse{SignatureDomain: nil}, errors.New("bad domain root")) - validator.SubmitAggregateAndProof(context.Background(), 0, validatorPubKey) + validator.SubmitAggregateAndProof(context.Background(), 0, pubKey) } func TestSubmitAggregateAndProof_Ok(t *testing.T) { - validator, m, finish := setup(t) + validator, m, validatorKey, finish := setup(t) defer finish() + pubKey := [48]byte{} + copy(pubKey[:], validatorKey.PublicKey().Marshal()) validator.duties = ðpb.DutiesResponse{ Duties: []*ethpb.DutiesResponse_Duty{ { - PublicKey: validatorKey.PublicKey.Marshal(), + PublicKey: validatorKey.PublicKey().Marshal(), }, }, } @@ -116,11 +122,11 @@ func TestSubmitAggregateAndProof_Ok(t *testing.T) { gomock.AssignableToTypeOf(ðpb.SignedAggregateSubmitRequest{}), ).Return(ðpb.SignedAggregateSubmitResponse{AttestationDataRoot: make([]byte, 32)}, nil) - validator.SubmitAggregateAndProof(context.Background(), 0, validatorPubKey) + validator.SubmitAggregateAndProof(context.Background(), 0, pubKey) } func TestWaitForSlotTwoThird_WaitCorrectly(t *testing.T) { - validator, _, finish := setup(t) + validator, _, _, finish := setup(t) defer finish() currentTime := timeutils.Now() numOfSlots := uint64(4) @@ -135,9 +141,11 @@ func TestWaitForSlotTwoThird_WaitCorrectly(t *testing.T) { } func TestAggregateAndProofSignature_CanSignValidSignature(t *testing.T) { - validator, m, finish := setup(t) + validator, m, validatorKey, finish := setup(t) defer finish() + pubKey := [48]byte{} + copy(pubKey[:], validatorKey.PublicKey().Marshal()) m.validatorClient.EXPECT().DomainData( gomock.Any(), // ctx ðpb.DomainRequest{Epoch: 0, Domain: params.BeaconConfig().DomainAggregateAndProof[:]}, @@ -155,7 +163,7 @@ func TestAggregateAndProofSignature_CanSignValidSignature(t *testing.T) { }, SelectionProof: make([]byte, 96), } - sig, err := validator.aggregateAndProofSig(context.Background(), validatorPubKey, agg) + sig, err := validator.aggregateAndProofSig(context.Background(), pubKey, agg) require.NoError(t, err) _, err = bls.SignatureFromBytes(sig) require.NoError(t, err) diff --git a/validator/client/attest.go b/validator/client/attest.go index 8ddb612d8546..22abac291e4c 100644 --- a/validator/client/attest.go +++ b/validator/client/attest.go @@ -11,14 +11,11 @@ import ( "github.com/prysmaticlabs/go-bitfield" "github.com/prysmaticlabs/prysm/beacon-chain/core/helpers" validatorpb "github.com/prysmaticlabs/prysm/proto/validator/accounts/v2" - "github.com/prysmaticlabs/prysm/shared/bls" "github.com/prysmaticlabs/prysm/shared/bytesutil" - "github.com/prysmaticlabs/prysm/shared/featureconfig" "github.com/prysmaticlabs/prysm/shared/hashutil" "github.com/prysmaticlabs/prysm/shared/params" "github.com/prysmaticlabs/prysm/shared/slotutil" "github.com/prysmaticlabs/prysm/shared/timeutils" - keymanager "github.com/prysmaticlabs/prysm/validator/keymanager/v1" "github.com/sirupsen/logrus" "go.opencensus.io/trace" ) @@ -176,21 +173,12 @@ func (v *validator) signAtt(ctx context.Context, pubKey [48]byte, data *ethpb.At return nil, err } - var sig bls.Signature - if featureconfig.Get().EnableAccountsV2 { - sig, err = v.keyManagerV2.Sign(ctx, &validatorpb.SignRequest{ - PublicKey: pubKey[:], - SigningRoot: root[:], - SignatureDomain: domain.SignatureDomain, - Object: &validatorpb.SignRequest_AttestationData{AttestationData: data}, - }) - } else { - if protectingKeymanager, supported := v.keyManager.(keymanager.ProtectingKeyManager); supported { - sig, err = protectingKeymanager.SignAttestation(pubKey, bytesutil.ToBytes32(domain.SignatureDomain), data) - } else { - sig, err = v.keyManager.Sign(ctx, pubKey, root) - } - } + sig, err := v.keyManagerV2.Sign(ctx, &validatorpb.SignRequest{ + PublicKey: pubKey[:], + SigningRoot: root[:], + SignatureDomain: domain.SignatureDomain, + Object: &validatorpb.SignRequest_AttestationData{AttestationData: data}, + }) if err != nil { return nil, err } diff --git a/validator/client/attest_protect_test.go b/validator/client/attest_protect_test.go index a475e9ab34a3..5f6596e88a77 100644 --- a/validator/client/attest_protect_test.go +++ b/validator/client/attest_protect_test.go @@ -20,8 +20,10 @@ func TestPreSignatureValidation(t *testing.T) { } reset := featureconfig.InitWithReset(config) defer reset() - validator, _, finish := setup(t) + validator, _, validatorKey, finish := setup(t) defer finish() + pubKey := [48]byte{} + copy(pubKey[:], validatorKey.PublicKey().Marshal()) att := ðpb.IndexedAttestation{ AttestingIndices: []uint64{1, 2}, Data: ðpb.AttestationData{ @@ -40,10 +42,10 @@ func TestPreSignatureValidation(t *testing.T) { } mockProtector := &mockSlasher.MockProtector{AllowAttestation: false} validator.protector = mockProtector - err := validator.preAttSignValidations(context.Background(), att, validatorPubKey) + err := validator.preAttSignValidations(context.Background(), att, pubKey) require.ErrorContains(t, failedPreAttSignExternalErr, err) mockProtector.AllowAttestation = true - err = validator.preAttSignValidations(context.Background(), att, validatorPubKey) + err = validator.preAttSignValidations(context.Background(), att, pubKey) require.NoError(t, err, "Expected allowed attestation not to throw error") } @@ -54,7 +56,7 @@ func TestPreSignatureValidation_NilLocal(t *testing.T) { } reset := featureconfig.InitWithReset(config) defer reset() - validator, _, finish := setup(t) + validator, _, _, finish := setup(t) defer finish() att := ðpb.IndexedAttestation{ AttestingIndices: []uint64{1, 2}, @@ -84,8 +86,10 @@ func TestPostSignatureUpdate(t *testing.T) { } reset := featureconfig.InitWithReset(config) defer reset() - validator, _, finish := setup(t) + validator, _, validatorKey, finish := setup(t) defer finish() + pubKey := [48]byte{} + copy(pubKey[:], validatorKey.PublicKey().Marshal()) att := ðpb.IndexedAttestation{ AttestingIndices: []uint64{1, 2}, Data: ðpb.AttestationData{ @@ -104,10 +108,10 @@ func TestPostSignatureUpdate(t *testing.T) { } mockProtector := &mockSlasher.MockProtector{AllowAttestation: false} validator.protector = mockProtector - err := validator.postAttSignUpdate(context.Background(), att, validatorPubKey) + err := validator.postAttSignUpdate(context.Background(), att, pubKey) require.ErrorContains(t, failedPostAttSignExternalErr, err, "Expected error on post signature update is detected as slashable") mockProtector.AllowAttestation = true - err = validator.postAttSignUpdate(context.Background(), att, validatorPubKey) + err = validator.postAttSignUpdate(context.Background(), att, pubKey) require.NoError(t, err, "Expected allowed attestation not to throw error") } @@ -118,7 +122,7 @@ func TestPostSignatureUpdate_NilLocal(t *testing.T) { } reset := featureconfig.InitWithReset(config) defer reset() - validator, _, finish := setup(t) + validator, _, _, finish := setup(t) defer finish() att := ðpb.IndexedAttestation{ AttestingIndices: []uint64{1, 2}, diff --git a/validator/client/attest_test.go b/validator/client/attest_test.go index a8493b00fc4c..f4f6849c9701 100644 --- a/validator/client/attest_test.go +++ b/validator/client/attest_test.go @@ -12,6 +12,7 @@ import ( ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1" "github.com/prysmaticlabs/go-bitfield" "github.com/prysmaticlabs/prysm/beacon-chain/core/helpers" + validatorpb "github.com/prysmaticlabs/prysm/proto/validator/accounts/v2" "github.com/prysmaticlabs/prysm/shared/bytesutil" "github.com/prysmaticlabs/prysm/shared/featureconfig" "github.com/prysmaticlabs/prysm/shared/testutil/assert" @@ -23,38 +24,42 @@ import ( func TestRequestAttestation_ValidatorDutiesRequestFailure(t *testing.T) { hook := logTest.NewGlobal() - validator, _, finish := setup(t) + validator, _, validatorKey, finish := setup(t) validator.duties = ðpb.DutiesResponse{Duties: []*ethpb.DutiesResponse_Duty{}} defer finish() - validator.SubmitAttestation(context.Background(), 30, validatorPubKey) + pubKey := [48]byte{} + copy(pubKey[:], validatorKey.PublicKey().Marshal()) + validator.SubmitAttestation(context.Background(), 30, pubKey) require.LogsContain(t, hook, "Could not fetch validator assignment") } func TestAttestToBlockHead_SubmitAttestation_EmptyCommittee(t *testing.T) { hook := logTest.NewGlobal() - validator, _, finish := setup(t) + validator, _, validatorKey, finish := setup(t) defer finish() + pubKey := [48]byte{} + copy(pubKey[:], validatorKey.PublicKey().Marshal()) validator.duties = ðpb.DutiesResponse{Duties: []*ethpb.DutiesResponse_Duty{ { - PublicKey: validatorKey.PublicKey.Marshal(), + PublicKey: validatorKey.PublicKey().Marshal(), CommitteeIndex: 0, Committee: make([]uint64, 0), ValidatorIndex: 0, }}} - validator.SubmitAttestation(context.Background(), 0, validatorPubKey) + validator.SubmitAttestation(context.Background(), 0, pubKey) require.LogsContain(t, hook, "Empty committee") } func TestAttestToBlockHead_SubmitAttestation_RequestFailure(t *testing.T) { hook := logTest.NewGlobal() - validator, m, finish := setup(t) + validator, m, validatorKey, finish := setup(t) defer finish() validator.duties = ðpb.DutiesResponse{Duties: []*ethpb.DutiesResponse_Duty{ { - PublicKey: validatorKey.PublicKey.Marshal(), + PublicKey: validatorKey.PublicKey().Marshal(), CommitteeIndex: 5, Committee: make([]uint64, 111), ValidatorIndex: 0, @@ -76,7 +81,9 @@ func TestAttestToBlockHead_SubmitAttestation_RequestFailure(t *testing.T) { gomock.AssignableToTypeOf(ðpb.Attestation{}), ).Return(nil, errors.New("something went wrong")) - validator.SubmitAttestation(context.Background(), 30, validatorPubKey) + pubKey := [48]byte{} + copy(pubKey[:], validatorKey.PublicKey().Marshal()) + validator.SubmitAttestation(context.Background(), 30, pubKey) require.LogsContain(t, hook, "Could not submit attestation to beacon node") } @@ -86,14 +93,16 @@ func TestAttestToBlockHead_AttestsCorrectly(t *testing.T) { } reset := featureconfig.InitWithReset(config) defer reset() - validator, m, finish := setup(t) + validator, m, validatorKey, finish := setup(t) defer finish() hook := logTest.NewGlobal() validatorIndex := uint64(7) committee := []uint64{0, 3, 4, 2, validatorIndex, 6, 8, 9, 10} + pubKey := [48]byte{} + copy(pubKey[:], validatorKey.PublicKey().Marshal()) validator.duties = ðpb.DutiesResponse{Duties: []*ethpb.DutiesResponse_Duty{ { - PublicKey: validatorKey.PublicKey.Marshal(), + PublicKey: validatorKey.PublicKey().Marshal(), CommitteeIndex: 5, Committee: committee, ValidatorIndex: validatorIndex, @@ -125,7 +134,7 @@ func TestAttestToBlockHead_AttestsCorrectly(t *testing.T) { generatedAttestation = att }).Return(ðpb.AttestResponse{}, nil /* error */) - validator.SubmitAttestation(context.Background(), 30, validatorPubKey) + validator.SubmitAttestation(context.Background(), 30, pubKey) aggregationBitfield := bitfield.NewBitlist(uint64(len(committee))) aggregationBitfield.SetBitAt(4, true) @@ -142,7 +151,10 @@ func TestAttestToBlockHead_AttestsCorrectly(t *testing.T) { root, err := helpers.ComputeSigningRoot(expectedAttestation.Data, make([]byte, 32)) require.NoError(t, err) - sig, err := validator.keyManager.Sign(context.Background(), validatorPubKey, root) + sig, err := validator.keyManagerV2.Sign(context.Background(), &validatorpb.SignRequest{ + PublicKey: validatorKey.PublicKey().Marshal(), + SigningRoot: root[:], + }) require.NoError(t, err) expectedAttestation.Signature = sig.Marshal() if !reflect.DeepEqual(generatedAttestation, expectedAttestation) { @@ -160,13 +172,15 @@ func TestAttestToBlockHead_BlocksDoubleAtt(t *testing.T) { reset := featureconfig.InitWithReset(config) defer reset() hook := logTest.NewGlobal() - validator, m, finish := setup(t) + validator, m, validatorKey, finish := setup(t) defer finish() validatorIndex := uint64(7) committee := []uint64{0, 3, 4, 2, validatorIndex, 6, 8, 9, 10} + pubKey := [48]byte{} + copy(pubKey[:], validatorKey.PublicKey().Marshal()) validator.duties = ðpb.DutiesResponse{Duties: []*ethpb.DutiesResponse_Duty{ { - PublicKey: validatorKey.PublicKey.Marshal(), + PublicKey: validatorKey.PublicKey().Marshal(), CommitteeIndex: 5, Committee: committee, ValidatorIndex: validatorIndex, @@ -194,8 +208,8 @@ func TestAttestToBlockHead_BlocksDoubleAtt(t *testing.T) { gomock.AssignableToTypeOf(ðpb.Attestation{}), ).Return(ðpb.AttestResponse{AttestationDataRoot: make([]byte, 32)}, nil /* error */) - validator.SubmitAttestation(context.Background(), 30, validatorPubKey) - validator.SubmitAttestation(context.Background(), 30, validatorPubKey) + validator.SubmitAttestation(context.Background(), 30, pubKey) + validator.SubmitAttestation(context.Background(), 30, pubKey) require.LogsContain(t, hook, failedPreAttSignLocalErr) } @@ -206,13 +220,15 @@ func TestAttestToBlockHead_BlocksSurroundAtt(t *testing.T) { reset := featureconfig.InitWithReset(config) defer reset() hook := logTest.NewGlobal() - validator, m, finish := setup(t) + validator, m, validatorKey, finish := setup(t) defer finish() validatorIndex := uint64(7) committee := []uint64{0, 3, 4, 2, validatorIndex, 6, 8, 9, 10} + pubKey := [48]byte{} + copy(pubKey[:], validatorKey.PublicKey().Marshal()) validator.duties = ðpb.DutiesResponse{Duties: []*ethpb.DutiesResponse_Duty{ { - PublicKey: validatorKey.PublicKey.Marshal(), + PublicKey: validatorKey.PublicKey().Marshal(), CommitteeIndex: 5, Committee: committee, ValidatorIndex: validatorIndex, @@ -241,8 +257,8 @@ func TestAttestToBlockHead_BlocksSurroundAtt(t *testing.T) { gomock.AssignableToTypeOf(ðpb.Attestation{}), ).Return(ðpb.AttestResponse{}, nil /* error */) - validator.SubmitAttestation(context.Background(), 30, validatorPubKey) - validator.SubmitAttestation(context.Background(), 30, validatorPubKey) + validator.SubmitAttestation(context.Background(), 30, pubKey) + validator.SubmitAttestation(context.Background(), 30, pubKey) require.LogsContain(t, hook, failedPreAttSignLocalErr) } @@ -253,13 +269,15 @@ func TestAttestToBlockHead_BlocksSurroundedAtt(t *testing.T) { reset := featureconfig.InitWithReset(config) defer reset() hook := logTest.NewGlobal() - validator, m, finish := setup(t) + validator, m, validatorKey, finish := setup(t) defer finish() validatorIndex := uint64(7) + pubKey := [48]byte{} + copy(pubKey[:], validatorKey.PublicKey().Marshal()) committee := []uint64{0, 3, 4, 2, validatorIndex, 6, 8, 9, 10} validator.duties = ðpb.DutiesResponse{Duties: []*ethpb.DutiesResponse_Duty{ { - PublicKey: validatorKey.PublicKey.Marshal(), + PublicKey: validatorKey.PublicKey().Marshal(), CommitteeIndex: 5, Committee: committee, ValidatorIndex: validatorIndex, @@ -288,7 +306,7 @@ func TestAttestToBlockHead_BlocksSurroundedAtt(t *testing.T) { gomock.AssignableToTypeOf(ðpb.Attestation{}), ).Return(ðpb.AttestResponse{}, nil /* error */) - validator.SubmitAttestation(context.Background(), 30, validatorPubKey) + validator.SubmitAttestation(context.Background(), 30, pubKey) require.LogsDoNotContain(t, hook, failedPreAttSignLocalErr) m.validatorClient.EXPECT().GetAttestationData( @@ -300,14 +318,16 @@ func TestAttestToBlockHead_BlocksSurroundedAtt(t *testing.T) { Source: ðpb.Checkpoint{Root: bytesutil.PadTo([]byte("C"), 32), Epoch: 1}, }, nil) - validator.SubmitAttestation(context.Background(), 30, validatorPubKey) + validator.SubmitAttestation(context.Background(), 30, pubKey) require.LogsContain(t, hook, failedPreAttSignLocalErr) } func TestAttestToBlockHead_DoesNotAttestBeforeDelay(t *testing.T) { - validator, m, finish := setup(t) + validator, m, validatorKey, finish := setup(t) defer finish() + pubKey := [48]byte{} + copy(pubKey[:], validatorKey.PublicKey().Marshal()) validator.genesisTime = uint64(timeutils.Now().Unix()) m.validatorClient.EXPECT().GetDuties( gomock.Any(), // ctx @@ -326,12 +346,12 @@ func TestAttestToBlockHead_DoesNotAttestBeforeDelay(t *testing.T) { ).Return(ðpb.AttestResponse{}, nil /* error */).Times(0) timer := time.NewTimer(1 * time.Second) - go validator.SubmitAttestation(context.Background(), 0, validatorPubKey) + go validator.SubmitAttestation(context.Background(), 0, pubKey) <-timer.C } func TestAttestToBlockHead_DoesAttestAfterDelay(t *testing.T) { - validator, m, finish := setup(t) + validator, m, validatorKey, finish := setup(t) defer finish() var wg sync.WaitGroup @@ -341,9 +361,11 @@ func TestAttestToBlockHead_DoesAttestAfterDelay(t *testing.T) { validator.genesisTime = uint64(timeutils.Now().Unix()) validatorIndex := uint64(5) committee := []uint64{0, 3, 4, 2, validatorIndex, 6, 8, 9, 10} + pubKey := [48]byte{} + copy(pubKey[:], validatorKey.PublicKey().Marshal()) validator.duties = ðpb.DutiesResponse{Duties: []*ethpb.DutiesResponse_Duty{ { - PublicKey: validatorKey.PublicKey.Marshal(), + PublicKey: validatorKey.PublicKey().Marshal(), CommitteeIndex: 5, Committee: committee, ValidatorIndex: validatorIndex, @@ -370,17 +392,19 @@ func TestAttestToBlockHead_DoesAttestAfterDelay(t *testing.T) { gomock.Any(), ).Return(ðpb.AttestResponse{}, nil).Times(1) - validator.SubmitAttestation(context.Background(), 0, validatorPubKey) + validator.SubmitAttestation(context.Background(), 0, pubKey) } func TestAttestToBlockHead_CorrectBitfieldLength(t *testing.T) { - validator, m, finish := setup(t) + validator, m, validatorKey, finish := setup(t) defer finish() validatorIndex := uint64(2) committee := []uint64{0, 3, 4, 2, validatorIndex, 6, 8, 9, 10} + pubKey := [48]byte{} + copy(pubKey[:], validatorKey.PublicKey().Marshal()) validator.duties = ðpb.DutiesResponse{Duties: []*ethpb.DutiesResponse_Duty{ { - PublicKey: validatorKey.PublicKey.Marshal(), + PublicKey: validatorKey.PublicKey().Marshal(), CommitteeIndex: 5, Committee: committee, ValidatorIndex: validatorIndex, @@ -407,7 +431,7 @@ func TestAttestToBlockHead_CorrectBitfieldLength(t *testing.T) { generatedAttestation = att }).Return(ðpb.AttestResponse{}, nil /* error */) - validator.SubmitAttestation(context.Background(), 30, validatorPubKey) + validator.SubmitAttestation(context.Background(), 30, pubKey) assert.Equal(t, 2, len(generatedAttestation.AggregationBits)) } diff --git a/validator/client/metrics.go b/validator/client/metrics.go index ded741f638c4..8fdc5d82197a 100644 --- a/validator/client/metrics.go +++ b/validator/client/metrics.go @@ -8,7 +8,6 @@ import ( "github.com/prometheus/client_golang/prometheus/promauto" ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1" "github.com/prysmaticlabs/prysm/shared/bytesutil" - "github.com/prysmaticlabs/prysm/shared/featureconfig" "github.com/prysmaticlabs/prysm/shared/params" "github.com/sirupsen/logrus" ) @@ -133,11 +132,7 @@ func (v *validator) LogValidatorGainsAndLosses(ctx context.Context, slot uint64) var pks [][48]byte var err error - if featureconfig.Get().EnableAccountsV2 { - pks, err = v.keyManagerV2.FetchValidatingPublicKeys(ctx) - } else { - pks, err = v.keyManager.FetchValidatingKeys() - } + pks, err = v.keyManagerV2.FetchValidatingPublicKeys(ctx) if err != nil { return err } diff --git a/validator/client/propose.go b/validator/client/propose.go index 50ef63780d69..78812edb912a 100644 --- a/validator/client/propose.go +++ b/validator/client/propose.go @@ -12,10 +12,8 @@ import ( validatorpb "github.com/prysmaticlabs/prysm/proto/validator/accounts/v2" "github.com/prysmaticlabs/prysm/shared/bls" "github.com/prysmaticlabs/prysm/shared/bytesutil" - "github.com/prysmaticlabs/prysm/shared/featureconfig" "github.com/prysmaticlabs/prysm/shared/params" "github.com/prysmaticlabs/prysm/shared/timeutils" - km "github.com/prysmaticlabs/prysm/validator/keymanager/v1" "github.com/sirupsen/logrus" "go.opencensus.io/trace" ) @@ -175,27 +173,19 @@ func (v *validator) signRandaoReveal(ctx context.Context, pubKey [48]byte, epoch } var randaoReveal bls.Signature - if featureconfig.Get().EnableAccountsV2 { - root, err := helpers.ComputeSigningRoot(epoch, domain.SignatureDomain) - if err != nil { - return nil, err - } - randaoReveal, err = v.keyManagerV2.Sign(ctx, &validatorpb.SignRequest{ - PublicKey: pubKey[:], - SigningRoot: root[:], - SignatureDomain: domain.SignatureDomain, - Object: &validatorpb.SignRequest_Epoch{Epoch: epoch}, - }) - if err != nil { - return nil, err - } - } else { - randaoReveal, err = v.signObject(ctx, pubKey, epoch, domain.SignatureDomain) - if err != nil { - return nil, errors.Wrap(err, "could not sign reveal") - } + root, err := helpers.ComputeSigningRoot(epoch, domain.SignatureDomain) + if err != nil { + return nil, err + } + randaoReveal, err = v.keyManagerV2.Sign(ctx, &validatorpb.SignRequest{ + PublicKey: pubKey[:], + SigningRoot: root[:], + SignatureDomain: domain.SignatureDomain, + Object: &validatorpb.SignRequest_Epoch{Epoch: epoch}, + }) + if err != nil { + return nil, err } - return randaoReveal.Marshal(), nil } @@ -210,47 +200,18 @@ func (v *validator) signBlock(ctx context.Context, pubKey [48]byte, epoch uint64 } var sig bls.Signature - if featureconfig.Get().EnableAccountsV2 { - blockRoot, err := helpers.ComputeSigningRoot(b, domain.SignatureDomain) - if err != nil { - return nil, errors.Wrap(err, signingRootErr) - } - sig, err = v.keyManagerV2.Sign(ctx, &validatorpb.SignRequest{ - PublicKey: pubKey[:], - SigningRoot: blockRoot[:], - SignatureDomain: domain.SignatureDomain, - Object: &validatorpb.SignRequest_Block{Block: b}, - }) - if err != nil { - return nil, errors.Wrap(err, "could not sign block proposal") - } - return sig.Marshal(), nil + blockRoot, err := helpers.ComputeSigningRoot(b, domain.SignatureDomain) + if err != nil { + return nil, errors.Wrap(err, signingRootErr) } - if protectingKeymanager, supported := v.keyManager.(km.ProtectingKeyManager); supported { - bodyRoot, err := b.Body.HashTreeRoot() - if err != nil { - return nil, errors.Wrap(err, signingRootErr) - } - blockHeader := ðpb.BeaconBlockHeader{ - Slot: b.Slot, - ProposerIndex: b.ProposerIndex, - StateRoot: b.StateRoot, - ParentRoot: b.ParentRoot, - BodyRoot: bodyRoot[:], - } - sig, err = protectingKeymanager.SignProposal(pubKey, bytesutil.ToBytes32(domain.SignatureDomain), blockHeader) - if err != nil { - return nil, errors.Wrap(err, "could not sign block proposal") - } - } else { - blockRoot, err := helpers.ComputeSigningRoot(b, domain.SignatureDomain) - if err != nil { - return nil, errors.Wrap(err, signingRootErr) - } - sig, err = v.keyManager.Sign(ctx, pubKey, blockRoot) - if err != nil { - return nil, errors.Wrap(err, "could not sign block proposal") - } + sig, err = v.keyManagerV2.Sign(ctx, &validatorpb.SignRequest{ + PublicKey: pubKey[:], + SigningRoot: blockRoot[:], + SignatureDomain: domain.SignatureDomain, + Object: &validatorpb.SignRequest_Block{Block: b}, + }) + if err != nil { + return nil, errors.Wrap(err, "could not sign block proposal") } return sig.Marshal(), nil } diff --git a/validator/client/propose_protect_test.go b/validator/client/propose_protect_test.go index a38e7427ef94..4b887dc6a26d 100644 --- a/validator/client/propose_protect_test.go +++ b/validator/client/propose_protect_test.go @@ -17,8 +17,10 @@ func TestPreBlockSignValidation(t *testing.T) { } reset := featureconfig.InitWithReset(config) defer reset() - validator, _, finish := setup(t) + validator, _, validatorKey, finish := setup(t) defer finish() + pubKey := [48]byte{} + copy(pubKey[:], validatorKey.PublicKey().Marshal()) block := ðpb.BeaconBlock{ Slot: 10, @@ -26,10 +28,10 @@ func TestPreBlockSignValidation(t *testing.T) { } mockProtector := &mockSlasher.MockProtector{AllowBlock: false} validator.protector = mockProtector - err := validator.preBlockSignValidations(context.Background(), validatorPubKey, block) + err := validator.preBlockSignValidations(context.Background(), pubKey, block) require.ErrorContains(t, failedPreBlockSignExternalErr, err) mockProtector.AllowBlock = true - err = validator.preBlockSignValidations(context.Background(), validatorPubKey, block) + err = validator.preBlockSignValidations(context.Background(), pubKey, block) require.NoError(t, err, "Expected allowed attestation not to throw error") } @@ -40,8 +42,10 @@ func TestPostBlockSignUpdate(t *testing.T) { } reset := featureconfig.InitWithReset(config) defer reset() - validator, _, finish := setup(t) + validator, _, validatorKey, finish := setup(t) defer finish() + pubKey := [48]byte{} + copy(pubKey[:], validatorKey.PublicKey().Marshal()) block := ðpb.SignedBeaconBlock{ Block: ðpb.BeaconBlock{ @@ -51,9 +55,9 @@ func TestPostBlockSignUpdate(t *testing.T) { } mockProtector := &mockSlasher.MockProtector{AllowBlock: false} validator.protector = mockProtector - err := validator.postBlockSignUpdate(context.Background(), validatorPubKey, block) + err := validator.postBlockSignUpdate(context.Background(), pubKey, block) require.ErrorContains(t, failedPostBlockSignErr, err, "Expected error when post signature update is detected as slashable") mockProtector.AllowBlock = true - err = validator.postBlockSignUpdate(context.Background(), validatorPubKey, block) + err = validator.postBlockSignUpdate(context.Background(), pubKey, block) require.NoError(t, err, "Expected allowed attestation not to throw error") } diff --git a/validator/client/propose_test.go b/validator/client/propose_test.go index 14c24a32e70a..90d71c0f689e 100644 --- a/validator/client/propose_test.go +++ b/validator/client/propose_test.go @@ -47,8 +47,11 @@ func (m mockSignature) Copy() bls.Signature { return m } -func setup(t *testing.T) (*validator, *mocks, func()) { - valDB := testing2.SetupDB(t, [][48]byte{validatorPubKey}) +func setup(t *testing.T) (*validator, *mocks, bls.SecretKey, func()) { + validatorKey := bls.RandKey() + pubKey := [48]byte{} + copy(pubKey[:], validatorKey.PublicKey().Marshal()) + valDB := testing2.SetupDB(t, [][48]byte{pubKey}) ctrl := gomock.NewController(t) m := &mocks{ validatorClient: mock.NewMockBeaconNodeValidatorClient(ctrl), @@ -66,62 +69,75 @@ func setup(t *testing.T) (*validator, *mocks, func()) { TargetToSource: cleanMap, } attHistoryByPubKey := make(map[[48]byte]*slashpb.AttestationHistory) - attHistoryByPubKey[validatorPubKey] = clean - + attHistoryByPubKey[pubKey] = clean + copy(pubKey[:], validatorKey.PublicKey().Marshal()) + km := &mockKeymanager{ + keysMap: map[[48]byte]bls.SecretKey{ + pubKey: validatorKey, + }, + } validator := &validator{ db: valDB, + keyManagerV2: km, validatorClient: m.validatorClient, - keyManager: testKeyManager, graffiti: []byte{}, attLogs: make(map[[32]byte]*attSubmitted), aggregatedSlotCommitteeIDCache: aggregatedSlotCommitteeIDCache, attesterHistoryByPubKey: attHistoryByPubKey, } - return validator, m, ctrl.Finish + return validator, m, validatorKey, ctrl.Finish } func TestProposeBlock_DoesNotProposeGenesisBlock(t *testing.T) { hook := logTest.NewGlobal() - validator, _, finish := setup(t) + validator, _, validatorKey, finish := setup(t) defer finish() - validator.ProposeBlock(context.Background(), 0, validatorPubKey) + pubKey := [48]byte{} + copy(pubKey[:], validatorKey.PublicKey().Marshal()) + validator.ProposeBlock(context.Background(), 0, pubKey) require.LogsContain(t, hook, "Assigned to genesis slot, skipping proposal") } func TestProposeBlock_DomainDataFailed(t *testing.T) { hook := logTest.NewGlobal() - validator, m, finish := setup(t) + validator, m, validatorKey, finish := setup(t) defer finish() + pubKey := [48]byte{} + copy(pubKey[:], validatorKey.PublicKey().Marshal()) m.validatorClient.EXPECT().DomainData( gomock.Any(), // ctx gomock.Any(), // epoch ).Return(nil /*response*/, errors.New("uh oh")) - validator.ProposeBlock(context.Background(), 1, validatorPubKey) + validator.ProposeBlock(context.Background(), 1, pubKey) require.LogsContain(t, hook, "Failed to sign randao reveal") } func TestProposeBlock_DomainDataIsNil(t *testing.T) { hook := logTest.NewGlobal() - validator, m, finish := setup(t) + validator, m, validatorKey, finish := setup(t) defer finish() + pubKey := [48]byte{} + copy(pubKey[:], validatorKey.PublicKey().Marshal()) m.validatorClient.EXPECT().DomainData( gomock.Any(), // ctx gomock.Any(), // epoch ).Return(nil /*response*/, nil) - validator.ProposeBlock(context.Background(), 1, validatorPubKey) + validator.ProposeBlock(context.Background(), 1, pubKey) require.LogsContain(t, hook, domainDataErr) } func TestProposeBlock_RequestBlockFailed(t *testing.T) { hook := logTest.NewGlobal() - validator, m, finish := setup(t) + validator, m, validatorKey, finish := setup(t) defer finish() + pubKey := [48]byte{} + copy(pubKey[:], validatorKey.PublicKey().Marshal()) m.validatorClient.EXPECT().DomainData( gomock.Any(), // ctx @@ -133,14 +149,16 @@ func TestProposeBlock_RequestBlockFailed(t *testing.T) { gomock.Any(), // block request ).Return(nil /*response*/, errors.New("uh oh")) - validator.ProposeBlock(context.Background(), 1, validatorPubKey) + validator.ProposeBlock(context.Background(), 1, pubKey) require.LogsContain(t, hook, "Failed to request block from beacon node") } func TestProposeBlock_ProposeBlockFailed(t *testing.T) { hook := logTest.NewGlobal() - validator, m, finish := setup(t) + validator, m, validatorKey, finish := setup(t) defer finish() + pubKey := [48]byte{} + copy(pubKey[:], validatorKey.PublicKey().Marshal()) m.validatorClient.EXPECT().DomainData( gomock.Any(), // ctx @@ -162,7 +180,7 @@ func TestProposeBlock_ProposeBlockFailed(t *testing.T) { gomock.AssignableToTypeOf(ðpb.SignedBeaconBlock{}), ).Return(nil /*response*/, errors.New("uh oh")) - validator.ProposeBlock(context.Background(), 1, validatorPubKey) + validator.ProposeBlock(context.Background(), 1, pubKey) require.LogsContain(t, hook, "Failed to propose block") } @@ -173,8 +191,10 @@ func TestProposeBlock_BlocksDoubleProposal(t *testing.T) { reset := featureconfig.InitWithReset(cfg) defer reset() hook := logTest.NewGlobal() - validator, m, finish := setup(t) + validator, m, validatorKey, finish := setup(t) defer finish() + pubKey := [48]byte{} + copy(pubKey[:], validatorKey.PublicKey().Marshal()) m.validatorClient.EXPECT().DomainData( gomock.Any(), // ctx @@ -197,10 +217,10 @@ func TestProposeBlock_BlocksDoubleProposal(t *testing.T) { ).Return(ðpb.ProposeResponse{BlockRoot: make([]byte, 32)}, nil /*error*/) slot := params.BeaconConfig().SlotsPerEpoch*5 + 2 - validator.ProposeBlock(context.Background(), slot, validatorPubKey) + validator.ProposeBlock(context.Background(), slot, pubKey) require.LogsDoNotContain(t, hook, failedPreBlockSignLocalErr) - validator.ProposeBlock(context.Background(), slot, validatorPubKey) + validator.ProposeBlock(context.Background(), slot, pubKey) require.LogsContain(t, hook, failedPreBlockSignLocalErr) } @@ -211,8 +231,10 @@ func TestProposeBlock_BlocksDoubleProposal_After54KEpochs(t *testing.T) { reset := featureconfig.InitWithReset(cfg) defer reset() hook := logTest.NewGlobal() - validator, m, finish := setup(t) + validator, m, validatorKey, finish := setup(t) defer finish() + pubKey := [48]byte{} + copy(pubKey[:], validatorKey.PublicKey().Marshal()) m.validatorClient.EXPECT().DomainData( gomock.Any(), // ctx @@ -235,10 +257,10 @@ func TestProposeBlock_BlocksDoubleProposal_After54KEpochs(t *testing.T) { ).Return(ðpb.ProposeResponse{BlockRoot: make([]byte, 32)}, nil /*error*/) farFuture := (params.BeaconConfig().WeakSubjectivityPeriod + 9) * params.BeaconConfig().SlotsPerEpoch - validator.ProposeBlock(context.Background(), farFuture, validatorPubKey) + validator.ProposeBlock(context.Background(), farFuture, pubKey) require.LogsDoNotContain(t, hook, failedPreBlockSignLocalErr) - validator.ProposeBlock(context.Background(), farFuture, validatorPubKey) + validator.ProposeBlock(context.Background(), farFuture, pubKey) require.LogsContain(t, hook, failedPreBlockSignLocalErr) } @@ -249,8 +271,10 @@ func TestProposeBlock_AllowsPastProposals(t *testing.T) { reset := featureconfig.InitWithReset(cfg) defer reset() hook := logTest.NewGlobal() - validator, m, finish := setup(t) + validator, m, validatorKey, finish := setup(t) defer finish() + pubKey := [48]byte{} + copy(pubKey[:], validatorKey.PublicKey().Marshal()) m.validatorClient.EXPECT().DomainData( gomock.Any(), // ctx @@ -275,7 +299,7 @@ func TestProposeBlock_AllowsPastProposals(t *testing.T) { gomock.AssignableToTypeOf(ðpb.SignedBeaconBlock{}), ).Times(2).Return(ðpb.ProposeResponse{BlockRoot: make([]byte, 32)}, nil /*error*/) - validator.ProposeBlock(context.Background(), farAhead, validatorPubKey) + validator.ProposeBlock(context.Background(), farAhead, pubKey) require.LogsDoNotContain(t, hook, failedPreBlockSignLocalErr) past := (params.BeaconConfig().WeakSubjectivityPeriod - 400) * params.BeaconConfig().SlotsPerEpoch @@ -285,7 +309,7 @@ func TestProposeBlock_AllowsPastProposals(t *testing.T) { gomock.Any(), // ctx gomock.Any(), ).Return(blk2.Block, nil /*err*/) - validator.ProposeBlock(context.Background(), past, validatorPubKey) + validator.ProposeBlock(context.Background(), past, pubKey) require.LogsDoNotContain(t, hook, failedPreBlockSignLocalErr) } @@ -296,8 +320,10 @@ func TestProposeBlock_AllowsSameEpoch(t *testing.T) { reset := featureconfig.InitWithReset(cfg) defer reset() hook := logTest.NewGlobal() - validator, m, finish := setup(t) + validator, m, validatorKey, finish := setup(t) defer finish() + pubKey := [48]byte{} + copy(pubKey[:], validatorKey.PublicKey().Marshal()) m.validatorClient.EXPECT().DomainData( gomock.Any(), // ctx @@ -322,7 +348,6 @@ func TestProposeBlock_AllowsSameEpoch(t *testing.T) { gomock.AssignableToTypeOf(ðpb.SignedBeaconBlock{}), ).Times(2).Return(ðpb.ProposeResponse{BlockRoot: make([]byte, 32)}, nil /*error*/) - pubKey := validatorPubKey validator.ProposeBlock(context.Background(), farAhead, pubKey) require.LogsDoNotContain(t, hook, failedPreBlockSignLocalErr) @@ -338,8 +363,10 @@ func TestProposeBlock_AllowsSameEpoch(t *testing.T) { } func TestProposeBlock_BroadcastsBlock(t *testing.T) { - validator, m, finish := setup(t) + validator, m, validatorKey, finish := setup(t) defer finish() + pubKey := [48]byte{} + copy(pubKey[:], validatorKey.PublicKey().Marshal()) m.validatorClient.EXPECT().DomainData( gomock.Any(), // ctx @@ -361,12 +388,14 @@ func TestProposeBlock_BroadcastsBlock(t *testing.T) { gomock.AssignableToTypeOf(ðpb.SignedBeaconBlock{}), ).Return(ðpb.ProposeResponse{BlockRoot: make([]byte, 32)}, nil /*error*/) - validator.ProposeBlock(context.Background(), 1, validatorPubKey) + validator.ProposeBlock(context.Background(), 1, pubKey) } func TestProposeBlock_BroadcastsBlock_WithGraffiti(t *testing.T) { - validator, m, finish := setup(t) + validator, m, validatorKey, finish := setup(t) defer finish() + pubKey := [48]byte{} + copy(pubKey[:], validatorKey.PublicKey().Marshal()) validator.graffiti = []byte("12345678901234567890123456789012") @@ -397,12 +426,12 @@ func TestProposeBlock_BroadcastsBlock_WithGraffiti(t *testing.T) { return ðpb.ProposeResponse{BlockRoot: make([]byte, 32)}, nil }) - validator.ProposeBlock(context.Background(), 1, validatorPubKey) + validator.ProposeBlock(context.Background(), 1, pubKey) assert.Equal(t, string(validator.graffiti), string(sentBlock.Block.Body.Graffiti)) } func TestProposeExit_ValidatorIndexFailed(t *testing.T) { - _, m, finish := setup(t) + _, m, validatorKey, finish := setup(t) defer finish() m.validatorClient.EXPECT().ValidatorIndex( @@ -410,14 +439,20 @@ func TestProposeExit_ValidatorIndexFailed(t *testing.T) { gomock.Any(), ).Return(nil, errors.New("uh oh")) - err := ProposeExit(context.Background(), m.validatorClient, m.nodeClient, m.signExitFunc, validatorPubKey[:]) + err := ProposeExit( + context.Background(), + m.validatorClient, + m.nodeClient, + m.signExitFunc, + validatorKey.PublicKey().Marshal(), + ) assert.NotNil(t, err) assert.ErrorContains(t, "uh oh", err) assert.ErrorContains(t, "gRPC call to get validator index failed", err) } func TestProposeExit_GetGenesisFailed(t *testing.T) { - _, m, finish := setup(t) + _, m, validatorKey, finish := setup(t) defer finish() m.validatorClient.EXPECT(). @@ -428,14 +463,20 @@ func TestProposeExit_GetGenesisFailed(t *testing.T) { GetGenesis(gomock.Any(), gomock.Any()). Return(nil, errors.New("uh oh")) - err := ProposeExit(context.Background(), m.validatorClient, m.nodeClient, m.signExitFunc, validatorPubKey[:]) + err := ProposeExit( + context.Background(), + m.validatorClient, + m.nodeClient, + m.signExitFunc, + validatorKey.PublicKey().Marshal(), + ) assert.NotNil(t, err) assert.ErrorContains(t, "uh oh", err) assert.ErrorContains(t, "gRPC call to get genesis time failed", err) } func TestProposeExit_DomainDataFailed(t *testing.T) { - _, m, finish := setup(t) + _, m, validatorKey, finish := setup(t) defer finish() m.validatorClient.EXPECT(). @@ -455,7 +496,13 @@ func TestProposeExit_DomainDataFailed(t *testing.T) { DomainData(gomock.Any(), gomock.Any()). Return(nil, errors.New("uh oh")) - err := ProposeExit(context.Background(), m.validatorClient, m.nodeClient, m.signExitFunc, validatorPubKey[:]) + err := ProposeExit( + context.Background(), + m.validatorClient, + m.nodeClient, + m.signExitFunc, + validatorKey.PublicKey().Marshal(), + ) assert.NotNil(t, err) assert.ErrorContains(t, domainDataErr, err) assert.ErrorContains(t, "uh oh", err) @@ -463,7 +510,7 @@ func TestProposeExit_DomainDataFailed(t *testing.T) { } func TestProposeExit_DomainDataIsNil(t *testing.T) { - _, m, finish := setup(t) + _, m, validatorKey, finish := setup(t) defer finish() m.validatorClient.EXPECT(). @@ -483,14 +530,20 @@ func TestProposeExit_DomainDataIsNil(t *testing.T) { DomainData(gomock.Any(), gomock.Any()). Return(nil, nil) - err := ProposeExit(context.Background(), m.validatorClient, m.nodeClient, m.signExitFunc, validatorPubKey[:]) + err := ProposeExit( + context.Background(), + m.validatorClient, + m.nodeClient, + m.signExitFunc, + validatorKey.PublicKey().Marshal(), + ) assert.NotNil(t, err) assert.ErrorContains(t, domainDataErr, err) assert.ErrorContains(t, "failed to sign voluntary exit", err) } func TestProposeBlock_ProposeExitFailed(t *testing.T) { - _, m, finish := setup(t) + _, m, validatorKey, finish := setup(t) defer finish() m.validatorClient.EXPECT(). @@ -514,14 +567,20 @@ func TestProposeBlock_ProposeExitFailed(t *testing.T) { ProposeExit(gomock.Any(), gomock.AssignableToTypeOf(ðpb.SignedVoluntaryExit{})). Return(nil, errors.New("uh oh")) - err := ProposeExit(context.Background(), m.validatorClient, m.nodeClient, m.signExitFunc, validatorPubKey[:]) + err := ProposeExit( + context.Background(), + m.validatorClient, + m.nodeClient, + m.signExitFunc, + validatorKey.PublicKey().Marshal(), + ) assert.NotNil(t, err) assert.ErrorContains(t, "uh oh", err) assert.ErrorContains(t, "failed to propose voluntary exit", err) } func TestProposeExit_BroadcastsBlock(t *testing.T) { - _, m, finish := setup(t) + _, m, validatorKey, finish := setup(t) defer finish() m.validatorClient.EXPECT(). @@ -545,5 +604,11 @@ func TestProposeExit_BroadcastsBlock(t *testing.T) { ProposeExit(gomock.Any(), gomock.AssignableToTypeOf(ðpb.SignedVoluntaryExit{})). Return(ðpb.ProposeExitResponse{}, nil) - assert.NoError(t, ProposeExit(context.Background(), m.validatorClient, m.nodeClient, m.signExitFunc, validatorPubKey[:])) + assert.NoError(t, ProposeExit( + context.Background(), + m.validatorClient, + m.nodeClient, + m.signExitFunc, + validatorKey.PublicKey().Marshal(), + )) } diff --git a/validator/client/service.go b/validator/client/service.go index 08959695ba0b..4a26d753b95b 100644 --- a/validator/client/service.go +++ b/validator/client/service.go @@ -7,7 +7,6 @@ import ( "time" "github.com/dgraph-io/ristretto" - fssz "github.com/ferranbt/fastssz" ptypes "github.com/gogo/protobuf/types" middleware "github.com/grpc-ecosystem/go-grpc-middleware" grpc_retry "github.com/grpc-ecosystem/go-grpc-middleware/retry" @@ -16,17 +15,12 @@ import ( lru "github.com/hashicorp/golang-lru" "github.com/pkg/errors" ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1" - "github.com/prysmaticlabs/go-ssz" - "github.com/prysmaticlabs/prysm/beacon-chain/core/helpers" - "github.com/prysmaticlabs/prysm/shared/bls" "github.com/prysmaticlabs/prysm/shared/bytesutil" "github.com/prysmaticlabs/prysm/shared/event" - "github.com/prysmaticlabs/prysm/shared/featureconfig" "github.com/prysmaticlabs/prysm/shared/grpcutils" "github.com/prysmaticlabs/prysm/shared/params" "github.com/prysmaticlabs/prysm/validator/accounts/v2/wallet" "github.com/prysmaticlabs/prysm/validator/db" - keymanager "github.com/prysmaticlabs/prysm/validator/keymanager/v1" v2 "github.com/prysmaticlabs/prysm/validator/keymanager/v2" "github.com/prysmaticlabs/prysm/validator/keymanager/v2/direct" slashingprotection "github.com/prysmaticlabs/prysm/validator/slashing-protection" @@ -64,7 +58,6 @@ type ValidatorService struct { walletInitializedFeed *event.Feed cancel context.CancelFunc db db.Database - keyManager keymanager.KeyManager dataDir string withCert string endpoint string @@ -90,7 +83,6 @@ type Config struct { Validator Validator ValDB db.Database KeyManagerV2 v2.IKeymanager - KeyManager keymanager.KeyManager GraffitiFlag string CertFlag string DataDir string @@ -108,7 +100,6 @@ func NewValidatorService(ctx context.Context, cfg *Config) (*ValidatorService, e withCert: cfg.CertFlag, dataDir: cfg.DataDir, graffiti: []byte(cfg.GraffitiFlag), - keyManager: cfg.KeyManager, keyManagerV2: cfg.KeyManagerV2, logValidatorBalances: cfg.LogValidatorBalances, emitAccountMetrics: cfg.EmitAccountMetrics, @@ -173,7 +164,6 @@ func (v *ValidatorService) Start() { validatorClient: ethpb.NewBeaconNodeValidatorClient(v.conn), beaconClient: ethpb.NewBeaconChainClient(v.conn), node: ethpb.NewNodeClient(v.conn), - keyManager: v.keyManager, keyManagerV2: v.keyManagerV2, graffiti: v.graffiti, logValidatorBalances: v.logValidatorBalances, @@ -213,40 +203,30 @@ func (v *ValidatorService) Status() error { func (v *ValidatorService) recheckKeys(ctx context.Context) { var validatingKeys [][48]byte var err error - if featureconfig.Get().EnableAccountsV2 { - if v.useWeb { - initializedChan := make(chan *wallet.Wallet) - sub := v.walletInitializedFeed.Subscribe(initializedChan) - cleanup := sub.Unsubscribe - defer cleanup() - w := <-initializedChan - keyManagerV2, err := w.InitializeKeymanager( - ctx, true, /* skipMnemonicConfirm */ - ) - if err != nil { - // log.Fatalf will prevent defer from being called - cleanup() - log.Fatalf("Could not read keymanager for wallet: %v", err) - } - v.keyManagerV2 = keyManagerV2 - } - validatingKeys, err = v.keyManagerV2.FetchValidatingPublicKeys(ctx) - if err != nil { - log.WithError(err).Debug("Could not fetch validating keys") - } - if err := v.db.UpdatePublicKeysBuckets(validatingKeys); err != nil { - log.WithError(err).Debug("Could not update public keys buckets") - } - go recheckValidatingKeysBucket(ctx, v.db, v.keyManagerV2) - } else { - validatingKeys, err = v.keyManager.FetchValidatingKeys() + if v.useWeb { + initializedChan := make(chan *wallet.Wallet) + sub := v.walletInitializedFeed.Subscribe(initializedChan) + cleanup := sub.Unsubscribe + defer cleanup() + w := <-initializedChan + keyManagerV2, err := w.InitializeKeymanager( + ctx, true, /* skipMnemonicConfirm */ + ) if err != nil { - log.WithError(err).Debug("Could not fetch validating keys") - } - if err := v.db.UpdatePublicKeysBuckets(validatingKeys); err != nil { - log.WithError(err).Debug("Could not update public keys buckets") + // log.Fatalf will prevent defer from being called + cleanup() + log.Fatalf("Could not read keymanager for wallet: %v", err) } + v.keyManagerV2 = keyManagerV2 + } + validatingKeys, err = v.keyManagerV2.FetchValidatingPublicKeys(ctx) + if err != nil { + log.WithError(err).Debug("Could not fetch validating keys") } + if err := v.db.UpdatePublicKeysBuckets(validatingKeys); err != nil { + log.WithError(err).Debug("Could not update public keys buckets") + } + go recheckValidatingKeysBucket(ctx, v.db, v.keyManagerV2) for _, key := range validatingKeys { log.WithField( "publicKey", fmt.Sprintf("%#x", bytesutil.Trunc(key[:])), @@ -254,40 +234,6 @@ func (v *ValidatorService) recheckKeys(ctx context.Context) { } } -// signObject signs a generic object, with protection if available. -// This should only be used for accounts v1. -func (v *validator) signObject( - ctx context.Context, - pubKey [48]byte, - object interface{}, - domain []byte, -) (bls.Signature, error) { - if featureconfig.Get().EnableAccountsV2 { - return nil, errors.New("signObject not supported for accounts v2") - } - - if protectingKeymanager, supported := v.keyManager.(keymanager.ProtectingKeyManager); supported { - var root [32]byte - var err error - if v, ok := object.(fssz.HashRoot); ok { - root, err = v.HashTreeRoot() - } else { - root, err = ssz.HashTreeRoot(object) - } - - if err != nil { - return nil, err - } - return protectingKeymanager.SignGeneric(pubKey, root, bytesutil.ToBytes32(domain)) - } - - root, err := helpers.ComputeSigningRoot(object, domain) - if err != nil { - return nil, err - } - return v.keyManager.Sign(ctx, pubKey, root) -} - // ConstructDialOptions constructs a list of grpc dial options func ConstructDialOptions( maxCallRecvMsgSize int, diff --git a/validator/client/service_test.go b/validator/client/service_test.go index 126e092c6d2b..df5ce6c170b2 100644 --- a/validator/client/service_test.go +++ b/validator/client/service_test.go @@ -7,53 +7,13 @@ import ( "time" "github.com/prysmaticlabs/prysm/shared" - "github.com/prysmaticlabs/prysm/shared/bls" - "github.com/prysmaticlabs/prysm/shared/keystore" "github.com/prysmaticlabs/prysm/shared/testutil" "github.com/prysmaticlabs/prysm/shared/testutil/assert" "github.com/prysmaticlabs/prysm/shared/testutil/require" - v1 "github.com/prysmaticlabs/prysm/validator/accounts/v1" - keymanager "github.com/prysmaticlabs/prysm/validator/keymanager/v1" logTest "github.com/sirupsen/logrus/hooks/test" ) var _ shared.Service = (*ValidatorService)(nil) -var validatorKey *keystore.Key -var validatorPubKey [48]byte -var keyMap map[[48]byte]*keystore.Key -var keyMapThreeValidators map[[48]byte]*keystore.Key -var testKeyManager keymanager.KeyManager -var testKeyManagerThreeValidators keymanager.KeyManager - -func keySetup() { - keyMap = make(map[[48]byte]*keystore.Key) - keyMapThreeValidators = make(map[[48]byte]*keystore.Key) - - var err error - validatorKey, err = keystore.NewKey() - if err != nil { - log.WithError(err).Debug("Cannot create key") - } - copy(validatorPubKey[:], validatorKey.PublicKey.Marshal()) - keyMap[validatorPubKey] = validatorKey - - sks := make([]bls.SecretKey, 1) - sks[0] = validatorKey.SecretKey - testKeyManager = keymanager.NewDirect(sks) - - sks = make([]bls.SecretKey, 3) - for i := 0; i < 3; i++ { - vKey, err := keystore.NewKey() - if err != nil { - log.WithError(err).Debug("Cannot create key") - } - var pubKey [48]byte - copy(pubKey[:], vKey.PublicKey.Marshal()) - keyMapThreeValidators[pubKey] = vKey - sks[i] = vKey.SecretKey - } - testKeyManagerThreeValidators = keymanager.NewDirect(sks) -} func TestMain(m *testing.M) { dir := testutil.TempDir() + "/keystore1" @@ -63,10 +23,6 @@ func TestMain(m *testing.M) { } } defer cleanup() - if err := v1.NewValidatorAccount(dir, "1234"); err != nil { - log.WithError(err).Debug("Cannot create validator account") - } - keySetup() code := m.Run() // os.Exit will prevent defer from being called cleanup() @@ -95,11 +51,10 @@ func TestLifecycle(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) cancel() validatorService := &ValidatorService{ - ctx: ctx, - cancel: cancel, - endpoint: "merkle tries", - withCert: "alice.crt", - keyManager: keymanager.NewDirect(nil), + ctx: ctx, + cancel: cancel, + endpoint: "merkle tries", + withCert: "alice.crt", } validatorService.Start() require.NoError(t, validatorService.Stop(), "Could not stop service") @@ -112,10 +67,9 @@ func TestLifecycle_Insecure(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) cancel() validatorService := &ValidatorService{ - ctx: ctx, - cancel: cancel, - endpoint: "merkle tries", - keyManager: keymanager.NewDirect(nil), + ctx: ctx, + cancel: cancel, + endpoint: "merkle tries", } validatorService.Start() require.LogsContain(t, hook, "You are using an insecure gRPC connection") diff --git a/validator/client/validator.go b/validator/client/validator.go index b52689c65776..c6c4c1b29146 100644 --- a/validator/client/validator.go +++ b/validator/client/validator.go @@ -29,7 +29,6 @@ import ( "github.com/prysmaticlabs/prysm/shared/slotutil" "github.com/prysmaticlabs/prysm/validator/accounts/v2/wallet" vdb "github.com/prysmaticlabs/prysm/validator/db" - keymanager "github.com/prysmaticlabs/prysm/validator/keymanager/v1" v2keymanager "github.com/prysmaticlabs/prysm/validator/keymanager/v2" slashingprotection "github.com/prysmaticlabs/prysm/validator/slashing-protection" "github.com/sirupsen/logrus" @@ -69,7 +68,6 @@ type validator struct { duties *ethpb.DutiesResponse startBalances map[[48]byte]uint64 attLogs map[[32]byte]*attSubmitted - keyManager keymanager.KeyManager node ethpb.NodeClient keyManagerV2 v2keymanager.IKeymanager beaconClient ethpb.BeaconChainClient @@ -243,13 +241,7 @@ func (v *validator) WaitForActivation(ctx context.Context) error { ctx, span := trace.StartSpan(ctx, "validator.WaitForActivation") defer span.End() - var validatingKeys [][48]byte - var err error - if featureconfig.Get().EnableAccountsV2 { - validatingKeys, err = v.keyManagerV2.FetchValidatingPublicKeys(ctx) - } else { - validatingKeys, err = v.keyManager.FetchValidatingKeys() - } + validatingKeys, err := v.keyManagerV2.FetchValidatingPublicKeys(ctx) if err != nil { return errors.Wrap(err, "could not fetch validating keys") } @@ -389,12 +381,7 @@ func (v *validator) UpdateDuties(ctx context.Context, slot uint64) error { ctx, span := trace.StartSpan(ctx, "validator.UpdateAssignments") defer span.End() - var validatingKeys [][48]byte - if featureconfig.Get().EnableAccountsV2 { - validatingKeys, err = v.keyManagerV2.FetchValidatingPublicKeys(ctx) - } else { - validatingKeys, err = v.keyManager.FetchValidatingKeys() - } + validatingKeys, err := v.keyManagerV2.FetchValidatingPublicKeys(ctx) if err != nil { return err } diff --git a/validator/client/validator_test.go b/validator/client/validator_test.go index 18f1370b7301..296b1f026392 100644 --- a/validator/client/validator_test.go +++ b/validator/client/validator_test.go @@ -4,6 +4,7 @@ import ( "context" "errors" "io/ioutil" + "sync" "testing" "time" @@ -11,6 +12,7 @@ import ( "github.com/golang/mock/gomock" ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1" slashpb "github.com/prysmaticlabs/prysm/proto/slashing" + validatorpb "github.com/prysmaticlabs/prysm/proto/validator/accounts/v2" "github.com/prysmaticlabs/prysm/shared/bls" "github.com/prysmaticlabs/prysm/shared/bytesutil" "github.com/prysmaticlabs/prysm/shared/mock" @@ -18,7 +20,6 @@ import ( "github.com/prysmaticlabs/prysm/shared/testutil/assert" "github.com/prysmaticlabs/prysm/shared/testutil/require" dbTest "github.com/prysmaticlabs/prysm/validator/db/testing" - keymanager "github.com/prysmaticlabs/prysm/validator/keymanager/v1" "github.com/sirupsen/logrus" logTest "github.com/sirupsen/logrus/hooks/test" ) @@ -32,14 +33,30 @@ var _ Validator = (*validator)(nil) const cancelledCtx = "context has been canceled" -func publicKeys(t *testing.T, km keymanager.KeyManager) [][]byte { - keys, err := km.FetchValidatingKeys() - assert.NoError(t, err, "Cannot fetch validating keys") - res := make([][]byte, len(keys)) - for i := range keys { - res[i] = keys[i][:] +type mockKeymanager struct { + lock sync.RWMutex + keysMap map[[48]byte]bls.SecretKey +} + +func (m *mockKeymanager) FetchValidatingPublicKeys(ctx context.Context) ([][48]byte, error) { + m.lock.RLock() + defer m.lock.RUnlock() + keys := make([][48]byte, 0) + for pubKey := range m.keysMap { + keys = append(keys, pubKey) + } + return keys, nil +} + +func (m *mockKeymanager) Sign(ctx context.Context, req *validatorpb.SignRequest) (bls.Signature, error) { + pubKey := [48]byte{} + copy(pubKey[:], req.PublicKey) + privKey, ok := m.keysMap[pubKey] + if !ok { + return nil, errors.New("not found") } - return res + sig := privKey.Sign(req.SigningRoot) + return sig, nil } func generateMockStatusResponse(pubkeys [][]byte) *ethpb.ValidatorActivationResponse { @@ -61,7 +78,7 @@ func TestWaitForChainStart_SetsChainStartGenesisTime(t *testing.T) { client := mock.NewMockBeaconNodeValidatorClient(ctrl) v := validator{ - keyManager: testKeyManager, + //keyManager: testKeyManager, validatorClient: client, } genesis := uint64(time.Unix(1, 0).Unix()) @@ -88,7 +105,7 @@ func TestWaitForChainStart_ContextCanceled(t *testing.T) { client := mock.NewMockBeaconNodeValidatorClient(ctrl) v := validator{ - keyManager: testKeyManager, + //keyManager: testKeyManager, validatorClient: client, } genesis := uint64(time.Unix(0, 0).Unix()) @@ -114,9 +131,15 @@ func TestWaitForChainStart_StreamSetupFails(t *testing.T) { defer ctrl.Finish() client := mock.NewMockBeaconNodeValidatorClient(ctrl) + privKey := bls.RandKey() + pubKey := [48]byte{} + copy(pubKey[:], privKey.PublicKey().Marshal()) + km := &mockKeymanager{ + keysMap: make(map[[48]byte]bls.SecretKey), + } v := validator{ - keyManager: testKeyManager, validatorClient: client, + keyManagerV2: km, } clientStream := mock.NewMockBeaconNodeValidator_WaitForChainStartClient(ctrl) client.EXPECT().WaitForChainStart( @@ -134,7 +157,7 @@ func TestWaitForChainStart_ReceiveErrorFromStream(t *testing.T) { client := mock.NewMockBeaconNodeValidatorClient(ctrl) v := validator{ - keyManager: testKeyManager, + //keyManager: testKeyManager, validatorClient: client, } clientStream := mock.NewMockBeaconNodeValidator_WaitForChainStartClient(ctrl) @@ -157,7 +180,7 @@ func TestWaitForSynced_SetsGenesisTime(t *testing.T) { client := mock.NewMockBeaconNodeValidatorClient(ctrl) v := validator{ - keyManager: testKeyManager, + //keyManager: testKeyManager, validatorClient: client, } genesis := uint64(time.Unix(1, 0).Unix()) @@ -184,7 +207,6 @@ func TestWaitForSynced_ContextCanceled(t *testing.T) { client := mock.NewMockBeaconNodeValidatorClient(ctrl) v := validator{ - keyManager: testKeyManager, validatorClient: client, } genesis := uint64(time.Unix(0, 0).Unix()) @@ -211,7 +233,6 @@ func TestWaitForSynced_StreamSetupFails(t *testing.T) { client := mock.NewMockBeaconNodeValidatorClient(ctrl) v := validator{ - keyManager: testKeyManager, validatorClient: client, } clientStream := mock.NewMockBeaconNodeValidator_WaitForSyncedClient(ctrl) @@ -230,7 +251,6 @@ func TestWaitForSynced_ReceiveErrorFromStream(t *testing.T) { client := mock.NewMockBeaconNodeValidatorClient(ctrl) v := validator{ - keyManager: testKeyManager, validatorClient: client, } clientStream := mock.NewMockBeaconNodeValidator_WaitForSyncedClient(ctrl) @@ -251,17 +271,24 @@ func TestWaitActivation_ContextCanceled(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() client := mock.NewMockBeaconNodeValidatorClient(ctrl) - + privKey := bls.RandKey() + pubKey := [48]byte{} + copy(pubKey[:], privKey.PublicKey().Marshal()) + km := &mockKeymanager{ + keysMap: map[[48]byte]bls.SecretKey{ + pubKey: privKey, + }, + } v := validator{ - keyManager: testKeyManager, validatorClient: client, + keyManagerV2: km, } clientStream := mock.NewMockBeaconNodeValidator_WaitForActivationClient(ctrl) client.EXPECT().WaitForActivation( gomock.Any(), ðpb.ValidatorActivationRequest{ - PublicKeys: publicKeys(t, v.keyManager), + PublicKeys: [][]byte{pubKey[:]}, }, ).Return(clientStream, nil) clientStream.EXPECT().Recv().Return( @@ -277,16 +304,23 @@ func TestWaitActivation_StreamSetupFails(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() client := mock.NewMockBeaconNodeValidatorClient(ctrl) - + privKey := bls.RandKey() + pubKey := [48]byte{} + copy(pubKey[:], privKey.PublicKey().Marshal()) + km := &mockKeymanager{ + keysMap: map[[48]byte]bls.SecretKey{ + pubKey: privKey, + }, + } v := validator{ - keyManager: testKeyManager, validatorClient: client, + keyManagerV2: km, } clientStream := mock.NewMockBeaconNodeValidator_WaitForActivationClient(ctrl) client.EXPECT().WaitForActivation( gomock.Any(), ðpb.ValidatorActivationRequest{ - PublicKeys: publicKeys(t, v.keyManager), + PublicKeys: [][]byte{pubKey[:]}, }, ).Return(clientStream, errors.New("failed stream")) err := v.WaitForActivation(context.Background()) @@ -299,15 +333,23 @@ func TestWaitActivation_ReceiveErrorFromStream(t *testing.T) { defer ctrl.Finish() client := mock.NewMockBeaconNodeValidatorClient(ctrl) + privKey := bls.RandKey() + pubKey := [48]byte{} + copy(pubKey[:], privKey.PublicKey().Marshal()) + km := &mockKeymanager{ + keysMap: map[[48]byte]bls.SecretKey{ + pubKey: privKey, + }, + } v := validator{ - keyManager: testKeyManager, validatorClient: client, + keyManagerV2: km, } clientStream := mock.NewMockBeaconNodeValidator_WaitForActivationClient(ctrl) client.EXPECT().WaitForActivation( gomock.Any(), ðpb.ValidatorActivationRequest{ - PublicKeys: publicKeys(t, v.keyManager), + PublicKeys: [][]byte{pubKey[:]}, }, ).Return(clientStream, nil) clientStream.EXPECT().Recv().Return( @@ -324,19 +366,26 @@ func TestWaitActivation_LogsActivationEpochOK(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() client := mock.NewMockBeaconNodeValidatorClient(ctrl) - + privKey := bls.RandKey() + pubKey := [48]byte{} + copy(pubKey[:], privKey.PublicKey().Marshal()) + km := &mockKeymanager{ + keysMap: map[[48]byte]bls.SecretKey{ + pubKey: privKey, + }, + } v := validator{ - keyManager: testKeyManager, validatorClient: client, + keyManagerV2: km, genesisTime: 1, } - resp := generateMockStatusResponse(publicKeys(t, v.keyManager)) + resp := generateMockStatusResponse([][]byte{pubKey[:]}) resp.Statuses[0].Status.Status = ethpb.ValidatorStatus_ACTIVE clientStream := mock.NewMockBeaconNodeValidator_WaitForActivationClient(ctrl) client.EXPECT().WaitForActivation( gomock.Any(), ðpb.ValidatorActivationRequest{ - PublicKeys: publicKeys(t, v.keyManager), + PublicKeys: [][]byte{pubKey[:]}, }, ).Return(clientStream, nil) clientStream.EXPECT().Recv().Return( @@ -352,7 +401,6 @@ func TestCanonicalHeadSlot_FailedRPC(t *testing.T) { defer ctrl.Finish() client := mock.NewMockBeaconChainClient(ctrl) v := validator{ - keyManager: testKeyManager, beaconClient: client, genesisTime: 1, } @@ -369,7 +417,6 @@ func TestCanonicalHeadSlot_OK(t *testing.T) { defer ctrl.Finish() client := mock.NewMockBeaconChainClient(ctrl) v := validator{ - keyManager: testKeyManager, beaconClient: client, } client.EXPECT().GetChainHead( @@ -386,21 +433,27 @@ func TestWaitMultipleActivation_LogsActivationEpochOK(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() client := mock.NewMockBeaconNodeValidatorClient(ctrl) - + privKey := bls.RandKey() + pubKey := [48]byte{} + copy(pubKey[:], privKey.PublicKey().Marshal()) + km := &mockKeymanager{ + keysMap: map[[48]byte]bls.SecretKey{ + pubKey: privKey, + }, + } v := validator{ - keyManager: testKeyManagerThreeValidators, validatorClient: client, + keyManagerV2: km, genesisTime: 1, } - publicKeys := publicKeys(t, v.keyManager) - resp := generateMockStatusResponse(publicKeys) + + resp := generateMockStatusResponse([][]byte{pubKey[:]}) resp.Statuses[0].Status.Status = ethpb.ValidatorStatus_ACTIVE - resp.Statuses[1].Status.Status = ethpb.ValidatorStatus_ACTIVE clientStream := mock.NewMockBeaconNodeValidator_WaitForActivationClient(ctrl) client.EXPECT().WaitForActivation( gomock.Any(), ðpb.ValidatorActivationRequest{ - PublicKeys: publicKeys, + PublicKeys: [][]byte{pubKey[:]}, }, ).Return(clientStream, nil) clientStream.EXPECT().Recv().Return( @@ -416,12 +469,20 @@ func TestWaitActivation_NotAllValidatorsActivatedOK(t *testing.T) { defer ctrl.Finish() client := mock.NewMockBeaconNodeValidatorClient(ctrl) + privKey := bls.RandKey() + pubKey := [48]byte{} + copy(pubKey[:], privKey.PublicKey().Marshal()) + km := &mockKeymanager{ + keysMap: map[[48]byte]bls.SecretKey{ + pubKey: privKey, + }, + } v := validator{ - keyManager: testKeyManagerThreeValidators, validatorClient: client, + keyManagerV2: km, genesisTime: 1, } - resp := generateMockStatusResponse(publicKeys(t, v.keyManager)) + resp := generateMockStatusResponse([][]byte{pubKey[:]}) resp.Statuses[0].Status.Status = ethpb.ValidatorStatus_ACTIVE clientStream := mock.NewMockBeaconNodeValidator_WaitForActivationClient(ctrl) client.EXPECT().WaitForActivation( @@ -505,7 +566,6 @@ func TestUpdateDuties_DoesNothingWhenNotEpochStart_AlreadyExistingAssignments(t slot := uint64(1) v := validator{ - keyManager: testKeyManager, validatorClient: client, duties: ðpb.DutiesResponse{ Duties: []*ethpb.DutiesResponse_Duty{ @@ -530,9 +590,17 @@ func TestUpdateDuties_ReturnsError(t *testing.T) { defer ctrl.Finish() client := mock.NewMockBeaconNodeValidatorClient(ctrl) + privKey := bls.RandKey() + pubKey := [48]byte{} + copy(pubKey[:], privKey.PublicKey().Marshal()) + km := &mockKeymanager{ + keysMap: map[[48]byte]bls.SecretKey{ + pubKey: privKey, + }, + } v := validator{ - keyManager: testKeyManager, validatorClient: client, + keyManagerV2: km, duties: ðpb.DutiesResponse{ Duties: []*ethpb.DutiesResponse_Duty{ { @@ -559,6 +627,14 @@ func TestUpdateDuties_OK(t *testing.T) { client := mock.NewMockBeaconNodeValidatorClient(ctrl) slot := params.BeaconConfig().SlotsPerEpoch + privKey := bls.RandKey() + pubKey := [48]byte{} + copy(pubKey[:], privKey.PublicKey().Marshal()) + km := &mockKeymanager{ + keysMap: map[[48]byte]bls.SecretKey{ + pubKey: privKey, + }, + } resp := ðpb.DutiesResponse{ Duties: []*ethpb.DutiesResponse_Duty{ { @@ -572,7 +648,7 @@ func TestUpdateDuties_OK(t *testing.T) { }, } v := validator{ - keyManager: testKeyManager, + keyManagerV2: km, validatorClient: client, } client.EXPECT().GetDuties( @@ -650,7 +726,6 @@ func TestUpdateProtections_OK(t *testing.T) { } v := validator{ db: db, - keyManager: testKeyManager, validatorClient: client, duties: duties, } @@ -672,7 +747,6 @@ func TestSaveProtections_OK(t *testing.T) { require.NoError(t, err) v := validator{ db: db, - keyManager: testKeyManager, validatorClient: client, attesterHistoryByPubKey: cleanHistories, } @@ -695,37 +769,15 @@ func TestSaveProtections_OK(t *testing.T) { } func TestRolesAt_OK(t *testing.T) { - v, m, finish := setup(t) + v, m, validatorKey, finish := setup(t) defer finish() - sks := make([]bls.SecretKey, 4) - sks[0] = bls.RandKey() - sks[1] = bls.RandKey() - sks[2] = bls.RandKey() - sks[3] = bls.RandKey() - v.keyManager = keymanager.NewDirect(sks) v.duties = ðpb.DutiesResponse{ Duties: []*ethpb.DutiesResponse_Duty{ { CommitteeIndex: 1, AttesterSlot: 1, - PublicKey: sks[0].PublicKey().Marshal(), - }, - { - CommitteeIndex: 2, - ProposerSlots: []uint64{1}, - PublicKey: sks[1].PublicKey().Marshal(), - }, - { - CommitteeIndex: 1, - AttesterSlot: 2, - PublicKey: sks[2].PublicKey().Marshal(), - }, - { - CommitteeIndex: 2, - AttesterSlot: 1, - ProposerSlots: []uint64{1, 5}, - PublicKey: sks[3].PublicKey().Marshal(), + PublicKey: validatorKey.PublicKey().Marshal(), }, }, } @@ -735,50 +787,23 @@ func TestRolesAt_OK(t *testing.T) { gomock.Any(), // epoch ).Return(ðpb.DomainResponse{SignatureDomain: make([]byte, 32)}, nil /*err*/) - m.validatorClient.EXPECT().DomainData( - gomock.Any(), // ctx - gomock.Any(), // epoch - ).Return(ðpb.DomainResponse{SignatureDomain: make([]byte, 32)}, nil /*err*/) - roleMap, err := v.RolesAt(context.Background(), 1) require.NoError(t, err) - assert.Equal(t, ValidatorRole(roleAttester), roleMap[bytesutil.ToBytes48(sks[0].PublicKey().Marshal())][0]) - assert.Equal(t, ValidatorRole(roleProposer), roleMap[bytesutil.ToBytes48(sks[1].PublicKey().Marshal())][0]) - assert.Equal(t, ValidatorRole(roleUnknown), roleMap[bytesutil.ToBytes48(sks[2].PublicKey().Marshal())][0]) - assert.Equal(t, ValidatorRole(roleProposer), roleMap[bytesutil.ToBytes48(sks[3].PublicKey().Marshal())][0]) - assert.Equal(t, ValidatorRole(roleAttester), roleMap[bytesutil.ToBytes48(sks[3].PublicKey().Marshal())][1]) - assert.Equal(t, ValidatorRole(roleAggregator), roleMap[bytesutil.ToBytes48(sks[3].PublicKey().Marshal())][2]) + assert.Equal(t, ValidatorRole(roleAttester), roleMap[bytesutil.ToBytes48(validatorKey.PublicKey().Marshal())][0]) } func TestRolesAt_DoesNotAssignProposer_Slot0(t *testing.T) { - v, m, finish := setup(t) + v, m, validatorKey, finish := setup(t) defer finish() - sks := make([]bls.SecretKey, 3) - sks[0] = bls.RandKey() - sks[1] = bls.RandKey() - sks[2] = bls.RandKey() - v.keyManager = keymanager.NewDirect(sks) v.duties = ðpb.DutiesResponse{ Duties: []*ethpb.DutiesResponse_Duty{ { CommitteeIndex: 1, AttesterSlot: 0, ProposerSlots: []uint64{0}, - PublicKey: sks[0].PublicKey().Marshal(), - }, - { - CommitteeIndex: 2, - AttesterSlot: 4, - ProposerSlots: nil, - PublicKey: sks[1].PublicKey().Marshal(), - }, - { - CommitteeIndex: 1, - AttesterSlot: 3, - ProposerSlots: nil, - PublicKey: sks[2].PublicKey().Marshal(), + PublicKey: validatorKey.PublicKey().Marshal(), }, }, } @@ -791,9 +816,7 @@ func TestRolesAt_DoesNotAssignProposer_Slot0(t *testing.T) { roleMap, err := v.RolesAt(context.Background(), 0) require.NoError(t, err) - assert.Equal(t, ValidatorRole(roleAttester), roleMap[bytesutil.ToBytes48(sks[0].PublicKey().Marshal())][0]) - assert.Equal(t, ValidatorRole(roleUnknown), roleMap[bytesutil.ToBytes48(sks[1].PublicKey().Marshal())][0]) - assert.Equal(t, ValidatorRole(roleUnknown), roleMap[bytesutil.ToBytes48(sks[2].PublicKey().Marshal())][0]) + assert.Equal(t, ValidatorRole(roleAttester), roleMap[bytesutil.ToBytes48(validatorKey.PublicKey().Marshal())][0]) } func TestCheckAndLogValidatorStatus_OK(t *testing.T) { @@ -891,7 +914,6 @@ func TestCheckAndLogValidatorStatus_OK(t *testing.T) { defer ctrl.Finish() client := mock.NewMockBeaconNodeValidatorClient(ctrl) v := validator{ - keyManager: testKeyManager, validatorClient: client, duties: ðpb.DutiesResponse{ Duties: []*ethpb.DutiesResponse_Duty{ diff --git a/validator/flags/BUILD.bazel b/validator/flags/BUILD.bazel index 32eb50c9e462..a90fc38c3e69 100644 --- a/validator/flags/BUILD.bazel +++ b/validator/flags/BUILD.bazel @@ -10,7 +10,6 @@ go_library( visibility = ["//validator:__subpackages__"], deps = [ "//shared/fileutil:go_default_library", - "@com_github_sirupsen_logrus//:go_default_library", "@com_github_urfave_cli_v2//:go_default_library", ], ) diff --git a/validator/flags/flags.go b/validator/flags/flags.go index 54d7b22f8694..5a7cb4bc6b7d 100644 --- a/validator/flags/flags.go +++ b/validator/flags/flags.go @@ -8,7 +8,6 @@ import ( "time" "github.com/prysmaticlabs/prysm/shared/fileutil" - "github.com/sirupsen/logrus" "github.com/urfave/cli/v2" ) @@ -17,8 +16,6 @@ const ( WalletDefaultDirName = "prysm-wallet-v2" ) -var log = logrus.WithField("prefix", "flags") - var ( // DisableAccountMetricsFlag defines the graffiti value included in proposed blocks, default false. DisableAccountMetricsFlag = &cli.BoolFlag{ @@ -120,56 +117,12 @@ var ( "(browser enforced). This flag has no effect if not used with --grpc-gateway-port.", Value: "http://localhost:4242,http://127.0.0.1:4242,http://localhost:4200", } - // KeyManager specifies the key manager to use. - KeyManager = &cli.StringFlag{ - Name: "keymanager", - Usage: "The keymanger to use (unencrypted, interop, keystore, wallet)", - Value: "", - } - // KeyManagerOpts specifies the key manager options. - KeyManagerOpts = &cli.StringFlag{ - Name: "keymanageropts", - Usage: "The options for the keymanger, either a JSON string or path to same", - Value: "", - } - // KeystorePathFlag defines the location of the keystore directory for a validator's account. - KeystorePathFlag = &cli.StringFlag{ - Name: "keystore-path", - Usage: "Path to the desired keystore directory", - } // MonitoringPortFlag defines the http port used to serve prometheus metrics. MonitoringPortFlag = &cli.IntFlag{ Name: "monitoring-port", Usage: "Port used to listening and respond metrics for prometheus.", Value: 8081, } - // PasswordFlag defines the password value for storing and retrieving validator private keys from the keystore. - PasswordFlag = &cli.StringFlag{ - Name: "password", - Usage: "String value of the password for your validator private keys", - } - // SourceDirectories defines the locations of the source validator databases while managing validators. - SourceDirectories = &cli.StringFlag{ - Name: "source-dirs", - Usage: "The directory of source validator databases", - } - // SourceDirectory defines the location of the source validator database while managing validators. - SourceDirectory = &cli.StringFlag{ - Name: "source-dir", - Usage: "The directory of the source validator database", - } - // TargetDirectory defines the location of the target validator database while managing validators. - TargetDirectory = &cli.StringFlag{ - Name: "target-dir", - Usage: "The directory of the target validator database", - } - // UnencryptedKeysFlag specifies a file path of a JSON file of unencrypted validator keys as an - // alternative from launching the validator client from decrypting a keystore directory. - UnencryptedKeysFlag = &cli.StringFlag{ - Name: "unencrypted-keys", - Usage: "Filepath to a JSON file of unencrypted validator keys for easier launching of the validator client", - Value: "", - } // WalletDirFlag defines the path to a wallet directory for Prysm accounts-v2. WalletDirFlag = &cli.StringFlag{ Name: "wallet-dir", @@ -306,32 +259,6 @@ var ( } ) -// Deprecated flags list. -const deprecatedUsage = "DEPRECATED. DO NOT USE." - -var ( - // DeprecatedPasswordsDirFlag is a deprecated flag. - DeprecatedPasswordsDirFlag = &cli.StringFlag{ - Name: "passwords-dir", - Usage: deprecatedUsage, - Hidden: true, - } -) - -// DeprecatedFlags is a slice holding all of the validator client's deprecated flags. -var DeprecatedFlags = []cli.Flag{ - DeprecatedPasswordsDirFlag, -} - -// ComplainOnDeprecatedFlags logs out a error log if a deprecated flag is used, letting the user know it will be removed soon. -func ComplainOnDeprecatedFlags(ctx *cli.Context) { - for _, f := range DeprecatedFlags { - if ctx.IsSet(f.Names()[0]) { - log.Errorf("%s is deprecated and has no effect. Do not use this flag, it will be deleted soon.", f.Names()[0]) - } - } -} - // DefaultValidatorDir returns OS-specific default validator directory. func DefaultValidatorDir() string { // Try to place the data folder in the user's home dir diff --git a/validator/keymanager/v1/BUILD.bazel b/validator/keymanager/v1/BUILD.bazel deleted file mode 100644 index 20ee4ace3102..000000000000 --- a/validator/keymanager/v1/BUILD.bazel +++ /dev/null @@ -1,61 +0,0 @@ -load("@prysm//tools/go:def.bzl", "go_library") -load("@io_bazel_rules_go//go:def.bzl", "go_test") - -go_library( - name = "go_default_library", - srcs = [ - "direct.go", - "direct_interop.go", - "direct_keystore.go", - "direct_unencrypted.go", - "keymanager.go", - "log.go", - "opts.go", - "remote.go", - "wallet.go", - ], - importpath = "github.com/prysmaticlabs/prysm/validator/keymanager/v1", - visibility = ["//validator:__subpackages__"], - deps = [ - "//shared/bls:go_default_library", - "//shared/bytesutil:go_default_library", - "//shared/interop:go_default_library", - "//shared/params:go_default_library", - "//validator/accounts/v1:go_default_library", - "@com_github_pkg_errors//:go_default_library", - "@com_github_prysmaticlabs_ethereumapis//eth/v1alpha1:go_default_library", - "@com_github_sirupsen_logrus//:go_default_library", - "@com_github_wealdtech_eth2_signer_api//pb/v1:go_default_library", - "@com_github_wealdtech_go_eth2_wallet//:go_default_library", - "@com_github_wealdtech_go_eth2_wallet_store_filesystem//:go_default_library", - "@com_github_wealdtech_go_eth2_wallet_types_v2//:go_default_library", - "@org_golang_google_grpc//:go_default_library", - "@org_golang_google_grpc//credentials:go_default_library", - "@org_golang_x_crypto//ssh/terminal:go_default_library", - ], -) - -go_test( - name = "go_default_test", - srcs = [ - "direct_interop_test.go", - "direct_test.go", - "opts_test.go", - "remote_internal_test.go", - "remote_test.go", - "wallet_test.go", - ], - embed = [":go_default_library"], - deps = [ - "//shared/bls:go_default_library", - "//shared/bytesutil:go_default_library", - "//shared/params:go_default_library", - "//shared/testutil:go_default_library", - "//shared/testutil/assert:go_default_library", - "//shared/testutil/require:go_default_library", - "@com_github_wealdtech_go_eth2_wallet_encryptor_keystorev4//:go_default_library", - "@com_github_wealdtech_go_eth2_wallet_nd_v2//:go_default_library", - "@com_github_wealdtech_go_eth2_wallet_store_filesystem//:go_default_library", - "@com_github_wealdtech_go_eth2_wallet_types_v2//:go_default_library", - ], -) diff --git a/validator/keymanager/v1/direct.go b/validator/keymanager/v1/direct.go deleted file mode 100644 index 018b591bdcbd..000000000000 --- a/validator/keymanager/v1/direct.go +++ /dev/null @@ -1,48 +0,0 @@ -package v1 - -import ( - "context" - - "github.com/prysmaticlabs/prysm/shared/bls" - "github.com/prysmaticlabs/prysm/shared/bytesutil" -) - -// Direct is a key manager that holds all secret keys directly. -type Direct struct { - // Key to the map is the bytes of the public key. - publicKeys map[[48]byte]bls.PublicKey - // Key to the map is the bytes of the public key. - secretKeys map[[48]byte]bls.SecretKey -} - -// NewDirect creates a new direct key manager from the secret keys provided to it. -func NewDirect(sks []bls.SecretKey) *Direct { - res := &Direct{ - publicKeys: make(map[[48]byte]bls.PublicKey), - secretKeys: make(map[[48]byte]bls.SecretKey), - } - for _, sk := range sks { - publicKey := sk.PublicKey() - pubKey := bytesutil.ToBytes48(publicKey.Marshal()) - res.publicKeys[pubKey] = publicKey - res.secretKeys[pubKey] = sk - } - return res -} - -// FetchValidatingKeys fetches the list of public keys that should be used to validate with. -func (km *Direct) FetchValidatingKeys() ([][48]byte, error) { - keys := make([][48]byte, 0, len(km.publicKeys)) - for key := range km.publicKeys { - keys = append(keys, key) - } - return keys, nil -} - -// Sign signs a message for the validator to broadcast. -func (km *Direct) Sign(_ context.Context, pubKey [48]byte, root [32]byte) (bls.Signature, error) { - if secretKey, exists := km.secretKeys[pubKey]; exists { - return secretKey.Sign(root[:]), nil - } - return nil, ErrNoSuchKey -} diff --git a/validator/keymanager/v1/direct_interop.go b/validator/keymanager/v1/direct_interop.go deleted file mode 100644 index 9790355ed2a7..000000000000 --- a/validator/keymanager/v1/direct_interop.go +++ /dev/null @@ -1,55 +0,0 @@ -package v1 - -import ( - "encoding/json" - - "github.com/prysmaticlabs/prysm/shared/bls" - "github.com/prysmaticlabs/prysm/shared/bytesutil" - "github.com/prysmaticlabs/prysm/shared/interop" -) - -// Interop is a key manager that deterministically generates keys. -type Interop struct { - *Direct -} - -type interopOpts struct { - Keys uint64 `json:"keys"` - Offset uint64 `json:"offset"` -} - -var interopOptsHelp = `The interop key manager generates keys according to the interop testnet specification. The options are: - - keys This is the number of keys to generate - - offset This is the number of keys to skip before starting to generate keys -A sample set of options are: - { - "keys": 5, // Generate 5 keys - "offset": 1024 // Start with the 1024th key - }` - -// NewInterop creates a key manager using a number of interop keys at a given offset. -func NewInterop(input string) (*Interop, string, error) { - opts := &interopOpts{} - err := json.Unmarshal([]byte(input), opts) - if err != nil { - return nil, interopOptsHelp, err - } - - sks, pks, err := interop.DeterministicallyGenerateKeys(opts.Offset, opts.Keys) - if err != nil { - return nil, interopOptsHelp, err - } - - km := &Interop{ - Direct: &Direct{ - publicKeys: make(map[[48]byte]bls.PublicKey), - secretKeys: make(map[[48]byte]bls.SecretKey), - }, - } - for i := 0; uint64(i) < opts.Keys; i++ { - pubKey := bytesutil.ToBytes48(pks[i].Marshal()) - km.publicKeys[pubKey] = pks[i] - km.secretKeys[pubKey] = sks[i] - } - return km, "", nil -} diff --git a/validator/keymanager/v1/direct_interop_test.go b/validator/keymanager/v1/direct_interop_test.go deleted file mode 100644 index 42952bc77396..000000000000 --- a/validator/keymanager/v1/direct_interop_test.go +++ /dev/null @@ -1,49 +0,0 @@ -package v1_test - -import ( - "encoding/hex" - "testing" - - "github.com/prysmaticlabs/prysm/shared/bls" - "github.com/prysmaticlabs/prysm/shared/testutil/assert" - "github.com/prysmaticlabs/prysm/shared/testutil/require" - keymanager "github.com/prysmaticlabs/prysm/validator/keymanager/v1" -) - -func TestInteropListValidatingKeysZero(t *testing.T) { - _, _, err := keymanager.NewInterop("") - assert.ErrorContains(t, "unexpected end of JSON input", err) -} - -func TestInteropListValidatingKeysEmptyJSON(t *testing.T) { - _, _, err := keymanager.NewInterop("{}") - assert.ErrorContains(t, "input length must be greater than 0", err) -} - -func TestInteropListValidatingKeysSingle(t *testing.T) { - direct, _, err := keymanager.NewInterop(`{"keys":1}`) - require.NoError(t, err) - keys, err := direct.FetchValidatingKeys() - require.NoError(t, err) - assert.Equal(t, 1, len(keys), "Incorrect number of keys returned") - - pkBytes, err := hex.DecodeString("25295f0d1d592a90b333e26e85149708208e9f8e8bc18f6c77bd62f8ad7a6866") - require.NoError(t, err) - privateKey, err := bls.SecretKeyFromBytes(pkBytes) - require.NoError(t, err) - assert.DeepEqual(t, privateKey.PublicKey().Marshal(), keys[0][:], "Public k 0 incorrect") -} - -func TestInteropListValidatingKeysOffset(t *testing.T) { - direct, _, err := keymanager.NewInterop(`{"keys":1,"offset":9}`) - require.NoError(t, err) - keys, err := direct.FetchValidatingKeys() - require.NoError(t, err) - assert.Equal(t, 1, len(keys), "Incorrect number of keys returned") - - pkBytes, err := hex.DecodeString("2b3b88a041168a1c4cd04bdd8de7964fd35238f95442dc678514f9dadb81ec34") - require.NoError(t, err) - privateKey, err := bls.SecretKeyFromBytes(pkBytes) - require.NoError(t, err) - require.DeepEqual(t, privateKey.PublicKey().Marshal(), keys[0][:], "Public k 0 incorrect") -} diff --git a/validator/keymanager/v1/direct_keystore.go b/validator/keymanager/v1/direct_keystore.go deleted file mode 100644 index 61f6206ff051..000000000000 --- a/validator/keymanager/v1/direct_keystore.go +++ /dev/null @@ -1,91 +0,0 @@ -package v1 - -import ( - "encoding/json" - "errors" - "os" - "strings" - - "github.com/prysmaticlabs/prysm/shared/bls" - "github.com/prysmaticlabs/prysm/shared/bytesutil" - "github.com/prysmaticlabs/prysm/shared/params" - v1 "github.com/prysmaticlabs/prysm/validator/accounts/v1" - "golang.org/x/crypto/ssh/terminal" -) - -// Keystore is a key manager that loads keys from a standard keystore. -type Keystore struct { - *Direct -} - -type keystoreOpts struct { - Path string `json:"path"` - Passphrase string `json:"passphrase"` -} - -var keystoreOptsHelp = `The keystore key manager generates keys and stores them in a local encrypted store. The options are: - - path This is the filesystem path to where keys will be stored. Defaults to the user's home directory if not supplied - - passphrase This is the passphrase used to encrypt keys. Will be asked for if not supplied -A sample set of options are: - { - "path": "/home/me/keys", // Store the keys in '/home/me/keys' - "passphrase": "secret" // Use the passphrase 'secret' to encrypt and decrypt keys - }` - -// NewKeystore creates a key manager populated with the keys from the keystore at the given path. -func NewKeystore(input string) (KeyManager, string, error) { - opts := &keystoreOpts{} - err := json.Unmarshal([]byte(input), opts) - if err != nil { - return nil, keystoreOptsHelp, err - } - - if strings.Contains(opts.Path, "$") || strings.Contains(opts.Path, "~") || strings.Contains(opts.Path, "%") { - log.WithField("path", opts.Path).Warn("Keystore path contains unexpanded shell expansion characters") - } - - if opts.Path == "" { - opts.Path = v1.DefaultValidatorDir() - } - log.WithField("keystorePath", opts.Path).Debug("Checking validator keys") - - exists, err := v1.Exists(opts.Path, true /* assertNonEmpty */) - if err != nil { - return nil, keystoreOptsHelp, err - } - if exists { - if opts.Passphrase == "" { - log.Info("Enter your validator account password:") - bytePassword, err := terminal.ReadPassword(int(os.Stdin.Fd())) - if err != nil { - return nil, keystoreOptsHelp, err - } - text := string(bytePassword) - opts.Passphrase = strings.ReplaceAll(text, "\n", "") - } - - if err := v1.VerifyAccountNotExists(opts.Path, opts.Passphrase); err == nil { - log.Info("No account found, creating new validator account...") - } - } else { - return nil, "", errors.New("no validator keys found, please use validator accounts create") - } - - keyMap, err := v1.DecryptKeysFromKeystore(opts.Path, params.BeaconConfig().ValidatorPrivkeyFileName, opts.Passphrase) - if err != nil { - return nil, keystoreOptsHelp, err - } - - km := &Unencrypted{ - Direct: &Direct{ - publicKeys: make(map[[48]byte]bls.PublicKey), - secretKeys: make(map[[48]byte]bls.SecretKey), - }, - } - for _, key := range keyMap { - pubKey := bytesutil.ToBytes48(key.PublicKey.Marshal()) - km.publicKeys[pubKey] = key.PublicKey - km.secretKeys[pubKey] = key.SecretKey - } - return km, "", nil -} diff --git a/validator/keymanager/v1/direct_test.go b/validator/keymanager/v1/direct_test.go deleted file mode 100644 index dc9612adfb0e..000000000000 --- a/validator/keymanager/v1/direct_test.go +++ /dev/null @@ -1,59 +0,0 @@ -package v1_test - -import ( - "context" - "testing" - - "github.com/prysmaticlabs/prysm/shared/bls" - "github.com/prysmaticlabs/prysm/shared/bytesutil" - "github.com/prysmaticlabs/prysm/shared/testutil/assert" - "github.com/prysmaticlabs/prysm/shared/testutil/require" - keymanager "github.com/prysmaticlabs/prysm/validator/keymanager/v1" -) - -func TestDirectListValidatingKeysNil(t *testing.T) { - direct := keymanager.NewDirect(nil) - keys, err := direct.FetchValidatingKeys() - require.NoError(t, err) - assert.Equal(t, 0, len(keys), "Incorrect number of keys returned") -} - -func TestDirectListValidatingKeysSingle(t *testing.T) { - sks := make([]bls.SecretKey, 0) - sks = append(sks, bls.RandKey()) - direct := keymanager.NewDirect(sks) - keys, err := direct.FetchValidatingKeys() - require.NoError(t, err) - assert.Equal(t, 1, len(keys), "Incorrect number of keys returned") -} - -func TestDirectListValidatingKeysMultiple(t *testing.T) { - sks := make([]bls.SecretKey, 0) - numKeys := 256 - for i := 0; i < numKeys; i++ { - sks = append(sks, bls.RandKey()) - } - direct := keymanager.NewDirect(sks) - keys, err := direct.FetchValidatingKeys() - require.NoError(t, err) - assert.Equal(t, numKeys, len(keys), "Incorrect number of keys returned") -} - -func TestSignNoSuchKey(t *testing.T) { - sks := make([]bls.SecretKey, 0) - direct := keymanager.NewDirect(sks) - _, err := direct.Sign(context.Background(), [48]byte{}, [32]byte{}) - assert.ErrorContains(t, keymanager.ErrNoSuchKey.Error(), err) -} - -func TestSign(t *testing.T) { - sks := make([]bls.SecretKey, 0) - sks = append(sks, bls.RandKey()) - direct := keymanager.NewDirect(sks) - - pubKey := bytesutil.ToBytes48(sks[0].PublicKey().Marshal()) - msg := [32]byte{} - sig, err := direct.Sign(context.Background(), pubKey, msg) - require.NoError(t, err) - require.Equal(t, true, sig.Verify(sks[0].PublicKey(), bytesutil.FromBytes32(msg)), "Failed to verify generated signature") -} diff --git a/validator/keymanager/v1/direct_unencrypted.go b/validator/keymanager/v1/direct_unencrypted.go deleted file mode 100644 index 0c95d11cb415..000000000000 --- a/validator/keymanager/v1/direct_unencrypted.go +++ /dev/null @@ -1,109 +0,0 @@ -package v1 - -import ( - "encoding/json" - "io" - "io/ioutil" - "os" - "path/filepath" - "strings" - - "github.com/prysmaticlabs/prysm/shared/bls" - "github.com/prysmaticlabs/prysm/shared/bytesutil" -) - -// Unencrypted is a key manager that loads keys from an unencrypted store. -type Unencrypted struct { - *Direct -} - -type unencryptedOpts struct { - Path string `json:"path"` -} - -var unencryptedOptsHelp = `The unencrypted key manager stores keys in a local unencrypted store. The options are: - - path This is the filesystem path to a file containing the unencrypted keys -A sample set of options are: - { - "path": "/home/me/keys.json" // Access the keys in '/home/me/keys.json' - }` - -// NewUnencrypted creates a keymanager from a file of unencrypted keys. -func NewUnencrypted(input string) (*Unencrypted, string, error) { - opts := &unencryptedOpts{} - err := json.Unmarshal([]byte(input), opts) - if err != nil { - return nil, unencryptedOptsHelp, err - } - - if strings.Contains(opts.Path, "$") || strings.Contains(opts.Path, "~") || strings.Contains(opts.Path, "%") { - log.WithField("path", opts.Path).Warn("Keystore path contains unexpanded shell expansion characters") - } - - path, err := filepath.Abs(opts.Path) - if err != nil { - return nil, unencryptedOptsHelp, err - } - reader, err := os.Open(path) - if err != nil { - return nil, unencryptedOptsHelp, err - } - defer func() { - if err := reader.Close(); err != nil { - log.WithError(err).Error("Failed to close file reader") - } - }() - - keyMap, err := unencryptedKeysFromReader(reader) - if err != nil { - return nil, unencryptedOptsHelp, err - } - sks := make([]bls.SecretKey, 0, len(keyMap)) - sks = append(sks, keyMap...) - - km := &Unencrypted{ - Direct: &Direct{ - publicKeys: make(map[[48]byte]bls.PublicKey), - secretKeys: make(map[[48]byte]bls.SecretKey), - }, - } - for i := 0; i < len(sks); i++ { - pk := sks[i].PublicKey() - pubKey := bytesutil.ToBytes48(pk.Marshal()) - km.publicKeys[pubKey] = pk - km.secretKeys[pubKey] = sks[i] - } - return km, "", nil -} - -type unencryptedKeysContainer struct { - Keys []*unencryptedKeys `json:"keys"` -} - -type unencryptedKeys struct { - ValidatorKey []byte `json:"validator_key"` -} - -// unencryptedKeysFromReader loads the unencrypted keys from the given reader. -func unencryptedKeysFromReader(reader io.Reader) ([]bls.SecretKey, error) { - log.Warn("Loading encrypted keys from disk. Do not do this in production!") - - data, err := ioutil.ReadAll(reader) - if err != nil { - return nil, err - } - var ctnr *unencryptedKeysContainer - if err := json.Unmarshal(data, &ctnr); err != nil { - return nil, err - } - - res := make([]bls.SecretKey, 0, len(ctnr.Keys)) - for i := range ctnr.Keys { - secretKey, err := bls.SecretKeyFromBytes(ctnr.Keys[i].ValidatorKey) - if err != nil { - return nil, err - } - res = append(res, secretKey) - } - return res, nil -} diff --git a/validator/keymanager/v1/keymanager.go b/validator/keymanager/v1/keymanager.go deleted file mode 100644 index d66e601f587c..000000000000 --- a/validator/keymanager/v1/keymanager.go +++ /dev/null @@ -1,40 +0,0 @@ -package v1 - -import ( - "context" - "errors" - - ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1" - "github.com/prysmaticlabs/prysm/shared/bls" -) - -// ErrNoSuchKey is returned whenever a request is made for a key of which a key manager is unaware. -var ErrNoSuchKey = errors.New("no such key") - -// ErrCannotSign is returned whenever a signing attempt fails. -var ErrCannotSign = errors.New("cannot sign") - -// ErrDenied is returned whenever a signing attempt is denied. -var ErrDenied = errors.New("signing attempt denied") - -// KeyManager controls access to private keys by the validator. -type KeyManager interface { - // FetchValidatingKeys fetches the list of public keys that should be used to validate with. - FetchValidatingKeys() ([][48]byte, error) - // Sign signs a message for the validator to broadcast. - // Note that the domain should already be part of the root, but it is passed along for security purposes. - Sign(ctx context.Context, pubKey [48]byte, root [32]byte) (bls.Signature, error) -} - -// ProtectingKeyManager provides access to a keymanager that protects its clients from slashing events. -type ProtectingKeyManager interface { - // SignGeneric signs a generic root. - // Note that the domain should already be part of the root, but it is provided for authorisation purposes. - SignGeneric(pubKey [48]byte, root [32]byte, domain [32]byte) (bls.Signature, error) - - // SignProposal signs a block proposal for the validator to broadcast. - SignProposal(pubKey [48]byte, domain [32]byte, data *ethpb.BeaconBlockHeader) (bls.Signature, error) - - // SignAttestation signs an attestation for the validator to broadcast. - SignAttestation(pubKey [48]byte, domain [32]byte, data *ethpb.AttestationData) (bls.Signature, error) -} diff --git a/validator/keymanager/v1/log.go b/validator/keymanager/v1/log.go deleted file mode 100644 index 0d8c47d5caa0..000000000000 --- a/validator/keymanager/v1/log.go +++ /dev/null @@ -1,7 +0,0 @@ -package v1 - -import ( - "github.com/sirupsen/logrus" -) - -var log = logrus.WithField("prefix", "keymanager") diff --git a/validator/keymanager/v1/opts.go b/validator/keymanager/v1/opts.go deleted file mode 100644 index 3fcbd6c11d39..000000000000 --- a/validator/keymanager/v1/opts.go +++ /dev/null @@ -1,32 +0,0 @@ -package v1 - -import ( - "encoding/json" - "io/ioutil" - "strings" -) - -// decodeOpts decodes a value in to an options container. -// The input can be either JSON data or a path to a file containing JSON. -// This function returns an error if there is a problem decoding the input. -func decodeOpts(input string, res interface{}) error { - if input == "" { - // Empty input is okay. - return nil - } - - var data []byte - if strings.HasPrefix(input, "{") { - // Looks like straight JSON. - data = []byte(input) - } else { - // Assume it's a path. - file, err := ioutil.ReadFile(input) - if err != nil { - return err - } - data = file - } - - return json.Unmarshal(data, res) -} diff --git a/validator/keymanager/v1/opts_test.go b/validator/keymanager/v1/opts_test.go deleted file mode 100644 index 70e74f2b1931..000000000000 --- a/validator/keymanager/v1/opts_test.go +++ /dev/null @@ -1,67 +0,0 @@ -package v1 - -import ( - "encoding/json" - "errors" - "testing" - - "github.com/prysmaticlabs/prysm/shared/testutil/assert" - "github.com/prysmaticlabs/prysm/shared/testutil/require" -) - -func TestDecodeOpts(t *testing.T) { - tests := []struct { - name string - input string - res interface{} - err error - result string - }{ - { - name: "EmptyInput", - input: "", - res: &struct { - Name string `json:"name,omitempty"` - }{}, - result: `{}`, - }, - { - name: "EmptyJSON", - input: "{}", - res: &struct { - Name string `json:"name,omitempty"` - }{}, - result: `{}`, - }, - { - name: "BadInput", - input: "bad", - res: &struct { - Name string `json:"name,omitempty"` - }{}, - err: errors.New("open bad: no such file or directory"), - }, - { - name: "GoodDirect", - input: `{"name":"test"}`, - res: &struct { - Name string `json:"name,omitempty"` - }{}, - result: `{"name":"test"}`, - }, - } - - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - err := decodeOpts(test.input, test.res) - if test.err == nil { - require.NoError(t, err) - recoded, err := json.Marshal(test.res) - require.NoError(t, err) - require.DeepEqual(t, []byte(test.result), recoded, "Unexpected recoded value") - } else { - assert.ErrorContains(t, test.err.Error(), err) - } - }) - } -} diff --git a/validator/keymanager/v1/remote.go b/validator/keymanager/v1/remote.go deleted file mode 100644 index a5046f44b3c4..000000000000 --- a/validator/keymanager/v1/remote.go +++ /dev/null @@ -1,327 +0,0 @@ -package v1 - -import ( - "context" - "crypto/tls" - "crypto/x509" - "encoding/json" - "fmt" - "io/ioutil" - "regexp" - "strings" - - "github.com/pkg/errors" - ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1" - "github.com/prysmaticlabs/prysm/shared/bls" - "github.com/prysmaticlabs/prysm/shared/bytesutil" - pb "github.com/wealdtech/eth2-signer-api/pb/v1" - "google.golang.org/grpc" - "google.golang.org/grpc/credentials" -) - -const ( - // maxMessageSize is the largest message that can be received over GRPC. Set to 8MB, which handles ~128K keys. - maxMessageSize = 8 * 1024 * 1024 -) - -// Remote is a key manager that accesses a remote wallet daemon. -type Remote struct { - paths []string - conn *grpc.ClientConn - accounts map[[48]byte]*accountInfo - signClientInitiator func(*grpc.ClientConn) -} - -type accountInfo struct { - Name string `json:"name"` - PubKey []byte `json:"pubkey"` -} - -type remoteOpts struct { - Location string `json:"location"` - Accounts []string `json:"accounts"` - Certificates *remoteCertificateOpts `json:"certificates"` -} - -type remoteCertificateOpts struct { - CACert string `json:"ca_cert"` - ClientCert string `json:"client_cert"` - ClientKey string `json:"client_key"` -} - -var remoteOptsHelp = `The remote key manager connects to a walletd instance. The options are: - - location This is the location to look for wallets. If not supplied it will - use the standard (operating system-dependent) path. - - accounts This is a list of account specifiers. An account specifier is of - the form /[account name], where the account name can be a - regular expression. If the account specifier is just all - accounts in that wallet will be used. Multiple account specifiers can be - supplied if required. - - certificates This provides paths to certificates: - - ca_cert This is the path to the server's certificate authority certificate file - - client_cert This is the path to the client's certificate file - - client_key This is the path to the client's key file - -An sample keymanager options file (with annotations; these should be removed if -using this as a template) is: - - { - "location": "host.example.com:12345", // Connect to walletd at host.example.com on port 12345 - "accounts": ["Validators/Account.*"] // Use all accounts in the 'Validators' wallet starting with 'Account' - "certificates": { - "ca_cert": "/home/eth2/certs/ca.crt" // Certificate file for the CA that signed the server's certificate - "client_cert": "/home/eth2/certs/client.crt" // Certificate file for this client - "client_key": "/home/eth2/certs/client.key" // Key file for this client - } - }` - -// NewRemoteWallet creates a key manager populated with the keys from walletd. -func NewRemoteWallet(input string) (KeyManager, string, error) { - opts := &remoteOpts{} - err := json.Unmarshal([]byte(input), opts) - if err != nil { - return nil, remoteOptsHelp, err - } - - if len(opts.Accounts) == 0 { - return nil, remoteOptsHelp, errors.New("at least one account specifier is required") - } - - // Load the client certificates. - if opts.Certificates == nil { - return nil, remoteOptsHelp, errors.New("certificates are required") - } - if opts.Certificates.ClientCert == "" { - return nil, remoteOptsHelp, errors.New("client certificate is required") - } - if opts.Certificates.ClientKey == "" { - return nil, remoteOptsHelp, errors.New("client key is required") - } - clientPair, err := tls.LoadX509KeyPair(opts.Certificates.ClientCert, opts.Certificates.ClientKey) - if err != nil { - return nil, remoteOptsHelp, errors.Wrap(err, "failed to obtain client's certificate and/or key") - } - - // Load the CA for the server certificate if present. - cp := x509.NewCertPool() - if opts.Certificates.CACert != "" { - serverCA, err := ioutil.ReadFile(opts.Certificates.CACert) - if err != nil { - return nil, remoteOptsHelp, errors.Wrap(err, "failed to obtain server's CA certificate") - } - if !cp.AppendCertsFromPEM(serverCA) { - return nil, remoteOptsHelp, errors.Wrap(err, "failed to add server's CA certificate to pool") - } - } - - tlsCfg := &tls.Config{ - Certificates: []tls.Certificate{clientPair}, - RootCAs: cp, - } - clientCreds := credentials.NewTLS(tlsCfg) - - grpcOpts := []grpc.DialOption{ - // Require TLS with client certificate. - grpc.WithTransportCredentials(clientCreds), - // Receive large messages without erroring. - grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(maxMessageSize)), - } - - conn, err := grpc.Dial(opts.Location, grpcOpts...) - if err != nil { - return nil, remoteOptsHelp, errors.New("failed to connect to remote wallet") - } - - km := &Remote{ - conn: conn, - paths: opts.Accounts, - } - - err = km.RefreshValidatingKeys() - if err != nil { - return nil, remoteOptsHelp, errors.Wrap(err, "failed to fetch accounts from remote wallet") - } - - return km, remoteOptsHelp, nil -} - -// FetchValidatingKeys fetches the list of public keys that should be used to validate with. -func (km *Remote) FetchValidatingKeys() ([][48]byte, error) { - res := make([][48]byte, 0, len(km.accounts)) - for _, accountInfo := range km.accounts { - res = append(res, bytesutil.ToBytes48(accountInfo.PubKey)) - } - return res, nil -} - -// Sign without protection is not supported by remote keymanagers. -func (km *Remote) Sign(_ context.Context, _ [48]byte, _ [32]byte) (bls.Signature, error) { - return nil, errors.New("remote keymanager does not support unprotected signing") -} - -// SignGeneric signs a generic message for the validator to broadcast. -func (km *Remote) SignGeneric(ctx context.Context, pubKey [48]byte, root, domain [32]byte) (bls.Signature, error) { - accountInfo, exists := km.accounts[pubKey] - if !exists { - return nil, ErrNoSuchKey - } - - client := pb.NewSignerClient(km.conn) - req := &pb.SignRequest{ - Id: &pb.SignRequest_Account{Account: accountInfo.Name}, - Data: root[:], - Domain: domain[:], - } - resp, err := client.Sign(ctx, req) - if err != nil { - return nil, err - } - switch resp.State { - case pb.ResponseState_DENIED: - return nil, ErrDenied - case pb.ResponseState_FAILED: - return nil, ErrCannotSign - } - return bls.SignatureFromBytes(resp.Signature) -} - -// SignProposal signs a block proposal for the validator to broadcast. -func (km *Remote) SignProposal(ctx context.Context, pubKey [48]byte, domain [32]byte, data *ethpb.BeaconBlockHeader) (bls.Signature, error) { - accountInfo, exists := km.accounts[pubKey] - if !exists { - return nil, ErrNoSuchKey - } - - client := pb.NewSignerClient(km.conn) - req := &pb.SignBeaconProposalRequest{ - Id: &pb.SignBeaconProposalRequest_Account{Account: accountInfo.Name}, - Domain: domain[:], - Data: &pb.BeaconBlockHeader{ - Slot: data.Slot, - ProposerIndex: data.ProposerIndex, - ParentRoot: data.ParentRoot, - StateRoot: data.StateRoot, - BodyRoot: data.BodyRoot, - }, - } - resp, err := client.SignBeaconProposal(ctx, req) - if err != nil { - return nil, err - } - switch resp.State { - case pb.ResponseState_DENIED: - return nil, ErrDenied - case pb.ResponseState_FAILED: - return nil, ErrCannotSign - } - return bls.SignatureFromBytes(resp.Signature) -} - -// SignAttestation signs an attestation for the validator to broadcast. -func (km *Remote) SignAttestation(ctx context.Context, pubKey [48]byte, domain [32]byte, data *ethpb.AttestationData) (bls.Signature, error) { - accountInfo, exists := km.accounts[pubKey] - if !exists { - return nil, ErrNoSuchKey - } - - client := pb.NewSignerClient(km.conn) - req := &pb.SignBeaconAttestationRequest{ - Id: &pb.SignBeaconAttestationRequest_Account{Account: accountInfo.Name}, - Domain: domain[:], - Data: &pb.AttestationData{ - Slot: data.Slot, - CommitteeIndex: data.CommitteeIndex, - BeaconBlockRoot: data.BeaconBlockRoot, - Source: &pb.Checkpoint{ - Epoch: data.Source.Epoch, - Root: data.Source.Root, - }, - Target: &pb.Checkpoint{ - Epoch: data.Target.Epoch, - Root: data.Target.Root, - }, - }, - } - resp, err := client.SignBeaconAttestation(ctx, req) - if err != nil { - return nil, err - } - switch resp.State { - case pb.ResponseState_DENIED: - return nil, ErrDenied - case pb.ResponseState_FAILED: - return nil, ErrCannotSign - } - return bls.SignatureFromBytes(resp.Signature) -} - -// RefreshValidatingKeys refreshes the list of validating keys from the remote signer. -func (km *Remote) RefreshValidatingKeys() error { - listerClient := pb.NewListerClient(km.conn) - listAccountsReq := &pb.ListAccountsRequest{ - Paths: km.paths, - } - resp, err := listerClient.ListAccounts(context.TODO(), listAccountsReq) - if err != nil { - return err - } - if resp.State == pb.ResponseState_DENIED { - return errors.New("attempt to fetch keys denied") - } - if resp.State == pb.ResponseState_FAILED { - return errors.New("attempt to fetch keys failed") - } - - verificationRegexes := pathsToVerificationRegexes(km.paths) - accounts := make(map[[48]byte]*accountInfo, len(resp.Accounts)) - for _, account := range resp.Accounts { - verified := false - for _, verificationRegex := range verificationRegexes { - if verificationRegex.Match([]byte(account.Name)) { - verified = true - break - } - } - if !verified { - log.WithField("path", account.Name).Warn("Received unwanted account from server; ignoring") - continue - } - account := &accountInfo{ - Name: account.Name, - PubKey: account.PublicKey, - } - accounts[bytesutil.ToBytes48(account.PubKey)] = account - } - km.accounts = accounts - return nil -} - -// pathsToVerificationRegexes turns path specifiers in to regexes to ensure accounts we are given are good. -func pathsToVerificationRegexes(paths []string) []*regexp.Regexp { - regexes := make([]*regexp.Regexp, 0, len(paths)) - for _, path := range paths { - log := log.WithField("path", path) - parts := strings.Split(path, "/") - if len(parts) == 0 || parts[0] == "" { - log.Debug("Invalid path") - continue - } - if len(parts) == 1 { - parts = append(parts, ".*") - } - parts[1] = strings.TrimPrefix(parts[1], "^") - var specifier string - if strings.HasSuffix(parts[1], "$") { - specifier = fmt.Sprintf("^%s/%s", parts[0], parts[1]) - } else { - specifier = fmt.Sprintf("^%s/%s$", parts[0], parts[1]) - } - regex, err := regexp.Compile(specifier) - if err != nil { - log.WithField("specifier", specifier).WithError(err).Warn("Invalid path regex") - continue - } - regexes = append(regexes, regex) - } - return regexes -} diff --git a/validator/keymanager/v1/remote_internal_test.go b/validator/keymanager/v1/remote_internal_test.go deleted file mode 100644 index bfec33f202c8..000000000000 --- a/validator/keymanager/v1/remote_internal_test.go +++ /dev/null @@ -1,56 +0,0 @@ -package v1 - -import ( - "testing" - - "github.com/prysmaticlabs/prysm/shared/testutil/require" -) - -func TestPathsToVerificationRegexes(t *testing.T) { - tests := []struct { - name string - paths []string - regexes []string - err string - }{ - { - name: "Empty", - regexes: []string{}, - }, - { - name: "IgnoreBadPaths", - paths: []string{"", "/", "/Account"}, - regexes: []string{}, - }, - { - name: "Simple", - paths: []string{"Wallet/Account"}, - regexes: []string{"^Wallet/Account$"}, - }, - { - name: "Multiple", - paths: []string{"Wallet/Account1", "Wallet/Account2"}, - regexes: []string{"^Wallet/Account1$", "^Wallet/Account2$"}, - }, - { - name: "IgnoreInvalidRegex", - paths: []string{"Wallet/Account1", "Bad/***", "Wallet/Account2"}, - regexes: []string{"^Wallet/Account1$", "^Wallet/Account2$"}, - }, - { - name: "TidyExistingAnchors", - paths: []string{"Wallet/^.*$", "Wallet/Foo.*Bar$", "Wallet/^Account"}, - regexes: []string{"^Wallet/.*$", "^Wallet/Foo.*Bar$", "^Wallet/Account$"}, - }, - } - - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - regexes := pathsToVerificationRegexes(test.paths) - require.Equal(t, len(test.regexes), len(regexes), "Unexpected number of regexes") - for i := range regexes { - require.Equal(t, test.regexes[i], regexes[i].String(), "Unexpected regex %d", i) - } - }) - } -} diff --git a/validator/keymanager/v1/remote_test.go b/validator/keymanager/v1/remote_test.go deleted file mode 100644 index 4cefe9341083..000000000000 --- a/validator/keymanager/v1/remote_test.go +++ /dev/null @@ -1,165 +0,0 @@ -package v1_test - -import ( - "fmt" - "io/ioutil" - "os" - "strings" - "testing" - - "github.com/prysmaticlabs/prysm/shared/params" - "github.com/prysmaticlabs/prysm/shared/testutil" - "github.com/prysmaticlabs/prysm/shared/testutil/require" - keymanager "github.com/prysmaticlabs/prysm/validator/keymanager/v1" -) - -var validClientCert = `-----BEGIN CERTIFICATE----- -MIIEITCCAgmgAwIBAgIQXUJWQZgVO4IX+zlWGI1/mTANBgkqhkiG9w0BAQsFADAU -MRIwEAYDVQQDEwlBdHRlc3RhbnQwHhcNMjAwMzE3MDgwNjU3WhcNMjEwOTE3MDc1 -OTUyWjASMRAwDgYDVQQDEwdjbGllbnQxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A -MIIBCgKCAQEAsc977g16Tan2j7YuA+zQOlDntb4Bkfs4sDOznOEvnozHwRZOgfcP -jVcA9AS5eZOGIRrsTssptrgVNDPoIHWoKk7LAKyyLM3dGp5PWeyMBoQA5cq+yPAT -4JkJpDnBFfwxXB99osJH0z3jSTRa62CSVvPRBisK4B9AlLQfcleEQlKJugy9tOAj -G7zodwEi+J4AYQHmOiwL38ZsKq9We5y4HMQ0E7de0FoU5QHrtuPNrTuwVwrq825l -cEAAFey6Btngx+sziysPHWHYOq4xOZ1UPBApeaAFLguzusc/4VwM7kzRNr4VOD8a -eC3CtKLhBBVVxHI5ZlaHS+YylNGYD4+FxQIDAQABo3EwbzAOBgNVHQ8BAf8EBAMC -A7gwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMB0GA1UdDgQWBBQDGCE0 -3k4rHzB+Ycf3pt1MzeDPgzAfBgNVHSMEGDAWgBScIYZa4dQBIW/gVwR0ctGCuHhe -9jANBgkqhkiG9w0BAQsFAAOCAgEAHG/EfvqIwbhYfci+zRCYC7aQPuvhivJblBwN -mbXo2qsxvje1hcKm0ptJLOy/cjJzeLJYREhQlXDPRJC/xgELnbXRjgag82r35+pf -wVJwP6Yw53VCM3o0QKsUrKyMm4sAijOBrJyqpB5untAieZsry5Bfj0S4YobbtdJa -VsEioU07fVVczf5lYN0XrLgRnXq3LMkTiZ6drFiqLkwmXQZVxNujmcaFSm7yCALl -EdhYNmaqedS5me5UOGxwPacrsZwWF9dvMsl3OswgTcaGdsUtx2/q+S2vbZUAM/Gw -qaTanDfvVtVTF7KzVN9hiqKe4mO0HHHK2HWJYBLdRJjInOgRW+53hCmUhLxD+Dq+ -31jLKxn/Y4hyH9E+55b1sJHCFpsbEtVD53fojiH2C/uLbhq4Wr1PXgOoxzf2KeSQ -B3ENu8C4b6AlNhqOnz5zeDcx8Ug0vMfVDAwf6RAYMG5b/MoWNKcLNXhk8H1nbVkt -16ppjh6I27JqfNqfP2J/p3BF++ZugZuWfN9DRaJ6UPz+yyF7eW8fyDAQNl7LS0Kh -8PlF5cYvyIIKVHe38Mn8ZAWboKUs0xNv2vhA9V/4Q1ZzAEkXjmbk8H26sjGvJnvg -Lgm/+6LVWR4EnUlU8aEWASEpTWq2lSRF3ZOvNstHnufyiDfcwDcl/IKKQiVQQ3mX -tw8Jf74= ------END CERTIFICATE-----` -var validClientKey = `-----BEGIN RSA PRIVATE KEY----- -MIIEpAIBAAKCAQEAsc977g16Tan2j7YuA+zQOlDntb4Bkfs4sDOznOEvnozHwRZO -gfcPjVcA9AS5eZOGIRrsTssptrgVNDPoIHWoKk7LAKyyLM3dGp5PWeyMBoQA5cq+ -yPAT4JkJpDnBFfwxXB99osJH0z3jSTRa62CSVvPRBisK4B9AlLQfcleEQlKJugy9 -tOAjG7zodwEi+J4AYQHmOiwL38ZsKq9We5y4HMQ0E7de0FoU5QHrtuPNrTuwVwrq -825lcEAAFey6Btngx+sziysPHWHYOq4xOZ1UPBApeaAFLguzusc/4VwM7kzRNr4V -OD8aeC3CtKLhBBVVxHI5ZlaHS+YylNGYD4+FxQIDAQABAoIBAQCjV2MVcDQmHDhw -FH95A5bVu3TgM8flfs64rwYU25iPIexuqDs+kOMsh/xMLfrkgGz7BGyIhYGwZLK1 -3ekjyHHPS8qYuAyFtCelSEDE7tRDOAhLEFDq7gCUloGQ561EsQP3CMa1OZwZpgSh -PwM2ruRAFIK0E95NvOfqsv0gYN0Svo7hYjNsvW6ok/ZGMyN2ikcRR04wGOFOGjfT -xTmfURc9ejnOjHAOqLTpToPwM1/gWWR2iMQefC4njy4MO2BXqOPUmHxmmR4PYhu2 -8EcKbyRs+/fvL3GgD3VAlOe5vnkfBzssQhHmexgSk5lHZrcSxUGXYGrYKPAeV2mk -5HRBWp0RAoGBAOUn5w+NCAugcTGP0hfNlyGXsXqUZvnMyFWvUcxgzgPlJyEyDnKn -aIb1DFOF2HckCfLZdrHqqgaF6K3TDvW9BgSKIsvISpo1S95ZPD6DKUo6YQ10CQRW -q/ZZVbxtFksVgFRGYpCVmPNULmx7CiXDT1b/suwNMAwCZwiNPTSvKQVLAoGBAMaj -zDo1/eepRslqnz5s8hh7dGEjfG/ZJcLgAJAxCyAgnIP4Tls7QkNhCVp9LcN6i1bc -CnT6AIuZRXSJWEdp4k2QnVFUmh9Q5MGgwrKYSY5M/1puTISlF1yQ8J6FX8BlDVmy -4dyaSyC0RIvgBzF9/KBDxxmJcHgGQ0awLeeyl4cvAoGBAN83FS3itLmOmXQrofyp -uNNyDeFXeU9OmL5OPqGUkljc+Favib9JLtp3DIC3WfoD0uUJy0LXULN18QaRFnts -mtYFMIvMGE9KJxL5XWOPI8M4Rp1yL+5X9r3Km2cl45dT5GMzBIPOFOTBVU86MtJC -A6C9Bi5FUk4AcRi1a69MB+stAoGAWNiwoyS9IV38dGCFQ4W1LzAg2MXnhZuJoUVR -2yykfkU33Gs2mOXDeKGxblDpJDLumfYnkzSzA72VbE92NdLtTqYtR1Bg8zraZqTC -EOG+nLBh0o/dF8ND1LpbdXvQXRyVwRYaofI9Qi5/LlUQwplIYmKObiSkMnsSok5w -6d5emi8CgYBjtUihOFaAmgqkTHOn4j4eKS1O7/H8QQSVe5M0bocmAIbgJ4At3GnI -E1JcIY2SZtSwAWs6aQPGE42gwsNCCsQWdJNtViO23JbCwlcPToC4aDfc0JJNaYqp -oVV7C5jmJh9VRd2tXIXIZMMNOfThfNf2qDQuJ1S2t5KugozFiRsHUg== ------END RSA PRIVATE KEY-----` - -func TestNewRemoteWallet(t *testing.T) { - tests := []struct { - name string - opts string - clientCert string - clientKey string - caCert string - err string - }{ - { - name: "Empty", - opts: ``, - err: "unexpected end of JSON input", - }, - { - name: "NoAccounts", - opts: `{}`, - err: "at least one account specifier is required", - }, - { - name: "NoCertificates", - opts: `{"accounts":["foo"]}`, - err: "certificates are required", - }, - { - name: "NoClientCertificate", - opts: `{"accounts":["foo"],"certificates":{}}`, - err: "client certificate is required", - }, - { - name: "NoClientKey", - opts: `{"accounts":["foo"],"certificates":{"client_cert":"foo"}}`, - err: "client key is required", - }, - { - name: "MissingClientKey", - opts: `{"accounts":["foo"],"certificates":{"client_cert":"foo","client_key":"bar"}}`, - err: "failed to obtain client's certificate and/or key: open foo: no such file or directory", - }, - { - name: "BadClientCert", - clientCert: `bad`, - clientKey: validClientKey, - opts: `{"accounts":["foo"],"certificates":{"client_cert":"<>","client_key":"<>"}}`, - err: "failed to obtain client's certificate and/or key: tls: failed to find any PEM data in certificate input", - }, - { - name: "BadClientKey", - clientCert: validClientCert, - clientKey: `bad`, - opts: `{"accounts":["foo"],"certificates":{"client_cert":"<>","client_key":"<>"}}`, - err: "failed to obtain client's certificate and/or key: tls: failed to find any PEM data in key input", - }, - { - name: "MissingCACert", - clientCert: validClientCert, - clientKey: validClientKey, - opts: `{"accounts":["foo"],"certificates":{"client_cert":"<>","client_key":"<>","ca_cert":"bad"}}`, - err: "failed to obtain server's CA certificate: open bad: no such file or directory", - }, - } - - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - - if test.caCert != "" || test.clientCert != "" || test.clientKey != "" { - dir := fmt.Sprintf("%s/%s", testutil.TempDir(), test.name) - require.NoError(t, os.MkdirAll(dir, 0777)) - if test.caCert != "" { - caCertPath := fmt.Sprintf("%s/ca.crt", dir) - err := ioutil.WriteFile(caCertPath, []byte(test.caCert), params.BeaconIoConfig().ReadWritePermissions) - require.NoError(t, err, "Failed to write CA certificate") - test.opts = strings.ReplaceAll(test.opts, "<>", caCertPath) - } - if test.clientCert != "" { - clientCertPath := fmt.Sprintf("%s/client.crt", dir) - err := ioutil.WriteFile(clientCertPath, []byte(test.clientCert), params.BeaconIoConfig().ReadWritePermissions) - require.NoError(t, err, "Failed to write client certificate") - test.opts = strings.ReplaceAll(test.opts, "<>", clientCertPath) - } - if test.clientKey != "" { - clientKeyPath := fmt.Sprintf("%s/client.key", dir) - err := ioutil.WriteFile(clientKeyPath, []byte(test.clientKey), params.BeaconIoConfig().ReadWritePermissions) - require.NoError(t, err, "Failed to write client key") - test.opts = strings.ReplaceAll(test.opts, "<>", clientKeyPath) - } - } - - _, _, err := keymanager.NewRemoteWallet(test.opts) - if test.err == "" { - require.NoError(t, err) - } else { - require.ErrorContains(t, test.err, err) - } - }) - } -} diff --git a/validator/keymanager/v1/wallet.go b/validator/keymanager/v1/wallet.go deleted file mode 100644 index cd2bba3df0ca..000000000000 --- a/validator/keymanager/v1/wallet.go +++ /dev/null @@ -1,159 +0,0 @@ -package v1 - -import ( - "context" - "encoding/json" - "errors" - "fmt" - "os" - "regexp" - "strings" - - "github.com/prysmaticlabs/prysm/shared/bls" - "github.com/prysmaticlabs/prysm/shared/bytesutil" - e2wallet "github.com/wealdtech/go-eth2-wallet" - filesystem "github.com/wealdtech/go-eth2-wallet-store-filesystem" - e2wtypes "github.com/wealdtech/go-eth2-wallet-types/v2" -) - -type walletOpts struct { - Location string `json:"location"` - Accounts []string `json:"accounts"` - Passphrases []string `json:"passphrases"` -} - -var walletOptsHelp = `The wallet key manager stores keys in a local encrypted store. The options are: - - location This is the location to look for wallets. If not supplied it will - use the standard (operating system-dependent) path. - - accounts This is a list of account specifiers. An account specifier is of - the form /[account name], where the account name can be a - regular expression. If the account specifier is just all - accounts in that wallet will be used. Multiple account specifiers can be - supplied if required. - - passphrase This is the passphrase used to encrypt the accounts when they - were created. Multiple passphrases can be supplied if required. - -An sample keymanager options file (with annotations; these should be removed if -using this as a template) is: - - { - "location": "/wallets", // Look for wallets in the directory '/wallets' - "accounts": ["Validators/Account.*"], // Use all accounts in the 'Validators' wallet starting with 'Account' - "passphrases": ["secret1","secret2"] // Use the passphrases 'secret1' and 'secret2' to decrypt accounts - }` - -// NewWallet creates a key manager populated with the keys from a wallet at the given path. -func NewWallet(input string) (KeyManager, string, error) { - opts := &walletOpts{} - err := json.Unmarshal([]byte(input), opts) - if err != nil { - return nil, walletOptsHelp, err - } - - if len(opts.Accounts) == 0 { - return nil, walletOptsHelp, errors.New("at least one account specifier is required") - } - - if len(opts.Passphrases) == 0 { - return nil, walletOptsHelp, errors.New("at least one passphrase is required to decrypt accounts") - } - for i, passphrase := range opts.Passphrases { - if strings.HasPrefix(passphrase, "$") { - envPassphrase := os.Getenv(strings.TrimPrefix(passphrase, "$")) - if envPassphrase != "" { - // N.B. We do not log here if the environment variable is not found, as it is possible that this is actually a - // passphrase that just happens to begin with the '$' character. If this is a missing environment variable it will - // be noticed when the account fails to decrypt. - opts.Passphrases[i] = envPassphrase - } - } - } - - km := &Wallet{ - accounts: make(map[[48]byte]e2wtypes.Account), - } - - if strings.Contains(opts.Location, "$") || strings.Contains(opts.Location, "~") || strings.Contains(opts.Location, "%") { - log.WithField("path", opts.Location).Warn("Keystore path contains unexpanded shell expansion characters") - } - var store e2wtypes.Store - if opts.Location == "" { - store = filesystem.New() - } else { - store = filesystem.New(filesystem.WithLocation(opts.Location)) - } - ctx := context.Background() - for _, path := range opts.Accounts { - parts := strings.Split(path, "/") - if parts[0] == "" { - return nil, walletOptsHelp, fmt.Errorf("did not understand account specifier %q", path) - } - wallet, err := e2wallet.OpenWallet(parts[0], e2wallet.WithStore(store)) - if err != nil { - return nil, walletOptsHelp, err - } - accountSpecifier := "^.*$" - if len(parts) > 1 && len(parts[1]) > 0 { - accountSpecifier = fmt.Sprintf("^%s$", parts[1]) - } - re := regexp.MustCompile(accountSpecifier) - for account := range wallet.Accounts(ctx) { - log := log.WithField("account", fmt.Sprintf("%s/%s", wallet.Name(), account.Name())) - if re.Match([]byte(account.Name())) { - pubKey := bytesutil.ToBytes48(account.PublicKey().Marshal()) - unlocked := false - for _, passphrase := range opts.Passphrases { - locker, ok := account.(e2wtypes.AccountLocker) - if !ok { - log.WithError(err).Trace("Account does not implement the AccountLocker interface") - continue - } - if err := locker.Unlock(ctx, []byte(passphrase)); err != nil { - log.WithError(err).Trace("Failed to unlock account with one of the supplied passphrases") - } else { - km.accounts[pubKey] = account - unlocked = true - break - } - } - if !unlocked { - log.Warn("Failed to unlock account with any supplied passphrase; cannot validate with this key") - } - } - } - } - - return km, walletOptsHelp, nil -} - -// Wallet is a key manager that loads keys from a local Ethereum 2 wallet. -type Wallet struct { - accounts map[[48]byte]e2wtypes.Account -} - -// FetchValidatingKeys fetches the list of public keys that should be used to validate with. -func (km *Wallet) FetchValidatingKeys() ([][48]byte, error) { - res := make([][48]byte, 0, len(km.accounts)) - for pubKey := range km.accounts { - res = append(res, pubKey) - } - return res, nil -} - -// Sign signs a message for the validator to broadcast. -func (km *Wallet) Sign(ctx context.Context, pubKey [48]byte, root [32]byte) (bls.Signature, error) { - account, exists := km.accounts[pubKey] - if !exists { - return nil, ErrNoSuchKey - } - // TODO(#4817) Update with new library to remove domain here. - signer, ok := account.(e2wtypes.AccountSigner) - if !ok { - return nil, errors.New("account does not implement the AccountSigner interface") - } - sig, err := signer.Sign(ctx, root[:]) - if err != nil { - return nil, err - } - return bls.SignatureFromBytes(sig.Marshal()) -} diff --git a/validator/keymanager/v1/wallet_test.go b/validator/keymanager/v1/wallet_test.go deleted file mode 100644 index eeb98eeca294..000000000000 --- a/validator/keymanager/v1/wallet_test.go +++ /dev/null @@ -1,149 +0,0 @@ -package v1_test - -import ( - "context" - "fmt" - "io/ioutil" - "os" - "testing" - - "github.com/prysmaticlabs/prysm/shared/testutil/assert" - "github.com/prysmaticlabs/prysm/shared/testutil/require" - keymanager "github.com/prysmaticlabs/prysm/validator/keymanager/v1" - keystorev4 "github.com/wealdtech/go-eth2-wallet-encryptor-keystorev4" - nd "github.com/wealdtech/go-eth2-wallet-nd/v2" - filesystem "github.com/wealdtech/go-eth2-wallet-store-filesystem" - e2wtypes "github.com/wealdtech/go-eth2-wallet-types/v2" -) - -func SetupWallet(t *testing.T) string { - path, err := ioutil.TempDir("", "") - require.NoError(t, err) - store := filesystem.New(filesystem.WithLocation(path)) - encryptor := keystorev4.New() - - // Create wallets with keys. - ctx := context.Background() - w1, err := nd.CreateWallet(ctx, "Wallet 1", store, encryptor) - unlocker, ok := w1.(e2wtypes.WalletLocker) - require.Equal(t, true, ok) - require.NoError(t, unlocker.Unlock(ctx, nil)) - creator, ok := w1.(e2wtypes.WalletAccountCreator) - require.Equal(t, true, ok) - require.NoError(t, err, "Failed to create wallet") - require.NoError(t, err, "Failed to unlock wallet") - _, err = creator.CreateAccount(ctx, "Account 1", []byte("foo")) - require.NoError(t, err, "Failed to create account 1") - _, err = creator.CreateAccount(ctx, "Account 2", []byte("bar")) - require.NoError(t, err, "Failed to create account 2") - - return path -} - -func wallet(t *testing.T, opts string) keymanager.KeyManager { - km, _, err := keymanager.NewWallet(opts) - require.NoError(t, err) - return km -} - -func TestMultiplePassphrases(t *testing.T) { - path := SetupWallet(t) - defer func() { - assert.NoError(t, os.RemoveAll(path)) - }() - tests := []struct { - name string - wallet keymanager.KeyManager - accounts int - }{ - { - name: "Neither", - wallet: wallet(t, fmt.Sprintf(`{"location":%q,"accounts":["Wallet 1"],"passphrases":["neither"]}`, path)), - accounts: 0, - }, - { - name: "Foo", - wallet: wallet(t, fmt.Sprintf(`{"location":%q,"accounts":["Wallet 1"],"passphrases":["foo"]}`, path)), - accounts: 1, - }, - { - name: "Bar", - wallet: wallet(t, fmt.Sprintf(`{"location":%q,"accounts":["Wallet 1"],"passphrases":["bar"]}`, path)), - accounts: 1, - }, - { - name: "Both", - wallet: wallet(t, fmt.Sprintf(`{"location":%q,"accounts":["Wallet 1"],"passphrases":["foo","bar"]}`, path)), - accounts: 2, - }, - } - - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - keys, err := test.wallet.FetchValidatingKeys() - assert.NoError(t, err) - assert.Equal(t, test.accounts, len(keys), "Found %d keys", len(keys)) - }) - } -} - -func TestEnvPassphrases(t *testing.T) { - path := SetupWallet(t) - defer func() { - assert.NoError(t, os.RemoveAll(path)) - }() - - err := os.Setenv("TESTENVPASSPHRASES_NEITHER", "neither") - require.NoError(t, err, "Error setting environment variable TESTENVPASSPHRASES_NEITHER") - defer func() { - err := os.Unsetenv("TESTENVPASSPHRASES_NEITHER") - require.NoError(t, err, "Error unsetting environment variable TESTENVPASSPHRASES_NEITHER") - }() - err = os.Setenv("TESTENVPASSPHRASES_FOO", "foo") - require.NoError(t, err, "Error setting environment variable TESTENVPASSPHRASES_FOO") - defer func() { - err := os.Unsetenv("TESTENVPASSPHRASES_FOO") - require.NoError(t, err, "Error unsetting environment variable TESTENVPASSPHRASES_FOO") - }() - err = os.Setenv("TESTENVPASSPHRASES_BAR", "bar") - require.NoError(t, err, "Error setting environment variable TESTENVPASSPHRASES_BAR") - defer func() { - err := os.Unsetenv("TESTENVPASSPHRASES_BAR") - require.NoError(t, err, "Error unsetting environment variable TESTENVPASSPHRASES_BAR") - }() - - tests := []struct { - name string - wallet keymanager.KeyManager - accounts int - }{ - { - name: "Neither", - wallet: wallet(t, fmt.Sprintf(`{"location":%q,"accounts":["Wallet 1"],"passphrases":["$TESTENVPASSPHRASES_NEITHER"]}`, path)), - accounts: 0, - }, - { - name: "Foo", - wallet: wallet(t, fmt.Sprintf(`{"location":%q,"accounts":["Wallet 1"],"passphrases":["$TESTENVPASSPHRASES_FOO"]}`, path)), - accounts: 1, - }, - { - name: "Bar", - wallet: wallet(t, fmt.Sprintf(`{"location":%q,"accounts":["Wallet 1"],"passphrases":["$TESTENVPASSPHRASES_BAR"]}`, path)), - accounts: 1, - }, - { - name: "Both", - wallet: wallet(t, fmt.Sprintf(`{"location":%q,"accounts":["Wallet 1"],"passphrases":["$TESTENVPASSPHRASES_FOO","$TESTENVPASSPHRASES_BAR"]}`, path)), - accounts: 2, - }, - } - - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - keys, err := test.wallet.FetchValidatingKeys() - assert.NoError(t, err) - assert.Equal(t, test.accounts, len(keys), "Found %d keys", len(keys)) - }) - } -} diff --git a/validator/main.go b/validator/main.go index accb1fb240d8..3c075a63b78e 100644 --- a/validator/main.go +++ b/validator/main.go @@ -4,33 +4,26 @@ package main import ( - "context" "fmt" "os" "runtime" runtimeDebug "runtime/debug" - "strings" "time" joonix "github.com/joonix/log" - ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1" "github.com/prysmaticlabs/prysm/shared/cmd" "github.com/prysmaticlabs/prysm/shared/debug" "github.com/prysmaticlabs/prysm/shared/featureconfig" "github.com/prysmaticlabs/prysm/shared/journald" "github.com/prysmaticlabs/prysm/shared/logutil" _ "github.com/prysmaticlabs/prysm/shared/maxprocs" - "github.com/prysmaticlabs/prysm/shared/params" "github.com/prysmaticlabs/prysm/shared/version" - v1 "github.com/prysmaticlabs/prysm/validator/accounts/v1" v2 "github.com/prysmaticlabs/prysm/validator/accounts/v2" - "github.com/prysmaticlabs/prysm/validator/client" "github.com/prysmaticlabs/prysm/validator/flags" "github.com/prysmaticlabs/prysm/validator/node" "github.com/sirupsen/logrus" "github.com/urfave/cli/v2" prefixed "github.com/x-cray/logrus-prefixed-formatter" - "google.golang.org/grpc" ) // connTimeout defines a period after which connection to beacon node is cancelled. @@ -52,13 +45,7 @@ var appFlags = []cli.Flag{ flags.BeaconRPCGatewayProviderFlag, flags.CertFlag, flags.GraffitiFlag, - flags.KeystorePathFlag, - flags.SourceDirectories, - flags.SourceDirectory, - flags.TargetDirectory, - flags.PasswordFlag, flags.DisablePenaltyRewardLogFlag, - flags.UnencryptedKeysFlag, flags.InteropStartIndex, flags.InteropNumValidators, flags.EnableRPCFlag, @@ -70,15 +57,12 @@ var appFlags = []cli.Flag{ flags.GrpcRetryDelayFlag, flags.GrpcHeadersFlag, flags.GPRCGatewayCorsDomain, - flags.KeyManager, - flags.KeyManagerOpts, flags.DisableAccountMetricsFlag, cmd.MonitoringHostFlag, flags.MonitoringPortFlag, cmd.DisableMonitoringFlag, flags.SlasherRPCProviderFlag, flags.SlasherCertFlag, - flags.DeprecatedPasswordsDirFlag, flags.WalletPasswordFileFlag, flags.WalletDirFlag, flags.EnableWebFlag, @@ -121,197 +105,6 @@ func main() { app.Commands = []*cli.Command{ v2.WalletCommands, v2.AccountCommands, - { - Name: "accounts", - Category: "accounts", - Usage: "defines useful functions for interacting with the validator client's account", - Subcommands: []*cli.Command{ - { - Name: "create", - Description: `creates a new validator account keystore containing private keys for Ethereum 2.0 - -this command outputs a deposit data string which can be used to deposit Ether into the ETH1.0 deposit -contract in order to activate the validator client`, - Flags: cmd.WrapFlags(append(featureconfig.ActiveFlags(featureconfig.ValidatorFlags), - []cli.Flag{ - flags.KeystorePathFlag, - flags.PasswordFlag, - cmd.ChainConfigFileFlag, - }...)), - Before: func(cliCtx *cli.Context) error { - return cmd.LoadFlagsFromConfig(cliCtx, cliCtx.Command.Flags) - }, - Action: func(cliCtx *cli.Context) error { - featureconfig.ConfigureValidator(cliCtx) - - if cliCtx.IsSet(cmd.ChainConfigFileFlag.Name) { - chainConfigFileName := cliCtx.String(cmd.ChainConfigFileFlag.Name) - params.LoadChainConfigFile(chainConfigFileName) - } - - keystorePath, passphrase, err := v1.HandleEmptyKeystoreFlags(cliCtx, true /*confirmPassword*/) - if err != nil { - log.WithError(err).Error("Could not list keys") - return nil - } - if _, _, err := v1.CreateValidatorAccount(keystorePath, passphrase); err != nil { - log.WithField("err", err.Error()).Fatalf("Could not create validator at path: %s", keystorePath) - } - return nil - }, - }, - { - Name: "keys", - Description: `lists the private keys for 'keystore' keymanager keys`, - Flags: cmd.WrapFlags([]cli.Flag{ - flags.KeystorePathFlag, - flags.PasswordFlag, - }), - Before: func(cliCtx *cli.Context) error { - return cmd.LoadFlagsFromConfig(cliCtx, cliCtx.Command.Flags) - }, - Action: func(cliCtx *cli.Context) error { - keystorePath, passphrase, err := v1.HandleEmptyKeystoreFlags(cliCtx, false /*confirmPassword*/) - if err != nil { - log.WithError(err).Error("Could not list keys") - } - if err := v1.PrintPublicAndPrivateKeys(keystorePath, passphrase); err != nil { - log.WithError(err).Errorf("Could not list private and public keys in path %s", keystorePath) - } - return nil - }, - }, - { - Name: "status", - Description: `list the validator status for existing validator keys`, - Flags: cmd.WrapFlags([]cli.Flag{ - cmd.GrpcMaxCallRecvMsgSizeFlag, - flags.BeaconRPCProviderFlag, - flags.CertFlag, - flags.GrpcHeadersFlag, - flags.GrpcRetriesFlag, - flags.GrpcRetryDelayFlag, - flags.KeyManager, - flags.KeyManagerOpts, - }), - Before: func(cliCtx *cli.Context) error { - return cmd.LoadFlagsFromConfig(cliCtx, cliCtx.Command.Flags) - }, - Action: func(cliCtx *cli.Context) error { - var err error - var pubKeys [][]byte - if cliCtx.String(flags.KeyManager.Name) == "" { - keystorePath, passphrase, err := v1.HandleEmptyKeystoreFlags(cliCtx, false /*confirmPassword*/) - if err != nil { - return err - } - pubKeys, err = v1.ExtractPublicKeysFromKeyStore(keystorePath, passphrase) - if err != nil { - return err - } - } - ctx, cancel := context.WithTimeout(cliCtx.Context, connTimeout) - defer cancel() - dialOpts := client.ConstructDialOptions( - cliCtx.Int(cmd.GrpcMaxCallRecvMsgSizeFlag.Name), - cliCtx.String(flags.CertFlag.Name), - strings.Split(cliCtx.String(flags.GrpcHeadersFlag.Name), ","), - cliCtx.Uint(flags.GrpcRetriesFlag.Name), - cliCtx.Duration(flags.GrpcRetryDelayFlag.Name), - grpc.WithBlock()) - endpoint := cliCtx.String(flags.BeaconRPCProviderFlag.Name) - conn, err := grpc.DialContext(ctx, endpoint, dialOpts...) - if err != nil { - log.WithError(err).Errorf("Failed to dial beacon node endpoint at %s", endpoint) - return err - } - err = v1.RunStatusCommand(ctx, pubKeys, ethpb.NewBeaconNodeValidatorClient(conn)) - if closed := conn.Close(); closed != nil { - log.WithError(closed).Error("Could not close connection to beacon node") - } - return err - }, - }, - { - Name: "change-password", - Description: "changes password for all keys located in a keystore", - Flags: cmd.WrapFlags([]cli.Flag{ - flags.KeystorePathFlag, - flags.PasswordFlag, - }), - Before: func(cliCtx *cli.Context) error { - return cmd.LoadFlagsFromConfig(cliCtx, cliCtx.Command.Flags) - }, - Action: func(cliCtx *cli.Context) error { - keystorePath, oldPassword, err := v1.HandleEmptyKeystoreFlags(cliCtx, false /*confirmPassword*/) - if err != nil { - log.WithError(err).Error("Could not read keystore path and/or the old password") - } - - log.Info("Please enter the new password") - newPassword, err := cmd.EnterPassword(true, cmd.StdInPasswordReader{}) - if err != nil { - log.WithError(err).Error("Could not read the new password") - } - - err = v1.ChangePassword(keystorePath, oldPassword, newPassword) - if err != nil { - log.WithError(err).Error("Changing password failed") - } else { - log.Info("Password changed successfully") - } - - return nil - }, - }, - { - Name: "merge", - Description: "merges data from several validator databases into a new validator database", - Flags: cmd.WrapFlags([]cli.Flag{ - flags.SourceDirectories, - flags.TargetDirectory, - }), - Before: func(cliCtx *cli.Context) error { - return cmd.LoadFlagsFromConfig(cliCtx, cliCtx.Command.Flags) - }, - Action: func(cliCtx *cli.Context) error { - passedSources := cliCtx.String(flags.SourceDirectories.Name) - sources := strings.Split(passedSources, ",") - target := cliCtx.String(flags.TargetDirectory.Name) - - if err := v1.Merge(cliCtx.Context, sources, target); err != nil { - log.WithError(err).Error("Merging validator data failed") - } else { - log.Info("Merge completed successfully") - } - - return nil - }, - }, - { - Name: "split", - Description: "splits one validator database into several databases - one for each public key", - Flags: cmd.WrapFlags([]cli.Flag{ - flags.SourceDirectory, - flags.TargetDirectory, - }), - Before: func(cliCtx *cli.Context) error { - return cmd.LoadFlagsFromConfig(cliCtx, cliCtx.Command.Flags) - }, - Action: func(cliCtx *cli.Context) error { - source := cliCtx.String(flags.SourceDirectory.Name) - target := cliCtx.String(flags.TargetDirectory.Name) - - if err := v1.Split(cliCtx.Context, source, target); err != nil { - log.WithError(err).Error("Splitting validator data failed") - } else { - log.Info("Split completed successfully") - } - - return nil - }, - }, - }, - }, } app.Flags = appFlags @@ -322,8 +115,6 @@ contract in order to activate the validator client`, return err } - flags.ComplainOnDeprecatedFlags(ctx) - format := ctx.String(cmd.LogFormat.Name) switch format { case "text": diff --git a/validator/node/BUILD.bazel b/validator/node/BUILD.bazel index 904b6332c7b2..654c61bd9cd3 100644 --- a/validator/node/BUILD.bazel +++ b/validator/node/BUILD.bazel @@ -10,7 +10,10 @@ go_test( "//shared/testutil:go_default_library", "//shared/testutil/assert:go_default_library", "//shared/testutil/require:go_default_library", - "//validator/accounts/v1:go_default_library", + "//validator/accounts/v2:go_default_library", + "//validator/accounts/v2/wallet:go_default_library", + "//validator/flags:go_default_library", + "//validator/keymanager/v2:go_default_library", "@com_github_sirupsen_logrus//hooks/test:go_default_library", "@com_github_urfave_cli_v2//:go_default_library", ], @@ -37,7 +40,6 @@ go_library( "//validator/client:go_default_library", "//validator/db/kv:go_default_library", "//validator/flags:go_default_library", - "//validator/keymanager/v1:go_default_library", "//validator/keymanager/v2:go_default_library", "//validator/keymanager/v2/direct:go_default_library", "//validator/rpc:go_default_library", diff --git a/validator/node/node.go b/validator/node/node.go index 1d7b19346ab5..5de292c8772b 100644 --- a/validator/node/node.go +++ b/validator/node/node.go @@ -5,7 +5,6 @@ package node import ( "fmt" - "io/ioutil" "os" "os/signal" "path/filepath" @@ -29,7 +28,6 @@ import ( "github.com/prysmaticlabs/prysm/validator/client" "github.com/prysmaticlabs/prysm/validator/db/kv" "github.com/prysmaticlabs/prysm/validator/flags" - v1 "github.com/prysmaticlabs/prysm/validator/keymanager/v1" v2 "github.com/prysmaticlabs/prysm/validator/keymanager/v2" "github.com/prysmaticlabs/prysm/validator/keymanager/v2/direct" "github.com/prysmaticlabs/prysm/validator/rpc" @@ -157,48 +155,39 @@ func (s *ValidatorClient) Close() { } func (s *ValidatorClient) initializeFromCLI(cliCtx *cli.Context) error { - var keyManagerV1 v1.KeyManager var keyManagerV2 v2.IKeymanager var err error var accountsDir string - if featureconfig.Get().EnableAccountsV2 { - if cliCtx.IsSet(flags.InteropNumValidators.Name) { - numValidatorKeys := cliCtx.Uint64(flags.InteropNumValidators.Name) - offset := cliCtx.Uint64(flags.InteropStartIndex.Name) - keyManagerV2, err = direct.NewInteropKeymanager(cliCtx.Context, offset, numValidatorKeys) - if err != nil { - return errors.Wrap(err, "could not generate interop keys") - } - accountsDir = cliCtx.String(flags.KeystorePathFlag.Name) - } else { - // Read the wallet from the specified path. - w, err := wallet.OpenWalletOrElseCli(cliCtx, func(cliCtx *cli.Context) (*wallet.Wallet, error) { - return nil, errors.New("no wallet found, create a new one with validator wallet-v2 create") - }) - if err != nil { - return errors.Wrap(err, "could not open wallet") - } - s.wallet = w - log.WithFields(logrus.Fields{ - "wallet": w.AccountsDir(), - "keymanager-kind": w.KeymanagerKind().String(), - }).Info("Opened validator wallet") - keyManagerV2, err = w.InitializeKeymanager( - cliCtx.Context, false, /* skipMnemonicConfirm */ - ) - if err != nil { - return errors.Wrap(err, "could not read keymanager for wallet") - } - if err := w.LockWalletConfigFile(cliCtx.Context); err != nil { - log.Fatalf("Could not get a lock on wallet file. Please check if you have another validator instance running and using the same wallet: %v", err) - } - accountsDir = s.wallet.AccountsDir() + if cliCtx.IsSet(flags.InteropNumValidators.Name) { + numValidatorKeys := cliCtx.Uint64(flags.InteropNumValidators.Name) + offset := cliCtx.Uint64(flags.InteropStartIndex.Name) + keyManagerV2, err = direct.NewInteropKeymanager(cliCtx.Context, offset, numValidatorKeys) + if err != nil { + return errors.Wrap(err, "could not generate interop keys") } } else { - keyManagerV1, err = selectV1Keymanager(cliCtx) + // Read the wallet from the specified path. + w, err := wallet.OpenWalletOrElseCli(cliCtx, func(cliCtx *cli.Context) (*wallet.Wallet, error) { + return nil, errors.New("no wallet found, create a new one with validator wallet-v2 create") + }) if err != nil { - return err + return errors.Wrap(err, "could not open wallet") + } + s.wallet = w + log.WithFields(logrus.Fields{ + "wallet": w.AccountsDir(), + "keymanager-kind": w.KeymanagerKind().String(), + }).Info("Opened validator wallet") + keyManagerV2, err = w.InitializeKeymanager( + cliCtx.Context, false, /* skipMnemonicConfirm */ + ) + if err != nil { + return errors.Wrap(err, "could not read keymanager for wallet") } + if err := w.LockWalletConfigFile(cliCtx.Context); err != nil { + log.Fatalf("Could not get a lock on wallet file. Please check if you have another validator instance running and using the same wallet: %v", err) + } + accountsDir = s.wallet.AccountsDir() } dataDir := moveDb(cliCtx, accountsDir) @@ -236,7 +225,7 @@ func (s *ValidatorClient) initializeFromCLI(cliCtx *cli.Context) error { return err } } - if err := s.registerClientService(keyManagerV1, keyManagerV2); err != nil { + if err := s.registerClientService(keyManagerV2); err != nil { return err } if cliCtx.Bool(flags.EnableRPCFlag.Name) { @@ -305,7 +294,7 @@ func (s *ValidatorClient) initializeForWeb(cliCtx *cli.Context) error { return err } } - if err := s.registerClientService(nil, nil); err != nil { + if err := s.registerClientService(nil); err != nil { return err } if err := s.registerRPCService(cliCtx); err != nil { @@ -327,7 +316,6 @@ func (s *ValidatorClient) registerPrometheusService() error { } func (s *ValidatorClient) registerClientService( - keyManager v1.KeyManager, keyManagerV2 v2.IKeymanager, ) error { endpoint := s.cliCtx.String(flags.BeaconRPCProviderFlag.Name) @@ -347,7 +335,6 @@ func (s *ValidatorClient) registerClientService( v, err := client.NewValidatorService(s.cliCtx.Context, &client.Config{ Endpoint: endpoint, DataDir: dataDir, - KeyManager: keyManager, KeyManagerV2: keyManagerV2, LogValidatorBalances: logValidatorBalances, EmitAccountMetrics: emitAccountMetrics, @@ -440,74 +427,6 @@ func (s *ValidatorClient) registerWebService(cliCtx *cli.Context) error { return s.services.RegisterService(srv) } -// Selects the key manager depending on the options provided by the user. -func selectV1Keymanager(ctx *cli.Context) (v1.KeyManager, error) { - manager := strings.ToLower(ctx.String(flags.KeyManager.Name)) - opts := ctx.String(flags.KeyManagerOpts.Name) - if opts == "" { - opts = "{}" - } else if !strings.HasPrefix(opts, "{") { - fileopts, err := ioutil.ReadFile(opts) - if err != nil { - return nil, errors.Wrap(err, "Failed to read keymanager options file") - } - opts = string(fileopts) - } - - if manager == "" { - // Attempt to work out keymanager from deprecated vars. - if unencryptedKeys := ctx.String(flags.UnencryptedKeysFlag.Name); unencryptedKeys != "" { - manager = "unencrypted" - opts = fmt.Sprintf(`{"path":%q}`, unencryptedKeys) - log.Warn(fmt.Sprintf("--unencrypted-keys flag is deprecated. Please use --keymanager=unencrypted --keymanageropts='%s'", opts)) - } else if numValidatorKeys := ctx.Uint64(flags.InteropNumValidators.Name); numValidatorKeys > 0 { - manager = "interop" - opts = fmt.Sprintf(`{"keys":%d,"offset":%d}`, numValidatorKeys, ctx.Uint64(flags.InteropStartIndex.Name)) - log.Warn(fmt.Sprintf("--interop-num-validators and --interop-start-index flags are deprecated. Please use --keymanager=interop --keymanageropts='%s'", opts)) - } else if keystorePath := ctx.String(flags.KeystorePathFlag.Name); keystorePath != "" { - manager = "keystore" - opts = fmt.Sprintf(`{"path":%q,"passphrase":%q}`, keystorePath, ctx.String(flags.PasswordFlag.Name)) - log.Warn(fmt.Sprintf("--keystore-path flag is deprecated. Please use --keymanager=keystore --keymanageropts='%s'", opts)) - } else { - // Default if no choice made - manager = "keystore" - passphrase := ctx.String(flags.PasswordFlag.Name) - if passphrase == "" { - log.Warn("Implicit selection of keymanager is deprecated. Please use --keymanager=keystore or select a different keymanager") - } else { - opts = fmt.Sprintf(`{"passphrase":%q}`, passphrase) - log.Warn(`Implicit selection of keymanager is deprecated. Please use --keymanager=keystore --keymanageropts='{"passphrase":""}' or select a different keymanager`) - } - } - } - - var km v1.KeyManager - var help string - var err error - switch manager { - case "interop": - km, help, err = v1.NewInterop(opts) - case "unencrypted": - km, help, err = v1.NewUnencrypted(opts) - case "keystore": - km, help, err = v1.NewKeystore(opts) - case "wallet": - km, help, err = v1.NewWallet(opts) - case "remote": - km, help, err = v1.NewRemoteWallet(opts) - default: - return nil, fmt.Errorf("unknown keymanager %q", manager) - } - if err != nil { - if help != "" { - // Print help for the keymanager - fmt.Println(help) - } - return nil, err - } - return km, nil -} - func clearDB(dataDir string, force bool) error { var err error clearDBConfirmed := force diff --git a/validator/node/node_test.go b/validator/node/node_test.go index 68eec6588a3b..846e80c2d023 100644 --- a/validator/node/node_test.go +++ b/validator/node/node_test.go @@ -4,6 +4,7 @@ import ( "crypto/rand" "flag" "fmt" + "io/ioutil" "math/big" "os" "path/filepath" @@ -12,7 +13,10 @@ import ( "github.com/prysmaticlabs/prysm/shared/testutil" "github.com/prysmaticlabs/prysm/shared/testutil/assert" "github.com/prysmaticlabs/prysm/shared/testutil/require" - v1 "github.com/prysmaticlabs/prysm/validator/accounts/v1" + v2 "github.com/prysmaticlabs/prysm/validator/accounts/v2" + "github.com/prysmaticlabs/prysm/validator/accounts/v2/wallet" + "github.com/prysmaticlabs/prysm/validator/flags" + v2keymanager "github.com/prysmaticlabs/prysm/validator/keymanager/v2" logTest "github.com/sirupsen/logrus/hooks/test" "github.com/urfave/cli/v2" ) @@ -22,20 +26,37 @@ func TestNode_Builds(t *testing.T) { app := cli.App{} set := flag.NewFlagSet("test", 0) set.String("datadir", testutil.TempDir()+"/datadir", "the node data directory") - dir := testutil.TempDir() + "/keystore1" + dir := testutil.TempDir() + "/walletpath" + passwordDir := testutil.TempDir() + "/password" + require.NoError(t, os.MkdirAll(passwordDir, os.ModePerm)) + passwordFile := filepath.Join(passwordDir, "password.txt") + walletPassword := "$$Passw0rdz2$$" + require.NoError(t, ioutil.WriteFile( + passwordFile, + []byte(walletPassword), + os.ModePerm, + )) defer func() { assert.NoError(t, os.RemoveAll(dir)) - }() - defer func() { + assert.NoError(t, os.RemoveAll(passwordDir)) assert.NoError(t, os.RemoveAll(testutil.TempDir()+"/datadir")) }() - set.String("keystore-path", dir, "path to keystore") - set.String("password", "1234", "validator account password") + set.String("wallet-dir", dir, "path to wallet") + set.String("wallet-password-file", passwordFile, "path to wallet password") + set.String("keymanager-kind", "direct", "keymanager kind") set.String("verbosity", "debug", "log verbosity") - set.Bool("disable-accounts-v2", true, "disabling accounts v2") + require.NoError(t, set.Set(flags.WalletPasswordFileFlag.Name, passwordFile)) context := cli.NewContext(&app, set, nil) + w, err := v2.CreateWalletWithKeymanager(context.Context, &v2.CreateWalletConfig{ + WalletCfg: &wallet.Config{ + WalletDir: dir, + KeymanagerKind: v2keymanager.Direct, + WalletPassword: walletPassword, + }, + }) + require.NoError(t, err) + require.NoError(t, w.SaveHashedPassword(context.Context)) - require.NoError(t, v1.NewValidatorAccount(dir, "1234"), "Could not create validator account") valClient, err := NewValidatorClient(context) require.NoError(t, err, "Failed to create ValidatorClient") err = valClient.db.Close() diff --git a/validator/usage.go b/validator/usage.go index 71f4f7b1e983..15fc107702fd 100644 --- a/validator/usage.go +++ b/validator/usage.go @@ -84,12 +84,7 @@ var appHelpFlagGroups = []flagGroup{ flags.EnableWebFlag, flags.WebHostFlag, flags.WebPortFlag, - flags.KeyManager, - flags.KeyManagerOpts, - flags.KeystorePathFlag, - flags.PasswordFlag, flags.DisablePenaltyRewardLogFlag, - flags.UnencryptedKeysFlag, flags.GraffitiFlag, flags.EnableRPCFlag, flags.RPCHost, @@ -102,12 +97,8 @@ var appHelpFlagGroups = []flagGroup{ flags.GrpcHeadersFlag, flags.SlasherRPCProviderFlag, flags.SlasherCertFlag, - flags.SourceDirectories, - flags.SourceDirectory, - flags.TargetDirectory, flags.DisableAccountMetricsFlag, flags.WalletDirFlag, - flags.DeprecatedPasswordsDirFlag, flags.WalletPasswordFileFlag, }, },