Skip to content

Commit d81384a

Browse files
committed
mixclient: Wait for KEs from all attempted sessions
This commit modifies the mixing client to consider fully formed sessions (where all peers have sent a KE with matching sessions), even if other sessions have already been attempted after. Previously, only the most recently attempted session would ever be used, and clients would only ratchet-down the peers they would mix with. With this change, initial session disagreement can be recovered from more gracefully, as some peers will form an alternate session matching the session that other peers originally tried. This commit also introduces a fix for a race that could result in root-solving wallets not publishing their solutions in a timely manner, which would result in non-solving wallets eventually being blamed for DC timeout.
1 parent 172eeb5 commit d81384a

File tree

4 files changed

+772
-577
lines changed

4 files changed

+772
-577
lines changed

mixing/mixclient/blame.go

Lines changed: 44 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"fmt"
1212
"math/big"
1313
"sort"
14+
"time"
1415

1516
"github.com/decred/dcrd/chaincfg/chainhash"
1617
"github.com/decred/dcrd/dcrec/secp256k1/v4"
@@ -20,6 +21,8 @@ import (
2021
"github.com/decred/dcrd/wire"
2122
)
2223

24+
var errBlameFailed = errors.New("blame failed")
25+
2326
// blamedIdentities identifies detected misbehaving peers.
2427
//
2528
// If a run returns a blamedIdentities error, these peers are immediately
@@ -48,7 +51,7 @@ func (e blamedIdentities) String() string {
4851
}
4952

5053
func (c *Client) blame(ctx context.Context, sesRun *sessionRun) (err error) {
51-
c.logf("Blaming for sid=%x", sesRun.sid[:])
54+
sesRun.logf("running blame assignment")
5255

5356
mp := c.mixpool
5457
prs := sesRun.prs
@@ -65,14 +68,11 @@ func (c *Client) blame(ctx context.Context, sesRun *sessionRun) (err error) {
6568
}
6669
}()
6770

68-
err = c.sendLocalPeerMsgs(ctx, sesRun, true, func(p *peer) mixing.Message {
69-
// Send initial secrets messages from any peers who detected
70-
// misbehavior.
71-
if !p.triggeredBlame {
72-
return nil
73-
}
74-
return p.rs
75-
})
71+
deadline := time.Now().Add(timeoutDuration)
72+
73+
// Send initial secrets messages from any peers who detected
74+
// misbehavior.
75+
err = c.sendLocalPeerMsgs(ctx, deadline, sesRun, 0)
7676
if err != nil {
7777
return err
7878
}
@@ -87,15 +87,17 @@ func (c *Client) blame(ctx context.Context, sesRun *sessionRun) (err error) {
8787
rsHashes = append(rsHashes, rs.Hash())
8888
}
8989

90-
// Send remaining secrets messages.
91-
err = c.sendLocalPeerMsgs(ctx, sesRun, true, func(p *peer) mixing.Message {
92-
if p.triggeredBlame {
93-
p.triggeredBlame = false
94-
return nil
90+
// Send remaining secrets messages with observed RS hashes from the
91+
// initial peers who published secrets.
92+
c.forLocalPeers(ctx, sesRun, func(p *peer) error {
93+
if !p.triggeredBlame {
94+
if p.rs != nil {
95+
p.rs.SeenSecrets = rsHashes
96+
}
9597
}
96-
p.rs.SeenSecrets = rsHashes
97-
return p.rs
98+
return nil
9899
})
100+
err = c.sendLocalPeerMsgs(ctx, deadline, sesRun, msgRS)
99101
if err != nil {
100102
return err
101103
}
@@ -113,14 +115,14 @@ func (c *Client) blame(ctx context.Context, sesRun *sessionRun) (err error) {
113115
}
114116
if len(rss) != len(sesRun.peers) {
115117
// Blame peers who did not send secrets
116-
c.logf("received %d RSs for %d peers; blaming unresponsive peers",
118+
sesRun.logf("received %d RSs for %d peers; blaming unresponsive peers",
117119
len(rss), len(sesRun.peers))
118120

119121
for _, p := range sesRun.peers {
120122
if p.rs != nil {
121123
continue
122124
}
123-
c.logf("blaming %x for RS timeout", p.id[:])
125+
sesRun.logf("blaming %x for RS timeout", p.id[:])
124126
blamed = append(blamed, *p.id)
125127
}
126128
return blamed
@@ -142,10 +144,14 @@ func (c *Client) blame(ctx context.Context, sesRun *sessionRun) (err error) {
142144
continue
143145
}
144146
id := &rs.Identity
145-
c.logf("blaming %x for false failure accusation", id[:])
147+
sesRun.logf("blaming %x for false failure accusation", id[:])
146148
blamed = append(blamed, *id)
147149
}
148-
err = blamed
150+
if len(blamed) > 0 {
151+
err = blamed
152+
} else {
153+
err = errBlameFailed
154+
}
149155
}()
150156

151157
defer c.mu.Unlock()
@@ -159,7 +165,7 @@ func (c *Client) blame(ctx context.Context, sesRun *sessionRun) (err error) {
159165
KELoop:
160166
for _, p := range sesRun.peers {
161167
if p.ke == nil {
162-
c.logf("blaming %x for missing messages", p.id[:])
168+
sesRun.logf("blaming %x for missing messages", p.id[:])
163169
blamed = append(blamed, *p.id)
164170
continue
165171
}
@@ -169,15 +175,15 @@ KELoop:
169175
cm := p.rs.Commitment(c.blake256Hasher)
170176
c.blake256HasherMu.Unlock()
171177
if cm != p.ke.Commitment {
172-
c.logf("blaming %x for false commitment, got %x want %x",
178+
sesRun.logf("blaming %x for false commitment, got %x want %x",
173179
p.id[:], cm[:], p.ke.Commitment[:])
174180
blamed = append(blamed, *p.id)
175181
continue
176182
}
177183

178184
// Blame peers whose seed is not the correct length (will panic chacha20prng).
179185
if len(p.rs.Seed) != chacha20prng.SeedSize {
180-
c.logf("blaming %x for bad seed size in RS message", p.id[:])
186+
sesRun.logf("blaming %x for bad seed size in RS message", p.id[:])
181187
blamed = append(blamed, *p.id)
182188
continue
183189
}
@@ -187,7 +193,7 @@ KELoop:
187193
if mixing.InField(scratch.SetBytes(m)) {
188194
continue
189195
}
190-
c.logf("blaming %x for SR message outside field", p.id[:])
196+
sesRun.logf("blaming %x for SR message outside field", p.id[:])
191197
blamed = append(blamed, *p.id)
192198
continue KELoop
193199
}
@@ -199,7 +205,7 @@ KELoop:
199205
// Recover derived key exchange from PRNG.
200206
p.kx, err = mixing.NewKX(p.prng)
201207
if err != nil {
202-
c.logf("blaming %x for bad KX", p.id[:])
208+
sesRun.logf("blaming %x for bad KX", p.id[:])
203209
blamed = append(blamed, *p.id)
204210
continue
205211
}
@@ -210,14 +216,14 @@ KELoop:
210216
case !bytes.Equal(p.ke.ECDH[:], p.kx.ECDHPublicKey.SerializeCompressed()):
211217
fallthrough
212218
case !bytes.Equal(p.ke.PQPK[:], p.kx.PQPublicKey[:]):
213-
c.logf("blaming %x for KE public keys not derived from their PRNG",
219+
sesRun.logf("blaming %x for KE public keys not derived from their PRNG",
214220
p.id[:])
215221
blamed = append(blamed, *p.id)
216222
continue KELoop
217223
}
218224
publishedECDHPub, err := secp256k1.ParsePubKey(p.ke.ECDH[:])
219225
if err != nil {
220-
c.logf("blaming %x for unparsable pubkey")
226+
sesRun.logf("blaming %x for unparsable pubkey")
221227
blamed = append(blamed, *p.id)
222228
continue
223229
}
@@ -229,7 +235,7 @@ KELoop:
229235
start += mcount
230236

231237
if uint32(len(p.rs.SlotReserveMsgs)) != mcount || uint32(len(p.rs.DCNetMsgs)) != mcount {
232-
c.logf("blaming %x for bad message count", p.id[:])
238+
sesRun.logf("blaming %x for bad message count", p.id[:])
233239
blamed = append(blamed, *p.id)
234240
continue
235241
}
@@ -261,19 +267,19 @@ KELoop:
261267
// from their PRNG.
262268
for i, p := range sesRun.peers {
263269
if p.ct == nil {
264-
c.logf("blaming %x for missing messages", p.id[:])
270+
sesRun.logf("blaming %x for missing messages", p.id[:])
265271
blamed = append(blamed, *p.id)
266272
continue
267273
}
268274
if len(recoveredCTs[i]) != len(p.ct.Ciphertexts) {
269-
c.logf("blaming %x for different ciphertexts count %d != %d",
275+
sesRun.logf("blaming %x for different ciphertexts count %d != %d",
270276
p.id[:], len(recoveredCTs[i]), len(p.ct.Ciphertexts))
271277
blamed = append(blamed, *p.id)
272278
continue
273279
}
274280
for j := range p.ct.Ciphertexts {
275281
if !bytes.Equal(p.ct.Ciphertexts[j][:], recoveredCTs[i][j][:]) {
276-
c.logf("blaming %x for different ciphertexts", p.id[:])
282+
sesRun.logf("blaming %x for different ciphertexts", p.id[:])
277283
blamed = append(blamed, *p.id)
278284
break
279285
}
@@ -294,7 +300,7 @@ KELoop:
294300
for _, pids := range shared {
295301
if len(pids) > 1 {
296302
for i := range pids {
297-
c.logf("blaming %x for shared SR message", pids[i][:])
303+
sesRun.logf("blaming %x for shared SR message", pids[i][:])
298304
}
299305
blamed = append(blamed, pids...)
300306
}
@@ -306,7 +312,7 @@ KELoop:
306312
SRLoop:
307313
for i, p := range sesRun.peers {
308314
if p.sr == nil {
309-
c.logf("blaming %x for missing messages", p.id[:])
315+
sesRun.logf("blaming %x for missing messages", p.id[:])
310316
blamed = append(blamed, *p.id)
311317
continue
312318
}
@@ -325,7 +331,7 @@ SRLoop:
325331
var decapErr *mixing.DecapsulateError
326332
if errors.As(err, &decapErr) {
327333
submittingID := p.id
328-
c.logf("blaming %x for unrecoverable secrets", submittingID[:])
334+
sesRun.logf("blaming %x for unrecoverable secrets", submittingID[:])
329335
blamed = append(blamed, *submittingID)
330336
continue
331337
}
@@ -343,7 +349,7 @@ SRLoop:
343349
// Blame when committed mix does not match provided.
344350
for k := range srMix {
345351
if srMix[k].Cmp(scratch.SetBytes(p.sr.DCMix[j][k])) != 0 {
346-
c.logf("blaming %x for bad SR mix", p.id[:])
352+
sesRun.logf("blaming %x for bad SR mix", p.id[:])
347353
blamed = append(blamed, *p.id)
348354
continue SRLoop
349355
}
@@ -376,7 +382,7 @@ DCLoop:
376382
// deferred function) if no peers could be assigned blame is
377383
// not likely to be seen under this situation.
378384
if p.dc == nil {
379-
c.logf("blaming %x for missing messages", p.id[:])
385+
sesRun.logf("blaming %x for missing messages", p.id[:])
380386
blamed = append(blamed, *p.id)
381387
continue
382388
}
@@ -386,7 +392,7 @@ DCLoop:
386392
// message, and there must be mcount DC-net vectors.
387393
mcount := p.pr.MessageCount
388394
if uint32(len(p.dc.DCNet)) != mcount {
389-
c.logf("blaming %x for missing DC mix vectors", p.id[:])
395+
sesRun.logf("blaming %x for missing DC mix vectors", p.id[:])
390396
blamed = append(blamed, *p.id)
391397
continue
392398
}
@@ -406,7 +412,7 @@ DCLoop:
406412
// Blame when committed mix does not match provided.
407413
for k := 0; k < len(dcMix); k++ {
408414
if !dcMix.Equals(mixing.Vec(p.dc.DCNet[j])) {
409-
c.logf("blaming %x for bad DC mix", p.id[:])
415+
sesRun.logf("blaming %x for bad DC mix", p.id[:])
410416
blamed = append(blamed, *p.id)
411417
continue DCLoop
412418
}

0 commit comments

Comments
 (0)