Skip to content

Commit 378816d

Browse files
authored
Merge pull request #3139 from algorand/rel/beta-3.1.3
go-algorand v3.1.3-beta
2 parents 53cf013 + 615fee2 commit 378816d

33 files changed

+1178
-440
lines changed

buildnumber.dat

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
2
1+
3

catchup/fetcher_test.go

+6
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323
"net/url"
2424
"strings"
2525
"testing"
26+
"time"
2627

2728
"github.com/gorilla/mux"
2829
"github.com/stretchr/testify/require"
@@ -291,6 +292,11 @@ func (p *testUnicastPeer) IsOutgoing() bool {
291292
return false
292293
}
293294

295+
// GetConnectionLatency returns the connection latency between the local node and this peer.
296+
func (p *testUnicastPeer) GetConnectionLatency() time.Duration {
297+
return time.Duration(0)
298+
}
299+
294300
func (p *testUnicastPeer) Unicast(ctx context.Context, msg []byte, tag protocol.Tag, callback network.UnicastWebsocketMessageStateCallback) error {
295301
ps := p.gn.(*httpTestPeerSource)
296302
var dispather network.MessageHandler

catchup/peerSelector_test.go

+5
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,11 @@ func (d *mockUnicastPeer) IsOutgoing() bool {
6666
return false
6767
}
6868

69+
// GetConnectionLatency returns the connection latency between the local node and this peer.
70+
func (d *mockUnicastPeer) GetConnectionLatency() time.Duration {
71+
return time.Duration(0)
72+
}
73+
6974
func TestPeerAddress(t *testing.T) {
7075
partitiontest.PartitionTest(t)
7176

catchup/service.go

+3
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,9 @@ func (s *Service) fetchAndWrite(r basics.Round, prevFetchCompleteChan chan bool,
324324

325325
if err != nil {
326326
switch err.(type) {
327+
case ledgercore.ErrNonSequentialBlockEval:
328+
s.log.Infof("fetchAndWrite(%d): no need to re-evaluate historical block", r)
329+
return true
327330
case ledgercore.BlockInLedgerError:
328331
s.log.Infof("fetchAndWrite(%d): block already in ledger", r)
329332
return true

config/config.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ type Local struct {
6363
// Version tracks the current version of the defaults so we can migrate old -> new
6464
// This is specifically important whenever we decide to change the default value
6565
// for an existing parameter. This field tag must be updated any time we add a new version.
66-
Version uint32 `version[0]:"0" version[1]:"1" version[2]:"2" version[3]:"3" version[4]:"4" version[5]:"5" version[6]:"6" version[7]:"7" version[8]:"8" version[9]:"9" version[10]:"10" version[11]:"11" version[12]:"12" version[13]:"13" version[14]:"14" version[15]:"15" version[16]:"16" version[17]:"17"`
66+
Version uint32 `version[0]:"0" version[1]:"1" version[2]:"2" version[3]:"3" version[4]:"4" version[5]:"5" version[6]:"6" version[7]:"7" version[8]:"8" version[9]:"9" version[10]:"10" version[11]:"11" version[12]:"12" version[13]:"13" version[14]:"14" version[15]:"15" version[16]:"16" version[17]:"17" version[18]:"18"`
6767

6868
// environmental (may be overridden)
6969
// When enabled, stores blocks indefinitally, otherwise, only the most recents blocks
@@ -84,7 +84,7 @@ type Local struct {
8484
MaxConnectionsPerIP int `version[3]:"30"`
8585

8686
// 0 == disable
87-
PeerPingPeriodSeconds int `version[0]:"0"`
87+
PeerPingPeriodSeconds int `version[0]:"0" version[18]:"10"`
8888

8989
// for https serving
9090
TLSCertFile string `version[0]:""`

config/local_defaults.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
package config
2121

2222
var defaultLocal = Local{
23-
Version: 17,
23+
Version: 18,
2424
AccountUpdatesStatsInterval: 5000000000,
2525
AccountsRebuildSynchronousMode: 1,
2626
AnnounceParticipationKey: true,
@@ -92,7 +92,7 @@ var defaultLocal = Local{
9292
OutgoingMessageFilterBucketSize: 128,
9393
ParticipationKeysRefreshInterval: 60000000000,
9494
PeerConnectionsUpdateInterval: 3600,
95-
PeerPingPeriodSeconds: 0,
95+
PeerPingPeriodSeconds: 10,
9696
PriorityPeers: map[string]bool{},
9797
PublicAddress: "",
9898
ReconnectTime: 60000000000,

data/txHandler.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -538,7 +538,7 @@ func (handler *solicitedAsyncTxHandler) loop(ctx context.Context) {
538538
// We reencode here instead of using rawmsg.Data to avoid broadcasting non-canonical encodings
539539
err := handler.txHandler.net.Relay(ctx, protocol.TxnTag, reencode(txnGroup.Transactions), false, groups.networkPeer)
540540
if err != nil {
541-
logging.Base().Infof("solicitedAsyncTxHandler was unable to relay transaction message : %v")
541+
logging.Base().Infof("solicitedAsyncTxHandler was unable to relay transaction message : %v", err)
542542
break
543543
}
544544
}

go.mod

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ require (
88
github.com/algorand/graphtrace v0.0.0-20201117160756-e524ed1a6f64
99
github.com/algorand/msgp v1.1.48
1010
github.com/algorand/oapi-codegen v1.3.5-algorand5
11-
github.com/algorand/websocket v1.4.2
11+
github.com/algorand/websocket v1.4.3
1212
github.com/algorand/xorfilter v0.2.0
1313
github.com/aws/aws-sdk-go v1.16.5
1414
github.com/chrismcguire/gobberish v0.0.0-20150821175641-1d8adb509a0e

go.sum

+2-2
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ github.com/algorand/msgp v1.1.48 h1:5P+gVmTnk0m37r+rA3ZsFZW219ZqmCLulW5f8Z+3nx8=
1010
github.com/algorand/msgp v1.1.48/go.mod h1:LtOntbYiCHj/Sl/Sqxtf8CZOrDt2a8Dv3tLaS6mcnUE=
1111
github.com/algorand/oapi-codegen v1.3.5-algorand5 h1:y576Ca2/guQddQrQA7dtL5KcOx5xQgPeIupiuFMGyCI=
1212
github.com/algorand/oapi-codegen v1.3.5-algorand5/go.mod h1:/k0Ywn0lnt92uBMyE+yiRf/Wo3/chxHHsAfenD09EbY=
13-
github.com/algorand/websocket v1.4.2 h1:zMB7ukz+c7tcef8rVqmKQTv6KQtxXtCFuiAqKaE7n9I=
14-
github.com/algorand/websocket v1.4.2/go.mod h1:0nFSn+xppw/GZS9hgWPS3b8/4FcA3Pj7XQxm+wqHGx8=
13+
github.com/algorand/websocket v1.4.3 h1:8YiA+ZtwqAyg0K30lQyl7gUdKUArYXvBtd/cTFwA4uQ=
14+
github.com/algorand/websocket v1.4.3/go.mod h1:0nFSn+xppw/GZS9hgWPS3b8/4FcA3Pj7XQxm+wqHGx8=
1515
github.com/algorand/xorfilter v0.2.0 h1:YC31ANxdZ2jmtbwqv1+USskVSqjkeiRZcQGc6//ro9Q=
1616
github.com/algorand/xorfilter v0.2.0/go.mod h1:f5cJsYrFbJhXkbjnV4odJB44np05/PvwvdBnABnQoUs=
1717
github.com/aws/aws-sdk-go v1.16.5 h1:NVxzZXIuwX828VcJrpNxxWjur1tlOBISdMdDdHIKHcc=

installer/config.json.example

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"Version": 17,
2+
"Version": 18,
33
"AccountUpdatesStatsInterval": 5000000000,
44
"AccountsRebuildSynchronousMode": 1,
55
"AnnounceParticipationKey": true,
@@ -71,7 +71,7 @@
7171
"OutgoingMessageFilterBucketSize": 128,
7272
"ParticipationKeysRefreshInterval": 60000000000,
7373
"PeerConnectionsUpdateInterval": 3600,
74-
"PeerPingPeriodSeconds": 0,
74+
"PeerPingPeriodSeconds": 10,
7575
"PriorityPeers": {},
7676
"PublicAddress": "",
7777
"ReconnectTime": 60000000000,

network/latencyTracker.go

+170
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
// Copyright (C) 2019-2021 Algorand, Inc.
2+
// This file is part of go-algorand
3+
//
4+
// go-algorand is free software: you can redistribute it and/or modify
5+
// it under the terms of the GNU Affero General Public License as
6+
// published by the Free Software Foundation, either version 3 of the
7+
// License, or (at your option) any later version.
8+
//
9+
// go-algorand is distributed in the hope that it will be useful,
10+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
// GNU Affero General Public License for more details.
13+
//
14+
// You should have received a copy of the GNU Affero General Public License
15+
// along with go-algorand. If not, see <https://www.gnu.org/licenses/>.
16+
17+
package network
18+
19+
import (
20+
"errors"
21+
"net"
22+
"strconv"
23+
"sync/atomic"
24+
"time"
25+
26+
"github.com/algorand/websocket"
27+
28+
"github.com/algorand/go-deadlock"
29+
30+
"github.com/algorand/go-algorand/config"
31+
)
32+
33+
const pongMessageWriteDuration = time.Second
34+
const pingMessageWriteDuration = time.Second
35+
36+
var errInvalidPongMessageContent = errors.New("invalid pong message content")
37+
var errInvalidPingMessageContent = errors.New("invalid ping message content")
38+
39+
// latencyTracker works in conjunction with the wspeer in measuring the
40+
// communication latency over the websocket connection.
41+
type latencyTracker struct {
42+
// receivedPacketCounter is a counter for all incoming messages
43+
// placed here to be aligned with 64bit address.
44+
receivedPacketCounter uint64
45+
46+
// latency is the effective latency of the connection.
47+
// placed here to be aligned with 64bit address.
48+
latency int64
49+
50+
// lastPingSentTime is the timestamp at which we last sent a message.
51+
// this variable is only touched by checkPingSending, and therefore doesn't
52+
// need to be syncronized. The "clone" of this variable lastPingSentTimeSynced,
53+
// is being used by both the checkPingSending as well as by the pongHandler
54+
// and therefore require synchronization.
55+
lastPingSentTime int64
56+
57+
// static variables
58+
// ( doesn't get changed after init, hence, no synchronization needed )
59+
60+
// conn is the underlying connection object.
61+
conn wsPeerWebsocketConn
62+
63+
// enabled indicates whether the pingpong is currently enabled or not.
64+
enabled bool
65+
66+
// pingInterval is the max interval at which the client would send ping messages.
67+
pingInterval time.Duration
68+
69+
// lastPingMu synchronize the protected variables that might be modified across
70+
// the checkPingSending and the pongHandler. All the variable below this point
71+
// need to be syncronized with the mutex.
72+
lastPingMu deadlock.Mutex
73+
74+
// lastPingID is the last ping ID, a monotonic growing number used to ensure
75+
// that the pong message we've receive corresponds to the latest ping message
76+
// that we've sent.
77+
lastPingID uint64
78+
79+
// lastPingReceivedCounter stores message counter at the time we sent the ping.
80+
// In order to ensure the timing accuracy, we want to have no other messages
81+
// being exchanged. This, of course, would only delay the ping-pong until a
82+
// better measurement could be taken.
83+
lastPingReceivedCounter uint64
84+
85+
// lastPingSentTimeSynced, as stated above, is the syncronized version of lastPingSentTime.
86+
// it is used only in the case where we end up sending the ping message.
87+
lastPingSentTimeSynced int64
88+
}
89+
90+
func (lt *latencyTracker) init(conn wsPeerWebsocketConn, cfg config.Local, initialConnectionLatency time.Duration) {
91+
lt.conn = conn
92+
lt.enabled = cfg.PeerPingPeriodSeconds > 0 && cfg.EnablePingHandler
93+
lt.latency = int64(initialConnectionLatency)
94+
lt.pingInterval = time.Duration(cfg.PeerPingPeriodSeconds) * time.Second
95+
conn.SetPingHandler(lt.pingHandler)
96+
conn.SetPongHandler(lt.pongHandler)
97+
}
98+
99+
func (lt *latencyTracker) pingHandler(message string) error {
100+
if _, err := strconv.Atoi(message); err != nil {
101+
return errInvalidPingMessageContent
102+
}
103+
err := lt.conn.WriteControl(websocket.PongMessage, []byte(message), time.Now().Add(pongMessageWriteDuration))
104+
if err == websocket.ErrCloseSent {
105+
return nil
106+
} else if e, ok := err.(net.Error); ok && e.Temporary() {
107+
return nil
108+
}
109+
return err
110+
}
111+
112+
func (lt *latencyTracker) pongHandler(message string) error {
113+
pongID, err := strconv.Atoi(message)
114+
if err != nil {
115+
return errInvalidPongMessageContent
116+
}
117+
118+
lt.lastPingMu.Lock()
119+
defer lt.lastPingMu.Unlock()
120+
121+
if uint64(pongID) != lt.lastPingID {
122+
// we've sent more than one ping since; ignore this message.
123+
return nil
124+
}
125+
if lt.receivedPacketCounter != lt.lastPingReceivedCounter {
126+
// we've received other messages since the one that we sent. The timing
127+
// here would not be accurate.
128+
return nil
129+
}
130+
lastPingSentTime := time.Unix(0, lt.lastPingSentTimeSynced)
131+
roundtripDuration := time.Since(lastPingSentTime)
132+
atomic.StoreInt64(&lt.latency, roundtripDuration.Nanoseconds())
133+
return nil
134+
}
135+
136+
func (lt *latencyTracker) getConnectionLatency() time.Duration {
137+
return time.Duration(atomic.LoadInt64(&lt.latency))
138+
}
139+
140+
func (lt *latencyTracker) checkPingSending(now *time.Time) error {
141+
if !lt.enabled {
142+
return nil
143+
}
144+
if now.Sub(time.Unix(0, lt.lastPingSentTime)) < lt.pingInterval {
145+
return nil
146+
}
147+
148+
// it looks like it's time to send a ping :
149+
lt.lastPingMu.Lock()
150+
defer lt.lastPingMu.Unlock()
151+
152+
lt.lastPingID++
153+
err := lt.conn.WriteControl(websocket.PingMessage, []byte(strconv.Itoa(int(lt.lastPingID))), now.Add(pingMessageWriteDuration))
154+
if err == websocket.ErrCloseSent {
155+
return nil
156+
} else if e, ok := err.(net.Error); ok && e.Temporary() {
157+
return nil
158+
}
159+
if err != nil {
160+
return err
161+
}
162+
lt.lastPingSentTimeSynced = now.UnixNano()
163+
lt.lastPingReceivedCounter = atomic.LoadUint64(&lt.receivedPacketCounter)
164+
lt.lastPingSentTime = lt.lastPingSentTimeSynced
165+
return nil
166+
}
167+
168+
func (lt *latencyTracker) increaseReceivedCounter() {
169+
atomic.AddUint64(&lt.receivedPacketCounter, 1)
170+
}

0 commit comments

Comments
 (0)