Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 18 additions & 9 deletions mixing/mixclient/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,6 @@ const pairingVersion byte = 2
const (
timeoutDuration = 30 * time.Second
maxJitter = timeoutDuration / 10
msgJitter = 300 * time.Millisecond
peerJitter = maxJitter - msgJitter
)

// expiredPRErr indicates that a dicemix session failed to complete due to the
Expand Down Expand Up @@ -397,10 +395,12 @@ type Client struct {
testWaiting chan struct{}
testTickC chan time.Time
testHooks map[hook]hookFunc

msgJitter time.Duration
}

// NewClient creates a wallet's mixing client manager.
func NewClient(w Wallet) *Client {
func NewClient(w Wallet, msgJitter time.Duration) *Client {
var prFlags byte
err := solverrpc.StartSolver()
if err == nil {
Expand All @@ -421,6 +421,7 @@ func NewClient(w Wallet) *Client {
blake256Hasher: blake256.NewHasher256(),
epoch: w.Mixpool().Epoch(),
stopping: make(chan struct{}),
msgJitter: msgJitter,
}
}

Expand Down Expand Up @@ -567,7 +568,7 @@ func (c *Client) sendLocalPeerMsgs(ctx context.Context, deadline time.Time, s *s
continue
}
msg := delayedMsg{
sendTime: now.Add(p.msgJitter()),
sendTime: now.Add(p.msgJitter(c.msgJitter)),
deadline: deadline,
m: nil,
p: p,
Expand Down Expand Up @@ -694,7 +695,10 @@ func (c *Client) waitForEpoch(ctx context.Context) (time.Time, error) {
}
}

func (p *peer) msgJitter() time.Duration {
func (p *peer) msgJitter(msgJitter time.Duration) time.Duration {
if msgJitter == 0 {
return p.jitter
}
return p.jitter + rand.Duration(msgJitter)
}

Expand All @@ -717,7 +721,7 @@ func (c *Client) prDelay(ctx context.Context, p *peer) error {
wait = sendAfter.Sub(now)
sendBefore = sendBefore.Add(c.epoch)
}
wait += p.msgJitter() + rand.Duration(sendBefore.Sub(now))
wait += p.msgJitter(c.msgJitter) + rand.Duration(sendBefore.Sub(now))
timer := time.NewTimer(wait)
select {
case <-ctx.Done():
Expand Down Expand Up @@ -963,7 +967,7 @@ func (c *Client) epochTicker(ctx context.Context) error {
}

// Dicemix performs a new mixing session for a coinjoin mix transaction.
func (c *Client) Dicemix(ctx context.Context, cj *CoinJoin) error {
func (c *Client) Dicemix(ctx context.Context, cj *CoinJoin, peerJitter time.Duration) error {
select {
case <-c.warming:
case <-ctx.Done():
Expand All @@ -977,7 +981,7 @@ func (c *Client) Dicemix(ctx context.Context, cj *CoinJoin) error {

p := &peer{
client: c,
jitter: rand.Duration(peerJitter),
jitter: peerJitter,
res: make(chan error, 1),
pub: pub,
priv: priv,
Expand Down Expand Up @@ -2063,7 +2067,12 @@ DCs:
return sesRun, err
}

time.Sleep(lowestJitter + rand.Duration(msgJitter))
var msgJitter time.Duration
if c.msgJitter > 0 {
msgJitter = rand.Duration(c.msgJitter)
}
time.Sleep(lowestJitter + msgJitter)

err = c.wallet.PublishTransaction(context.Background(), cj.tx)
if err != nil {
return sesRun, err
Expand Down
12 changes: 8 additions & 4 deletions mixing/mixclient/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ func requireCsppsolver(t *testing.T) {
var (
testStartingHeight uint32 = 100
testStartingBlock = chainhash.Hash{100}

// Zero jitter so tests can run as fast as possible.
msgJitter = time.Duration(0)
peerJitter = time.Duration(0)
)

const (
Expand All @@ -44,7 +48,7 @@ const (
)

func newTestClient(w *testWallet, logger slog.Logger) *Client {
c := NewClient(w)
c := NewClient(w, msgJitter)
c.testWaiting = make(chan struct{})
c.testTickC = make(chan time.Time)
c.SetLogger(logger)
Expand Down Expand Up @@ -231,7 +235,7 @@ func TestHonest(t *testing.T) {
for i := range peers {
p := peers[i]
g.Go(func() error {
return c.Dicemix(ctx, p.cj)
return c.Dicemix(ctx, p.cj, peerJitter)
})
}

Expand Down Expand Up @@ -346,7 +350,7 @@ func testDisruption(t *testing.T, misbehavingID *identity, h hook, f hookFunc) {
for _, p := range peers[:len(peers)/2] {
p := p
g.Go(func() error {
err := c.Dicemix(ctx, p.cj)
err := c.Dicemix(ctx, p.cj, peerJitter)
var e *testPeerBlamedError
if errors.As(err, &e) {
blameErrC <- e
Expand All @@ -359,7 +363,7 @@ func testDisruption(t *testing.T, misbehavingID *identity, h hook, f hookFunc) {
for _, p := range peers[len(peers)/2:] {
p := p
g.Go(func() error {
err := c2.Dicemix(ctx, p.cj)
err := c2.Dicemix(ctx, p.cj, peerJitter)
var e *testPeerBlamedError
if errors.As(err, &e) {
blameErrC <- e
Expand Down