@@ -2,47 +2,222 @@ package gnosis
2
2
3
3
import (
4
4
"context"
5
+ "math"
5
6
7
+ "github.com/ethereum/go-ethereum/common"
8
+ "github.com/jackc/pgx/v4"
9
+ "github.com/jackc/pgx/v4/pgxpool"
6
10
pubsub "github.com/libp2p/go-libp2p-pubsub"
7
11
"github.com/pkg/errors"
12
+ "github.com/rs/zerolog/log"
8
13
14
+ obskeyperdatabase "github.com/shutter-network/rolling-shutter/rolling-shutter/chainobserver/db/keyper"
15
+ corekeyperdatabase "github.com/shutter-network/rolling-shutter/rolling-shutter/keyper/database"
16
+ "github.com/shutter-network/rolling-shutter/rolling-shutter/keyperimpl/gnosis/database"
9
17
"github.com/shutter-network/rolling-shutter/rolling-shutter/p2pmsg"
18
+ "github.com/shutter-network/rolling-shutter/rolling-shutter/shdb"
10
19
)
11
20
12
- type DecryptionKeySharesHandler struct {}
21
+ type DecryptionKeySharesHandler struct {
22
+ dbpool * pgxpool.Pool
23
+ }
13
24
14
25
func (h * DecryptionKeySharesHandler ) MessagePrototypes () []p2pmsg.Message {
15
26
return []p2pmsg.Message {& p2pmsg.DecryptionKeyShares {}}
16
27
}
17
28
18
29
func (h * DecryptionKeySharesHandler ) ValidateMessage (_ context.Context , msg p2pmsg.Message ) (pubsub.ValidationResult , error ) {
19
30
keyShares := msg .(* p2pmsg.DecryptionKeyShares )
20
- _ , ok := keyShares .Extra .(* p2pmsg.DecryptionKeyShares_Gnosis )
31
+ extra , ok := keyShares .Extra .(* p2pmsg.DecryptionKeyShares_Gnosis )
21
32
if ! ok {
22
33
return pubsub .ValidationReject , errors .Errorf ("unexpected extra type %T, expected Gnosis" , keyShares .Extra )
23
34
}
35
+ if extra .Gnosis == nil {
36
+ return pubsub .ValidationReject , errors .New ("missing extra Gnosis data" )
37
+ }
38
+
39
+ if extra .Gnosis .Slot > math .MaxInt64 {
40
+ return pubsub .ValidationReject , errors .New ("slot number too large" )
41
+ }
42
+ if extra .Gnosis .TxPointer > math .MaxInt64 {
43
+ return pubsub .ValidationReject , errors .New ("tx pointer too large" )
44
+ }
45
+ // TODO: check signature
46
+
24
47
return pubsub .ValidationAccept , nil
25
48
}
26
49
27
- func (h * DecryptionKeySharesHandler ) HandleMessage (_ context.Context , _ p2pmsg.Message ) ([]p2pmsg.Message , error ) {
50
+ func (h * DecryptionKeySharesHandler ) HandleMessage (ctx context.Context , msg p2pmsg.Message ) ([]p2pmsg.Message , error ) {
51
+ keyShares := msg .(* p2pmsg.DecryptionKeyShares )
52
+ extra := keyShares .Extra .(* p2pmsg.DecryptionKeyShares_Gnosis ).Gnosis
53
+
54
+ gnosisDB := database .New (h .dbpool )
55
+ keyperCoreDB := corekeyperdatabase .New (h .dbpool )
56
+ obsKeyperDB := obskeyperdatabase .New (h .dbpool )
57
+
58
+ identitiesHash := computeIdentitiesHashFromShares (keyShares .Shares )
59
+ err := gnosisDB .InsertSlotDecryptionSignature (ctx , database.InsertSlotDecryptionSignatureParams {
60
+ Eon : int64 (keyShares .Eon ),
61
+ Block : int64 (extra .Slot ),
62
+ KeyperIndex : int64 (keyShares .KeyperIndex ),
63
+ TxPointer : int64 (extra .TxPointer ),
64
+ IdentitiesHash : identitiesHash ,
65
+ Signature : extra .Signature ,
66
+ })
67
+ if err != nil {
68
+ return []p2pmsg.Message {}, errors .Wrap (err , "failed to insert tx pointer vote" )
69
+ }
70
+
71
+ eonData , err := keyperCoreDB .GetEon (ctx , int64 (keyShares .Eon ))
72
+ if err != nil {
73
+ return []p2pmsg.Message {}, errors .Wrapf (err , "failed to get eon data from database for eon %d" , keyShares .Eon )
74
+ }
75
+ keyperSet , err := obsKeyperDB .GetKeyperSetByKeyperConfigIndex (ctx , eonData .KeyperConfigIndex )
76
+ if err != nil {
77
+ return []p2pmsg.Message {}, errors .Wrapf (err , "failed to get keyper set from database for eon %d" , keyShares .Eon )
78
+ }
79
+
80
+ signaturesDB , err := gnosisDB .GetSlotDecryptionSignatures (ctx , database.GetSlotDecryptionSignaturesParams {
81
+ Eon : int64 (keyShares .Eon ),
82
+ Block : int64 (extra .Slot ),
83
+ TxPointer : int64 (extra .TxPointer ),
84
+ IdentitiesHash : identitiesHash ,
85
+ Limit : keyperSet .Threshold ,
86
+ })
87
+ if err != nil {
88
+ return []p2pmsg.Message {}, errors .Wrap (err , "failed to count slot decryption signatures" )
89
+ }
90
+
91
+ // send a keys message if we have reached the required number of both the signatures and the key shares
92
+ if len (signaturesDB ) >= int (keyperSet .Threshold ) {
93
+ keys := []* p2pmsg.Key {}
94
+ for _ , share := range keyShares .GetShares () {
95
+ decryptionKeyDB , err := keyperCoreDB .GetDecryptionKey (ctx , corekeyperdatabase.GetDecryptionKeyParams {
96
+ Eon : int64 (keyShares .Eon ),
97
+ EpochID : share .EpochID ,
98
+ })
99
+ if err == pgx .ErrNoRows {
100
+ return []p2pmsg.Message {}, nil
101
+ }
102
+ key := & p2pmsg.Key {
103
+ Identity : share .EpochID ,
104
+ Key : decryptionKeyDB .DecryptionKey ,
105
+ }
106
+ keys = append (keys , key )
107
+ }
108
+ signerIndices := []uint64 {}
109
+ signatures := [][]byte {}
110
+ for _ , signature := range signaturesDB {
111
+ signerIndices = append (signerIndices , uint64 (signature .KeyperIndex ))
112
+ signatures = append (signatures , signature .Signature )
113
+ }
114
+ decryptionKeysMsg := & p2pmsg.DecryptionKeys {
115
+ InstanceID : keyShares .InstanceID ,
116
+ Eon : keyShares .Eon ,
117
+ Keys : keys ,
118
+ Extra : & p2pmsg.DecryptionKeys_Gnosis {
119
+ Gnosis : & p2pmsg.GnosisDecryptionKeysExtra {
120
+ Slot : extra .Slot ,
121
+ TxPointer : extra .TxPointer ,
122
+ SignerIndices : signerIndices ,
123
+ Signatures : signatures ,
124
+ },
125
+ },
126
+ }
127
+ return []p2pmsg.Message {decryptionKeysMsg }, nil
128
+ }
129
+
28
130
return []p2pmsg.Message {}, nil
29
131
}
30
132
31
- type DecryptionKeysHandler struct {}
133
+ type DecryptionKeysHandler struct {
134
+ dbpool * pgxpool.Pool
135
+ }
32
136
33
137
func (h * DecryptionKeysHandler ) MessagePrototypes () []p2pmsg.Message {
34
138
return []p2pmsg.Message {& p2pmsg.DecryptionKeys {}}
35
139
}
36
140
37
- func (h * DecryptionKeysHandler ) ValidateMessage (_ context.Context , msg p2pmsg.Message ) (pubsub.ValidationResult , error ) {
141
+ func (h * DecryptionKeysHandler ) ValidateMessage (ctx context.Context , msg p2pmsg.Message ) (pubsub.ValidationResult , error ) {
38
142
keys := msg .(* p2pmsg.DecryptionKeys )
39
- _ , ok := keys .Extra .(* p2pmsg.DecryptionKeys_Gnosis )
143
+ extra , ok := keys .Extra .(* p2pmsg.DecryptionKeys_Gnosis )
40
144
if ! ok {
41
145
return pubsub .ValidationReject , errors .Errorf ("unexpected extra type %T, expected Gnosis" , keys .Extra )
42
146
}
147
+ if extra .Gnosis == nil {
148
+ return pubsub .ValidationReject , errors .New ("missing extra Gnosis data" )
149
+ }
150
+
151
+ if extra .Gnosis .Slot > math .MaxInt64 {
152
+ return pubsub .ValidationReject , errors .New ("slot number too large" )
153
+ }
154
+ if extra .Gnosis .TxPointer > math .MaxInt32 { // the pointer will have to be incremented
155
+ return pubsub .ValidationReject , errors .New ("tx pointer too large" )
156
+ }
157
+ if len (keys .Keys ) == 0 {
158
+ return pubsub .ValidationReject , errors .New ("msg does not contain any keys" )
159
+ }
160
+
161
+ keyperCoreDB := corekeyperdatabase .New (h .dbpool )
162
+ obsKeyperDB := obskeyperdatabase .New (h .dbpool )
163
+ eonData , err := keyperCoreDB .GetEon (ctx , int64 (keys .Eon ))
164
+ if err != nil {
165
+ return pubsub .ValidationReject , errors .Wrapf (err , "failed to get eon data from database for eon %d" , keys .Eon )
166
+ }
167
+ keyperSet , err := obsKeyperDB .GetKeyperSet (ctx , eonData .ActivationBlockNumber )
168
+ if err != nil {
169
+ return pubsub .ValidationReject , errors .Wrapf (err , "failed to get keyper set from database for eon %d" , keys .Eon )
170
+ }
171
+
172
+ if int32 (len (extra .Gnosis .SignerIndices )) != keyperSet .Threshold {
173
+ return pubsub .ValidationReject , errors .Errorf ("expected %d signers, got %d" , keyperSet .Threshold , len (extra .Gnosis .SignerIndices ))
174
+ }
175
+ signers := []common.Address {}
176
+ for i , signerIndex := range extra .Gnosis .SignerIndices {
177
+ if i >= 1 {
178
+ prevSignerIndex := extra .Gnosis .SignerIndices [i - 1 ]
179
+ if signerIndex == prevSignerIndex {
180
+ return pubsub .ValidationReject , errors .New ("duplicate signer index found" )
181
+ }
182
+ if signerIndex < prevSignerIndex {
183
+ return pubsub .ValidationReject , errors .New ("signer indices not ordered" )
184
+ }
185
+ }
186
+ if signerIndex >= uint64 (len (keyperSet .Keypers )) {
187
+ return pubsub .ValidationReject , errors .New ("signer index out of range" )
188
+ }
189
+ signer , err := shdb .DecodeAddress (keyperSet .Keypers [signerIndex ])
190
+ if err != nil {
191
+ return pubsub .ValidationReject , errors .Wrap (err , "failed to decode signer address" )
192
+ }
193
+ signers = append (signers , signer )
194
+ }
195
+
196
+ // TODO: check signatures
197
+
43
198
return pubsub .ValidationAccept , nil
44
199
}
45
200
46
- func (h * DecryptionKeysHandler ) HandleMessage (_ context.Context , _ p2pmsg.Message ) ([]p2pmsg.Message , error ) {
201
+ func (h * DecryptionKeysHandler ) HandleMessage (ctx context.Context , msg p2pmsg.Message ) ([]p2pmsg.Message , error ) {
202
+ keys := msg .(* p2pmsg.DecryptionKeys )
203
+ extra := keys .Extra .(* p2pmsg.DecryptionKeys_Gnosis ).Gnosis
204
+ gnosisDB := database .New (h .dbpool )
205
+ // the first key is the block key, only the rest are tx keys, so subtract 1
206
+ newTxPointer := int64 (extra .TxPointer ) + int64 (len (keys .Keys )) - 1
207
+ log .Debug ().
208
+ Uint64 ("eon" , keys .Eon ).
209
+ Uint64 ("block" , extra .Slot ).
210
+ Uint64 ("tx-pointer-msg" , extra .TxPointer ).
211
+ Int ("num-keys" , len (keys .Keys )).
212
+ Int64 ("tx-pointer-updated" , newTxPointer ).
213
+ Msg ("updating tx pointer" )
214
+ err := gnosisDB .SetTxPointer (ctx , database.SetTxPointerParams {
215
+ Eon : int64 (keys .Eon ),
216
+ Block : int64 (extra .Slot ),
217
+ Value : newTxPointer ,
218
+ })
219
+ if err != nil {
220
+ return []p2pmsg.Message {}, errors .Wrap (err , "failed to set tx pointer" )
221
+ }
47
222
return []p2pmsg.Message {}, nil
48
223
}
0 commit comments