diff --git a/Makefile b/Makefile index bd6383ff69c75244eaf1b62ef3cc9c0fb91c5154..7cd635a516d953f796d6073610b0f4d6693e00db 100644 --- a/Makefile +++ b/Makefile @@ -20,12 +20,12 @@ build: go mod tidy update_release: - GOFLAGS="" go get -u gitlab.com/xx_network/primitives@release - GOFLAGS="" go get -u gitlab.com/elixxir/primitives@release - GOFLAGS="" go get -u gitlab.com/xx_network/crypto@release - GOFLAGS="" go get -u gitlab.com/elixxir/crypto@release - GOFLAGS="" go get -u gitlab.com/xx_network/comms@release - GOFLAGS="" go get -u gitlab.com/elixxir/comms@release + GOFLAGS="" go get gitlab.com/xx_network/primitives@release + GOFLAGS="" go get gitlab.com/elixxir/primitives@release + GOFLAGS="" go get gitlab.com/xx_network/crypto@release + GOFLAGS="" go get gitlab.com/elixxir/crypto@release + GOFLAGS="" go get gitlab.com/xx_network/comms@release + GOFLAGS="" go get gitlab.com/elixxir/comms@release update_master: GOFLAGS="" go get gitlab.com/xx_network/primitives@master @@ -35,6 +35,6 @@ update_master: GOFLAGS="" go get gitlab.com/xx_network/comms@master GOFLAGS="" go get gitlab.com/elixxir/comms@master -master: clean update_master build version +master: update_master clean build version -release: clean update_release build version +release: update_release clean build version diff --git a/api/client.go b/api/client.go index 9068708d01307030a811065b810588d8614b677c..57abc071a3ebc62da7c9c8d23c6be02f7a3aa340 100644 --- a/api/client.go +++ b/api/client.go @@ -435,15 +435,16 @@ func (c *Client) StopNetworkFollower(timeout time.Duration) error { return errors.WithMessage(err, "Failed to Stop the Network Follower") } err = c.runner.Close(timeout) - if err != nil { - return errors.WithMessage(err, "Failed to Stop the Network Follower") - } c.runner = stoppable.NewMulti("client") - err = c.status.toStopped() - if err != nil { - return errors.WithMessage(err, "Failed to Stop the Network Follower") + err2 := c.status.toStopped() + if err2 != nil { + if err == nil { + err = err2 + } else { + err = errors.WithMessage(err, err2.Error()) + } } - return nil + return err } // NetworkFollowerStatus Gets the state of the network follower. Returns: diff --git a/api/version_vars.go b/api/version_vars.go index fe6acf57e3e33481b9b788cdb7364301392d32e2..7ca866b7d96c690d27065573c80a38bd52916839 100644 --- a/api/version_vars.go +++ b/api/version_vars.go @@ -1,10 +1,10 @@ // Code generated by go generate; DO NOT EDIT. // This file was generated by robots at -// 2021-04-16 13:10:29.436463 -0500 CDT m=+0.022389085 +// 2021-05-14 10:40:35.967865 -0700 PDT m=+0.035901934 package api -const GITVERSION = `6f9309c8 go fmt` -const SEMVER = "2.4.0" +const GITVERSION = `7db53dd8 update go mod` +const SEMVER = "2.6.0" const DEPENDENCIES = `module gitlab.com/elixxir/client go 1.13 @@ -24,17 +24,18 @@ require ( github.com/spf13/jwalterweatherman v1.1.0 github.com/spf13/viper v1.7.1 gitlab.com/elixxir/bloomfilter v0.0.0-20200930191214-10e9ac31b228 - gitlab.com/elixxir/comms v0.0.4-0.20210413160356-853e51fc18e5 - gitlab.com/elixxir/crypto v0.0.7-0.20210412231025-6f75c577f803 + gitlab.com/elixxir/comms v0.0.4-0.20210506164842-7a132fdd895a + gitlab.com/elixxir/crypto v0.0.7-0.20210514172618-7745b6e1c865 gitlab.com/elixxir/ekv v0.1.5 - gitlab.com/elixxir/primitives v0.0.3-0.20210409190923-7bf3cd8d97e7 - gitlab.com/xx_network/comms v0.0.4-0.20210413212014-5e898f41f33a - gitlab.com/xx_network/crypto v0.0.5-0.20210405224157-2b1f387b42c1 - gitlab.com/xx_network/primitives v0.0.4-0.20210402222416-37c1c4d3fac4 + gitlab.com/elixxir/primitives v0.0.3-0.20210514171434-8ec71ecbb058 + gitlab.com/xx_network/comms v0.0.4-0.20210507215532-38ed97bd9365 + gitlab.com/xx_network/crypto v0.0.5-0.20210504210244-9ddabbad25fd + gitlab.com/xx_network/primitives v0.0.4-0.20210504205835-db68f11de78a golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2 - golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57 // indirect - google.golang.org/genproto v0.0.0-20210105202744-fe13368bc0e1 // indirect - google.golang.org/grpc v1.34.0 // indirect + golang.org/x/net v0.0.0-20210505214959-0714010a04ed + golang.org/x/sys v0.0.0-20210503173754-0981d6026fa6 // indirect + google.golang.org/genproto v0.0.0-20201030142918-24207fddd1c3 // indirect + google.golang.org/grpc v1.37.0 // indirect google.golang.org/protobuf v1.26.0-rc.1 gopkg.in/ini.v1 v1.62.0 // indirect ) diff --git a/auth/request.go b/auth/request.go index c43707904f835b19d1e64ba53cb4ec9fe550355f..a6b9ab7dcc765509017e4b0c5d8efe988e1d1c9b 100644 --- a/auth/request.go +++ b/auth/request.go @@ -55,17 +55,20 @@ func RequestAuth(partner, me contact.Contact, message string, rng io.Reader, //lookup if an ongoing request is occurring rqType, sr, _, err := storage.Auth().GetRequest(partner.ID) - if err != nil && !strings.Contains(err.Error(), auth.NoRequest){ + if err == nil { if rqType == auth.Receive { - return 0, errors.WithMessage(err, - "Cannot send a request after receiving a request") + return 0, errors.Errorf("Cannot send a request after " + + "receiving a request") } else if rqType == auth.Sent { resend = true - }else{ - return 0, errors.WithMessage(err, - "Cannot send a request after receiving unknown error " + - "on requesting contact status") + } else { + return 0, errors.Errorf("Cannot send a request after "+ + " a stored request with unknown rqType: %d", rqType) } + } else if !strings.Contains(err.Error(), auth.NoRequest) { + return 0, errors.WithMessage(err, + "Cannot send a request after receiving unknown error "+ + "on requesting contact status") } grp := storage.E2e().GetGroup() @@ -102,11 +105,11 @@ func RequestAuth(partner, me contact.Contact, message string, rng io.Reader, // in this case we have an ongoing request so we can resend the extant // request - if resend{ + if resend { newPrivKey = sr.GetMyPrivKey() newPubKey = sr.GetMyPubKey() - //in this case it is a new request and we must generate new keys - }else{ + //in this case it is a new request and we must generate new keys + } else { //generate new keypair newPrivKey = diffieHellman.GeneratePrivateKey(256, grp, rng) newPubKey = diffieHellman.GeneratePublicKey(newPrivKey, grp) @@ -140,7 +143,7 @@ func RequestAuth(partner, me contact.Contact, message string, rng io.Reader, /*store state*/ //fixme: channel is bricked if the first store succedes but the second fails //store the in progress auth - if !resend{ + if !resend { err = storage.Auth().AddSent(partner.ID, partner.DhPubKey, newPrivKey, newPrivKey, confirmFp) if err != nil { @@ -157,7 +160,7 @@ func RequestAuth(partner, me contact.Contact, message string, rng io.Reader, if err != nil { // if the send fails just set it to failed, it will // but automatically retried - return 0, errors.WithMessagef(err, "Auth Request with %s " + + return 0, errors.WithMessagef(err, "Auth Request with %s "+ "(msgDigest: %s) failed to transmit: %+v", partner.ID, cmixMsg.Digest(), err) } diff --git a/bindings/client.go b/bindings/client.go index 6eafdc35a03be94ad9cfa547f5a0054f60072230..33ef281983799bab25a50663a71b151749ba3535 100644 --- a/bindings/client.go +++ b/bindings/client.go @@ -18,6 +18,7 @@ import ( "gitlab.com/elixxir/crypto/contact" "gitlab.com/elixxir/primitives/states" "gitlab.com/xx_network/primitives/id" + "gitlab.com/xx_network/primitives/netTime" "sync" "time" ) @@ -25,6 +26,8 @@ import ( var extantClient bool var loginMux sync.Mutex +var clientSingleton *Client + // sets the log level func init() { jww.SetLogThreshold(jww.LevelInfo) @@ -96,7 +99,15 @@ func Login(storageDir string, password []byte, parameters string) (*Client, erro return nil, errors.New(fmt.Sprintf("Failed to login: %+v", err)) } extantClient = true - return &Client{api: *client}, nil + clientSingleton := &Client{api: *client} + return clientSingleton, nil +} + +// returns a previously created client. IF be used if the garbage collector +// removes the client instance on the app side. Is NOT thread safe relative to +// login, newClient, or newPrecannedClient +func GetClientSingleton() *Client { + return clientSingleton } // sets level of logging. All logs the set level and above will be displayed @@ -219,9 +230,9 @@ func (c *Client) StopNetworkFollower(timeoutMS int) error { // WaitForNewtwork will block until either the network is healthy or the // passed timeout. It will return true if the network is healthy func (c *Client) WaitForNetwork(timeoutMS int) bool { - start := time.Now() + start := netTime.Now() timeout := time.Duration(timeoutMS) * time.Millisecond - for time.Now().Sub(start) < timeout { + for netTime.Now().Sub(start) < timeout { if c.api.GetHealth().IsHealthy() { return true } diff --git a/bindings/timeNow.go b/bindings/timeNow.go index dbeda1696669f98b9a489990ced0f66f51c9757b..fc457b459ae43452a1920c26a8b9e24c53725d74 100644 --- a/bindings/timeNow.go +++ b/bindings/timeNow.go @@ -13,12 +13,12 @@ import ( ) type TimeSource interface { - NowMs() int + NowMs() int64 } // SetTimeSource sets the network time to a custom source. func SetTimeSource(timeNow TimeSource) { netTime.Now = func() time.Time { - return time.Unix(0, int64(timeNow.NowMs()*int(time.Millisecond))) + return time.Unix(0, timeNow.NowMs()*int64(time.Millisecond)) } } diff --git a/cmd/root.go b/cmd/root.go index ae852c8a1ec659c75497c712c95a99be3d05e096..7d017680700bfce74ed8c4f0613f3672e1ecf81d 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -62,7 +62,6 @@ var rootCmd = &cobra.Command{ recipientID, isPrecanPartner = parseRecipient( viper.GetString("destid")) } - fmt.Println(isPrecanPartner) // Set it to myself if recipientID == nil { diff --git a/cmd/version.go b/cmd/version.go index b781e502cb97afc8edd8c90300c8a9f1e5816969..68e3f78210a7de2e059d35d4a877204fc1c56f38 100644 --- a/cmd/version.go +++ b/cmd/version.go @@ -18,7 +18,7 @@ import ( ) // Change this value to set the version for this build -const currentVersion = "2.4.0" +const currentVersion = "2.6.0" func Version() string { out := fmt.Sprintf("Elixxir Client v%s -- %s\n\n", api.SEMVER, diff --git a/go.mod b/go.mod index 5adeb654fcc0b32b1f52f368b5e54a416aeb98af..0625e9acabb938a6c7c1fa10d8e08b646f64f249 100644 --- a/go.mod +++ b/go.mod @@ -17,14 +17,15 @@ require ( github.com/spf13/jwalterweatherman v1.1.0 github.com/spf13/viper v1.7.1 gitlab.com/elixxir/bloomfilter v0.0.0-20200930191214-10e9ac31b228 - gitlab.com/elixxir/comms v0.0.4-0.20210504172254-e591cfb12750 - gitlab.com/elixxir/crypto v0.0.7-0.20210413184512-e41c09223958 + gitlab.com/elixxir/comms v0.0.4-0.20210514193223-7efa4c966f23 + gitlab.com/elixxir/crypto v0.0.7-0.20210514185043-7398614e9e43 gitlab.com/elixxir/ekv v0.1.5 - gitlab.com/elixxir/primitives v0.0.3-0.20210427004615-c68ecf15fcf3 - gitlab.com/xx_network/comms v0.0.4-0.20210409202820-eb3dca6571d3 - gitlab.com/xx_network/crypto v0.0.5-0.20210405224157-2b1f387b42c1 - gitlab.com/xx_network/primitives v0.0.4-0.20210419175212-11b843dd4791 + gitlab.com/elixxir/primitives v0.0.3-0.20210514174939-fbba435364ed + gitlab.com/xx_network/comms v0.0.4-0.20210507215532-38ed97bd9365 + gitlab.com/xx_network/crypto v0.0.5-0.20210504210244-9ddabbad25fd + gitlab.com/xx_network/primitives v0.0.4-0.20210504205835-db68f11de78a golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2 + golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57 // indirect google.golang.org/genproto v0.0.0-20210105202744-fe13368bc0e1 // indirect google.golang.org/grpc v1.34.0 // indirect diff --git a/go.sum b/go.sum index 8dd7ece321e30d8dc552f474fe93c067a02de762..608786e20c6cce9b86db3173cd38459cdddb25a8 100644 --- a/go.sum +++ b/go.sum @@ -253,34 +253,14 @@ github.com/zeebo/pcg v1.0.0 h1:dt+dx+HvX8g7Un32rY9XWoYnd0NmKmrIzpHF7qiTDj0= github.com/zeebo/pcg v1.0.0/go.mod h1:09F0S9iiKrwn9rlI5yjLkmrug154/YRW6KnnXVDM/l4= gitlab.com/elixxir/bloomfilter v0.0.0-20200930191214-10e9ac31b228 h1:Gi6rj4mAlK0BJIk1HIzBVMjWNjIUfstrsXC2VqLYPcA= gitlab.com/elixxir/bloomfilter v0.0.0-20200930191214-10e9ac31b228/go.mod h1:H6jztdm0k+wEV2QGK/KYA+MY9nj9Zzatux/qIvDDv3k= -gitlab.com/elixxir/comms v0.0.4-0.20210409192302-249b5af3dbc8 h1:k9BLWNw7CHwH4H3gNWA0Q/BXNg7923AFflWJtYZr5z4= -gitlab.com/elixxir/comms v0.0.4-0.20210409192302-249b5af3dbc8/go.mod h1:/y5QIivolXMa6TO+ZqFWAV49wxlXXxUCqZH9Zi82kXU= -gitlab.com/elixxir/comms v0.0.4-0.20210413160356-853e51fc18e5 h1:Q/+lhZpIDQdIKy9aXNCLkCk8AavFE7HAuaila0sv5mw= -gitlab.com/elixxir/comms v0.0.4-0.20210413160356-853e51fc18e5/go.mod h1:0XsJ63n7knUeSX9BDKQG7xGtX6w0l5WsfplSsMbP9iM= -gitlab.com/elixxir/comms v0.0.4-0.20210418162540-e8b5e8c46988 h1:MjMxUPNrTaJcWblWEFtDory8zNnOt9ACqZSK3E2s7hU= -gitlab.com/elixxir/comms v0.0.4-0.20210418162540-e8b5e8c46988/go.mod h1:ld2cWRyYD9jxAFRR1FYAZce7FV25YMIjKUdCJF7Of44= -gitlab.com/elixxir/comms v0.0.4-0.20210423203408-dc8bf3dbd86b h1:iie2Lsj/kMBi7io426X5rHONUtJdOr5bqSeCFBN22qY= -gitlab.com/elixxir/comms v0.0.4-0.20210423203408-dc8bf3dbd86b/go.mod h1:ld2cWRyYD9jxAFRR1FYAZce7FV25YMIjKUdCJF7Of44= -gitlab.com/elixxir/comms v0.0.4-0.20210429222550-0cbb396aaacd h1:goYpN2Zg0x/QxZt0OiyvZsgRlJyP/m9NH+vY8lLm65Y= -gitlab.com/elixxir/comms v0.0.4-0.20210429222550-0cbb396aaacd/go.mod h1:ld2cWRyYD9jxAFRR1FYAZce7FV25YMIjKUdCJF7Of44= -gitlab.com/elixxir/comms v0.0.4-0.20210504172254-e591cfb12750 h1:8r8XAvI7HXzhTk+wr0FGU6oFJLWZT0O1/4mheXMGx30= -gitlab.com/elixxir/comms v0.0.4-0.20210504172254-e591cfb12750/go.mod h1:ld2cWRyYD9jxAFRR1FYAZce7FV25YMIjKUdCJF7Of44= +gitlab.com/elixxir/comms v0.0.4-0.20210514193223-7efa4c966f23 h1:rXx1Pc6H72jZh94AH4CwFifZ5eCOZ/SfNIk7yP0vNZA= +gitlab.com/elixxir/comms v0.0.4-0.20210514193223-7efa4c966f23/go.mod h1:pwfLDUtrurM8mDcU11QHtBgxhL6cb5Vf/R47zJ7enuQ= gitlab.com/elixxir/crypto v0.0.0-20200804182833-984246dea2c4 h1:28ftZDeYEko7xptCZzeFWS1Iam95dj46TWFVVlKmw6A= gitlab.com/elixxir/crypto v0.0.0-20200804182833-984246dea2c4/go.mod h1:ucm9SFKJo+K0N2GwRRpaNr+tKXMIOVWzmyUD0SbOu2c= gitlab.com/elixxir/crypto v0.0.3 h1:znCt/x2bL4y8czTPaaFkwzdgSgW3BJc/1+dxyf1jqVw= gitlab.com/elixxir/crypto v0.0.3/go.mod h1:ZNgBOblhYToR4m8tj4cMvJ9UsJAUKq+p0gCp07WQmhA= -gitlab.com/elixxir/crypto v0.0.7-0.20210409192145-eab67f2f8931 h1:kY/qBfjrZTFHJnvM1IcxB03+ZQL4+ESUjV4I4kCxoE8= -gitlab.com/elixxir/crypto v0.0.7-0.20210409192145-eab67f2f8931/go.mod h1:ZktO3MT3oNo+g2Nq0GuC3ebJWJphh7t5KwwDDGBegnY= -gitlab.com/elixxir/crypto v0.0.7-0.20210412193049-f3718fa4facb h1:9CT5f+nV4sisutLx8Z3BAEiqjktcCL2ZpEqcpmgzyqA= -gitlab.com/elixxir/crypto v0.0.7-0.20210412193049-f3718fa4facb/go.mod h1:ZktO3MT3oNo+g2Nq0GuC3ebJWJphh7t5KwwDDGBegnY= -gitlab.com/elixxir/crypto v0.0.7-0.20210412195114-be927031747a h1:DSYIXSCWrwkyHUs2fJMliI4+Bd9h+WA5PXI78uvhCj4= -gitlab.com/elixxir/crypto v0.0.7-0.20210412195114-be927031747a/go.mod h1:HMMRBuv/yMqB5c31G9OPlOAifOOqGypCyD5v6py+4vo= -gitlab.com/elixxir/crypto v0.0.7-0.20210412231025-6f75c577f803 h1:8sLODlAYRT0Y9NA+uoMoF1qBrBRrW5TikyKAOvyCd+E= -gitlab.com/elixxir/crypto v0.0.7-0.20210412231025-6f75c577f803/go.mod h1:HMMRBuv/yMqB5c31G9OPlOAifOOqGypCyD5v6py+4vo= -gitlab.com/elixxir/crypto v0.0.7-0.20210413182603-9525e6071fa7 h1:V004OOQrZ6F0iH4BwjObFWbWWqzvKbXRd3Dv2UEz6AI= -gitlab.com/elixxir/crypto v0.0.7-0.20210413182603-9525e6071fa7/go.mod h1:HMMRBuv/yMqB5c31G9OPlOAifOOqGypCyD5v6py+4vo= -gitlab.com/elixxir/crypto v0.0.7-0.20210413184512-e41c09223958 h1:tjEWlRieizWKnHFV1Q0nNegHT5QJJf9hECiM7nJSbik= -gitlab.com/elixxir/crypto v0.0.7-0.20210413184512-e41c09223958/go.mod h1:HMMRBuv/yMqB5c31G9OPlOAifOOqGypCyD5v6py+4vo= +gitlab.com/elixxir/crypto v0.0.7-0.20210514185043-7398614e9e43 h1:YrHC861+C0DZPXXEV567TUUleFt35EMe55pvPztjnV8= +gitlab.com/elixxir/crypto v0.0.7-0.20210514185043-7398614e9e43/go.mod h1:iL2uGUFjLT3Z97IjsCSSqmfRlSJ6Y/uIWEPZLEOKyys= gitlab.com/elixxir/ekv v0.1.5 h1:R8M1PA5zRU1HVnTyrtwybdABh7gUJSCvt1JZwUSeTzk= gitlab.com/elixxir/ekv v0.1.5/go.mod h1:e6WPUt97taFZe5PFLPb1Dupk7tqmDCTQu1kkstqJvw4= gitlab.com/elixxir/primitives v0.0.0-20200731184040-494269b53b4d/go.mod h1:OQgUZq7SjnE0b+8+iIAT2eqQF+2IFHn73tOo+aV11mg= @@ -288,29 +268,23 @@ gitlab.com/elixxir/primitives v0.0.0-20200804170709-a1896d262cd9/go.mod h1:p0Vel gitlab.com/elixxir/primitives v0.0.0-20200804182913-788f47bded40/go.mod h1:tzdFFvb1ESmuTCOl1z6+yf6oAICDxH2NPUemVgoNLxc= gitlab.com/elixxir/primitives v0.0.1 h1:q61anawANlNAExfkeQEE1NCsNih6vNV1FFLoUQX6txQ= gitlab.com/elixxir/primitives v0.0.1/go.mod h1:kNp47yPqja2lHSiS4DddTvFpB/4D9dB2YKnw5c+LJCE= -gitlab.com/elixxir/primitives v0.0.3-0.20210409190923-7bf3cd8d97e7 h1:q3cw7WVtD6hDqTi8ydky+yiqJ4RkWp/hkTSNirr9Z6Y= -gitlab.com/elixxir/primitives v0.0.3-0.20210409190923-7bf3cd8d97e7/go.mod h1:h0QHrjrixLNaP24ZXAgDOZXP4eegrQ24BCZPGitg8Jg= -gitlab.com/elixxir/primitives v0.0.3-0.20210427004615-c68ecf15fcf3 h1:fQZzwSDzFymbXlTPVCDTrnBkOhFAx4fACwZQHpmTVOY= -gitlab.com/elixxir/primitives v0.0.3-0.20210427004615-c68ecf15fcf3/go.mod h1:h0QHrjrixLNaP24ZXAgDOZXP4eegrQ24BCZPGitg8Jg= +gitlab.com/elixxir/primitives v0.0.3-0.20210514174939-fbba435364ed h1:iRNiL2PkHDgcPQt5qUlOtod0n0sSyaSNXN+AkmZ5ViA= +gitlab.com/elixxir/primitives v0.0.3-0.20210514174939-fbba435364ed/go.mod h1:4pNgiFEQQ11hHCXBRQJN1w9AIuKa1HTlPTxs9UYOXFA= gitlab.com/xx_network/comms v0.0.0-20200805174823-841427dd5023/go.mod h1:owEcxTRl7gsoM8c3RQ5KAm5GstxrJp5tn+6JfQ4z5Hw= -gitlab.com/xx_network/comms v0.0.4-0.20210406210737-45d1e87d294a h1:r0mvBjHPBCYEVmhEe6JhLQDc0+dCORf1ejtuZ8IbyKY= -gitlab.com/xx_network/comms v0.0.4-0.20210406210737-45d1e87d294a/go.mod h1:7ciuA+LTE0GC7upviGbyyb2hrpJG9Pnq2cc5oz2N5Ss= -gitlab.com/xx_network/comms v0.0.4-0.20210409202820-eb3dca6571d3 h1:0o9kveRSEQ9ykRh/hd+z9Iq53YNvFArW1RQ6ICdAG5g= -gitlab.com/xx_network/comms v0.0.4-0.20210409202820-eb3dca6571d3/go.mod h1:7ciuA+LTE0GC7upviGbyyb2hrpJG9Pnq2cc5oz2N5Ss= +gitlab.com/xx_network/comms v0.0.4-0.20210507215532-38ed97bd9365 h1:VjeUUy4hcc2uTOO5qZ0roJlGHySWJxN/G7bf1VnLfFM= +gitlab.com/xx_network/comms v0.0.4-0.20210507215532-38ed97bd9365/go.mod h1:RkNZ0CjeXKRhEFdUeAdCAF6QuK8sO1j2bUg9oqK0OEA= gitlab.com/xx_network/crypto v0.0.3/go.mod h1:DF2HYvvCw9wkBybXcXAgQMzX+MiGbFPjwt3t17VRqRE= gitlab.com/xx_network/crypto v0.0.4 h1:lpKOL5mTJ2awWMfgBy30oD/UvJVrWZzUimSHlOdZZxo= gitlab.com/xx_network/crypto v0.0.4/go.mod h1:+lcQEy+Th4eswFgQDwT0EXKp4AXrlubxalwQFH5O0Mk= -gitlab.com/xx_network/crypto v0.0.5-0.20210405224157-2b1f387b42c1 h1:4Hrphjtqn3vO8LI872YwVKy5dCFJdD5u0dE4O2QCZqU= -gitlab.com/xx_network/crypto v0.0.5-0.20210405224157-2b1f387b42c1/go.mod h1:CUhRpioyLaKIylg+LIyZX1rhOmFaEXQQ6esNycx9dcA= +gitlab.com/xx_network/crypto v0.0.5-0.20210504210244-9ddabbad25fd h1:jSY1ogxa2/MXthD8jadGr7IYBL4vXQID3VZp1g0GWec= +gitlab.com/xx_network/crypto v0.0.5-0.20210504210244-9ddabbad25fd/go.mod h1:bAqc5+q2K9OXWceHkZX+VnneSKlsSeg+G98O5S4Y2cA= gitlab.com/xx_network/primitives v0.0.0-20200803231956-9b192c57ea7c/go.mod h1:wtdCMr7DPePz9qwctNoAUzZtbOSHSedcK++3Df3psjA= gitlab.com/xx_network/primitives v0.0.0-20200804183002-f99f7a7284da h1:CCVslUwNC7Ul7NG5nu3ThGTSVUt1TxNRX+47f5TUwnk= gitlab.com/xx_network/primitives v0.0.0-20200804183002-f99f7a7284da/go.mod h1:OK9xevzWCaPO7b1wiluVJGk7R5ZsuC7pHY5hteZFQug= gitlab.com/xx_network/primitives v0.0.2 h1:r45yKenJ9e7PylI1ZXJ1Es09oYNaYXjxVy9+uYlwo7Y= gitlab.com/xx_network/primitives v0.0.2/go.mod h1:cs0QlFpdMDI6lAo61lDRH2JZz+3aVkHy+QogOB6F/qc= -gitlab.com/xx_network/primitives v0.0.4-0.20210402222416-37c1c4d3fac4 h1:YPYTKF0zQf08y0eQrjQP01C/EWQTypdqawjZPr5c6rc= -gitlab.com/xx_network/primitives v0.0.4-0.20210402222416-37c1c4d3fac4/go.mod h1:9imZHvYwNFobxueSvVtHneZLk9wTK7HQTzxPm+zhFhE= -gitlab.com/xx_network/primitives v0.0.4-0.20210419175212-11b843dd4791 h1:RSeT0tJiwRr1BuKsTCaulr+eJAxQHDl/r9ZMo4lN9mg= -gitlab.com/xx_network/primitives v0.0.4-0.20210419175212-11b843dd4791/go.mod h1:9imZHvYwNFobxueSvVtHneZLk9wTK7HQTzxPm+zhFhE= +gitlab.com/xx_network/primitives v0.0.4-0.20210504205835-db68f11de78a h1:Op+Dfm/Swtrs6Lgo/ro28SrCrftrfQtK9a3/EOoXYAo= +gitlab.com/xx_network/primitives v0.0.4-0.20210504205835-db68f11de78a/go.mod h1:9imZHvYwNFobxueSvVtHneZLk9wTK7HQTzxPm+zhFhE= gitlab.com/xx_network/ring v0.0.2 h1:TlPjlbFdhtJrwvRgIg4ScdngMTaynx/ByHBRZiXCoL0= gitlab.com/xx_network/ring v0.0.2/go.mod h1:aLzpP2TiZTQut/PVHR40EJAomzugDdHXetbieRClXIM= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= diff --git a/interfaces/IsRunning.go b/interfaces/IsRunning.go new file mode 100644 index 0000000000000000000000000000000000000000..5198434a8391a1de5c704f392f641fbaea50ae93 --- /dev/null +++ b/interfaces/IsRunning.go @@ -0,0 +1,8 @@ +package interfaces + +// this interface is used to allow the follower to to be stopped later if it +// fails + +type Running interface { + IsRunning() bool +} diff --git a/interfaces/params/message.go b/interfaces/params/message.go index fbf9779829b939145cf7bc1277fa79b5617b826a..acecde4ef9861ab722ff05c7e645272f20d21694 100644 --- a/interfaces/params/message.go +++ b/interfaces/params/message.go @@ -16,6 +16,8 @@ type Messages struct { MessageReceptionWorkerPoolSize uint MaxChecksGarbledMessage uint GarbledMessageWait time.Duration + // Use proxied (rather than direct) message sending + ProxySending bool } func GetDefaultMessage() Messages { @@ -24,5 +26,6 @@ func GetDefaultMessage() Messages { MessageReceptionWorkerPoolSize: 4, MaxChecksGarbledMessage: 10, GarbledMessageWait: 15 * time.Minute, + ProxySending: false, } } diff --git a/network/ephemeral/tracker.go b/network/ephemeral/tracker.go index 2f19604c49faea57cb58b5cf7caf3476af4d9eab..9a1ca5e59682e4d2907bb7ac0ff46f5daca0b204 100644 --- a/network/ephemeral/tracker.go +++ b/network/ephemeral/tracker.go @@ -61,6 +61,12 @@ func track(session *storage.Session, ourId *id.ID, stop *stoppable.Single) { for true { now := netTime.Now() + + //hack for inconsistent time on android + if now.Sub(lastCheck) <= 0 { + now = lastCheck.Add(time.Nanosecond) + } + // Generates the IDs since the last track protoIds, err := ephemeral.GetIdsByRange(ourId, receptionStore.GetIDSize(), now, now.Sub(lastCheck)) diff --git a/network/follow.go b/network/follow.go index 259e9b2a0390f9f78fee741c1ba32f75e23dd660..d479547ea1b360f83e06973ae4c49fa15b9008f2 100644 --- a/network/follow.go +++ b/network/follow.go @@ -23,12 +23,14 @@ package network // instance import ( + "bytes" "fmt" jww "github.com/spf13/jwalterweatherman" "gitlab.com/elixxir/client/interfaces" "gitlab.com/elixxir/client/network/rounds" pb "gitlab.com/elixxir/comms/mixmessages" "gitlab.com/elixxir/primitives/knownRounds" + "gitlab.com/elixxir/primitives/states" "gitlab.com/xx_network/comms/connect" "gitlab.com/xx_network/crypto/csprng" "gitlab.com/xx_network/primitives/id" @@ -46,7 +48,7 @@ type followNetworkComms interface { // followNetwork polls the network to get updated on the state of nodes, the // round status, and informs the client when messages can be retrieved. -func (m *manager) followNetwork(report interfaces.ClientErrorReport, quitCh <-chan struct{}) { +func (m *manager) followNetwork(report interfaces.ClientErrorReport, quitCh <-chan struct{}, isRunning interfaces.Running) { ticker := time.NewTicker(m.param.TrackNetworkPeriod) TrackTicker := time.NewTicker(debugTrackPeriod) rng := m.Rng.GetStream() @@ -58,17 +60,23 @@ func (m *manager) followNetwork(report interfaces.ClientErrorReport, quitCh <-ch rng.Close() done = true case <-ticker.C: - m.follow(report, rng, m.Comms) + m.follow(report, rng, m.Comms, isRunning) case <-TrackTicker.C: numPolls := atomic.SwapUint64(m.tracker, 0) jww.INFO.Printf("Polled the network %d times in the "+ "last %s", numPolls, debugTrackPeriod) } + if !isRunning.IsRunning() { + jww.ERROR.Printf("Killing network follower " + + "due to failed exit") + return + } } } // executes each iteration of the follower -func (m *manager) follow(report interfaces.ClientErrorReport, rng csprng.Source, comms followNetworkComms) { +func (m *manager) follow(report interfaces.ClientErrorReport, rng csprng.Source, + comms followNetworkComms, isRunning interfaces.Running) { //get the identity we will poll for identity, err := m.Session.Reception().GetIdentity(rng) @@ -98,20 +106,22 @@ func (m *manager) follow(report interfaces.ClientErrorReport, rng csprng.Source, jww.DEBUG.Printf("Executing poll for %v(%s) range: %s-%s(%s) from %s", identity.EphId.Int64(), identity.Source, identity.StartRequest, identity.EndRequest, identity.EndRequest.Sub(identity.StartRequest), host.GetId()) - result, err := comms.SendPoll(host, &pollReq) - if err != nil { - if report != nil { - report( - "NetworkFollower", - fmt.Sprintf("Failed to poll network, \"%s\", Gateway: %s", err.Error(), host.String()), - fmt.Sprintf("%+v", err), - ) - } - jww.ERROR.Printf("Unable to poll %s for NDF: %+v", host, err) - } - return result, err + return comms.SendPoll(host, &pollReq) }) + if !isRunning.IsRunning() { + jww.ERROR.Printf("Killing network follower " + + "due to failed exit") + return + } if err != nil { + if report != nil { + report( + "NetworkFollower", + fmt.Sprintf("Failed to poll network, \"%s\":", err.Error()), + fmt.Sprintf("%+v", err), + ) + } + jww.ERROR.Printf("Unable to poll gateways: %+v", err) return } @@ -154,50 +164,49 @@ func (m *manager) follow(report interfaces.ClientErrorReport, rng csprng.Source, // TODO: ClientErr needs to know the source of the error and it doesn't yet // Iterate over ClientErrors for each RoundUpdate - //for _, update := range pollResp.Updates { - // - // // Ignore irrelevant updates - // if update.State != uint32(states.COMPLETED) && update.State != uint32(states.FAILED) { - // continue - // } - // - // for _, clientErr := range update.ClientErrors { - // // If this Client appears in the ClientError - // if bytes.Equal(clientErr.ClientId, m.Session.GetUser().TransmissionID.Marshal()) { - // - // // Obtain relevant NodeGateway information - // // TODO ??? - // nGw, err := m.Instance.GetNodeAndGateway(gwHost.GetId()) - // if err != nil { - // jww.ERROR.Printf("Unable to get NodeGateway: %+v", err) - // return - // } - // nid, err := nGw.Node.GetNodeId() - // if err != nil { - // jww.ERROR.Printf("Unable to get NodeID: %+v", err) - // return - // } - // - // // FIXME: Should be able to trigger proper type of round event - // // FIXME: without mutating the RoundInfo. Signature also needs verified - // // FIXME: before keys are deleted - // update.State = uint32(states.FAILED) - // rnd, err := m.Instance.GetWrappedRound(id.Round(update.ID)) - // if err != nil { - // jww.ERROR.Printf("Failed to report client error: "+ - // "Could not get round for event triggering: "+ - // "Unable to get round %d from instance: %+v", - // id.Round(update.ID), err) - // break - // } - // m.Instance.GetRoundEvents().TriggerRoundEvent(rnd) - // - // // delete all existing keys and trigger a re-registration with the relevant Node - // m.Session.Cmix().Remove(nid) - // m.Instance.GetAddGatewayChan() <- nGw - // } - // } - //} + for _, update := range pollResp.Updates { + + // Ignore irrelevant updates + if update.State != uint32(states.COMPLETED) && update.State != uint32(states.FAILED) { + continue + } + + for _, clientErr := range update.ClientErrors { + // If this Client appears in the ClientError + if bytes.Equal(clientErr.ClientId, m.Session.GetUser().TransmissionID.Marshal()) { + + // Obtain relevant NodeGateway information + nid, err := id.Unmarshal(clientErr.Source) + if err != nil { + jww.ERROR.Printf("Unable to get NodeID: %+v", err) + return + } + nGw, err := m.Instance.GetNodeAndGateway(nid) + if err != nil { + jww.ERROR.Printf("Unable to get gateway: %+v", err) + return + } + + // FIXME: Should be able to trigger proper type of round event + // FIXME: without mutating the RoundInfo. Signature also needs verified + // FIXME: before keys are deleted + update.State = uint32(states.FAILED) + rnd, err := m.Instance.GetWrappedRound(id.Round(update.ID)) + if err != nil { + jww.ERROR.Printf("Failed to report client error: "+ + "Could not get round for event triggering: "+ + "Unable to get round %d from instance: %+v", + id.Round(update.ID), err) + break + } + m.Instance.GetRoundEvents().TriggerRoundEvent(rnd) + + // delete all existing keys and trigger a re-registration with the relevant Node + m.Session.Cmix().Remove(nid) + m.Instance.GetAddGatewayChan() <- nGw + } + } + } } // ---- Identity Specific Round Processing ----- diff --git a/network/gateway/hostPool.go b/network/gateway/hostPool.go index 173ca2e2a691f94c0b78d4065e9d3bd9ece7ddda..ba8198da839c4e9d2693d866be165f6afaf08d47 100644 --- a/network/gateway/hostPool.go +++ b/network/gateway/hostPool.go @@ -5,8 +5,9 @@ // LICENSE file // /////////////////////////////////////////////////////////////////////////////// -// Handles functionality related to providing Gateway connect.Host objects +// Package gateway Handles functionality related to providing Gateway connect.Host objects // for message sending to the rest of the client repo +// Used to minimize # of open connections on mobile clients package gateway @@ -21,6 +22,7 @@ import ( "gitlab.com/xx_network/comms/connect" "gitlab.com/xx_network/primitives/id" "gitlab.com/xx_network/primitives/ndf" + "golang.org/x/net/context" "io" "math" "strings" @@ -29,8 +31,9 @@ import ( ) // List of errors that initiate a Host replacement -var errorsList = []string{"context deadline exceeded", "connection refused", "host disconnected", - "transport is closing", "all SubConns are in TransientFailure", ndf.NO_NDF} +var errorsList = []string{context.DeadlineExceeded.Error(), "connection refused", "host disconnected", + "transport is closing", "all SubConns are in TransientFailure", "Last try to connect", + ndf.NO_NDF, "Host is in cool down"} // HostManager Interface allowing storage and retrieval of Host objects type HostManager interface { @@ -78,6 +81,7 @@ func DefaultPoolParams() PoolParams { p.HostParams.EnableCoolOff = true p.HostParams.NumSendsBeforeCoolOff = 1 p.HostParams.CoolOffTimeout = 5 * time.Minute + p.HostParams.SendTimeout = 3500 * time.Millisecond return p } @@ -125,6 +129,11 @@ func newHostPool(poolParams PoolParams, rng *fastRNG.StreamGenerator, ndf *ndf.N // UpdateNdf Mutates internal ndf to the given ndf func (h *HostPool) UpdateNdf(ndf *ndf.NetworkDefinition) { + if len(ndf.Gateways) == 0 { + jww.WARN.Printf("Unable to UpdateNdf: no gateways available") + return + } + h.ndfMux.Lock() h.ndf = ndf @@ -216,7 +225,9 @@ func (h *HostPool) getPreferred(targets []*id.ID) []*connect.Host { } // Replaces the given hostId in the HostPool if the given hostErr is in errorList -func (h *HostPool) checkReplace(hostId *id.ID, hostErr error) error { +// Returns whether the host was replaced +func (h *HostPool) checkReplace(hostId *id.ID, hostErr error) (bool, error) { + var err error // Check if Host should be replaced doReplace := false if hostErr != nil { @@ -230,19 +241,17 @@ func (h *HostPool) checkReplace(hostId *id.ID, hostErr error) error { } if doReplace { - h.hostMux.Lock() - defer h.hostMux.Unlock() - // If the Host is still in the pool + h.hostMux.Lock() if oldPoolIndex, ok := h.hostMap[*hostId]; ok { // Replace it h.ndfMux.RLock() - err := h.forceReplace(oldPoolIndex) + err = h.forceReplace(oldPoolIndex) h.ndfMux.RUnlock() - return err } + h.hostMux.Unlock() } - return nil + return doReplace, err } // Replace given Host index with a new, randomly-selected Host from the NDF diff --git a/network/gateway/hostpool_test.go b/network/gateway/hostpool_test.go index 8181e6d49f0ea5522e8ae33eb6ac143516c45a26..49dcacf6b8231647b8c0cbc0ab6e6f84b0c7d126 100644 --- a/network/gateway/hostpool_test.go +++ b/network/gateway/hostpool_test.go @@ -359,10 +359,13 @@ func TestHostPool_CheckReplace(t *testing.T) { oldGatewayIndex := 0 oldHost := testPool.hostList[oldGatewayIndex] expectedError := fmt.Errorf(errorsList[0]) - err = testPool.checkReplace(oldHost.GetId(), expectedError) + wasReplaced, err := testPool.checkReplace(oldHost.GetId(), expectedError) if err != nil { t.Errorf("Failed to check replace: %v", err) } + if !wasReplaced { + t.Errorf("Expected to replace") + } // Ensure that old gateway has been removed from the map if _, ok := testPool.hostMap[*oldHost.GetId()]; ok { @@ -378,10 +381,13 @@ func TestHostPool_CheckReplace(t *testing.T) { goodGatewayIndex := 0 goodGateway := testPool.hostList[goodGatewayIndex] unexpectedErr := fmt.Errorf("not in global error list") - err = testPool.checkReplace(oldHost.GetId(), unexpectedErr) + wasReplaced, err = testPool.checkReplace(oldHost.GetId(), unexpectedErr) if err != nil { t.Errorf("Failed to check replace: %v", err) } + if wasReplaced { + t.Errorf("Expected not to replace") + } // Ensure that gateway with an unexpected error was not modified if _, ok := testPool.hostMap[*goodGateway.GetId()]; !ok { diff --git a/network/gateway/sender.go b/network/gateway/sender.go index dcfcdbb5b88a0be02b67f4f61dfcaa01c1169489..619581cd7c9d4289ef3a88faeff48eff2a67bb6d 100644 --- a/network/gateway/sender.go +++ b/network/gateway/sender.go @@ -14,6 +14,7 @@ import ( "gitlab.com/elixxir/client/storage" "gitlab.com/elixxir/comms/network" "gitlab.com/elixxir/crypto/fastRNG" + "gitlab.com/elixxir/crypto/shuffle" "gitlab.com/xx_network/comms/connect" "gitlab.com/xx_network/primitives/id" "gitlab.com/xx_network/primitives/ndf" @@ -63,7 +64,7 @@ func (s *Sender) SendToSpecific(target *id.ID, host.GetId().String()) } jww.WARN.Printf("Unable to SendToSpecific proxy %s: %s", proxies[i].GetId().String(), err) - err = s.checkReplace(proxies[i].GetId(), err) + _, err = s.checkReplace(proxies[i].GetId(), err) if err != nil { jww.ERROR.Printf("Unable to checkReplace: %+v", err) } @@ -83,7 +84,7 @@ func (s *Sender) SendToAny(sendFunc func(host *connect.Host) (interface{}, error return result, nil } else { jww.WARN.Printf("Unable to SendToAny %s: %s", proxies[i].GetId().String(), err) - err = s.checkReplace(proxies[i].GetId(), err) + _, err = s.checkReplace(proxies[i].GetId(), err) if err != nil { jww.ERROR.Printf("Unable to checkReplace: %+v", err) } @@ -97,7 +98,20 @@ func (s *Sender) SendToAny(sendFunc func(host *connect.Host) (interface{}, error func (s *Sender) SendToPreferred(targets []*id.ID, sendFunc func(host *connect.Host, target *id.ID) (interface{}, error)) (interface{}, error) { + // Get the hosts and shuffle randomly targetHosts := s.getPreferred(targets) + var rndBytes [32]byte + stream := s.rng.GetStream() + _, err := stream.Read(rndBytes[:]) + stream.Close() + if err != nil { + return nil, err + } + shuffle.ShuffleSwap(rndBytes[:], len(targetHosts), func(i, j int) { + targetHosts[i], targetHosts[j] = targetHosts[j], targetHosts[i] + }) + + // Attempt to send directly to targets if they are in the HostPool for i := range targetHosts { result, err := sendFunc(targetHosts[i], targets[i]) if err == nil { @@ -105,25 +119,48 @@ func (s *Sender) SendToPreferred(targets []*id.ID, } else { jww.WARN.Printf("Unable to SendToPreferred %s via %s: %s", targets[i], targetHosts[i].GetId(), err) - err = s.checkReplace(targetHosts[i].GetId(), err) + _, err = s.checkReplace(targetHosts[i].GetId(), err) if err != nil { jww.ERROR.Printf("Unable to checkReplace: %+v", err) } } } - proxies := s.getAny(s.poolParams.ProxyAttempts, targets) - for i := range proxies { - target := targets[i%len(targets)].DeepCopy() - result, err := sendFunc(proxies[i], target) - if err == nil { - return result, nil - } else { - jww.WARN.Printf("Unable to SendToPreferred %s via proxy "+ - "%s: %s", target, proxies[i].GetId(), err) - err = s.checkReplace(proxies[i].GetId(), err) - if err != nil { - jww.ERROR.Printf("Unable to checkReplace: %+v", err) + // Build a list of proxies for every target + proxies := make([][]*connect.Host, len(targets)) + for i := 0; i < len(targets); i++ { + proxies[i] = s.getAny(s.poolParams.ProxyAttempts, targets) + } + + // Build a map of bad proxies + badProxies := make(map[string]interface{}) + + // Iterate between each target's list of proxies, using the next target for each proxy + for proxyIdx := uint32(0); proxyIdx < s.poolParams.ProxyAttempts; proxyIdx++ { + for targetIdx := range proxies { + target := targets[targetIdx] + targetProxies := proxies[targetIdx] + proxy := targetProxies[proxyIdx] + + // Skip bad proxies + if _, ok := badProxies[proxy.String()]; ok { + continue + } + + result, err := sendFunc(targetProxies[proxyIdx], target) + if err == nil { + return result, nil + } else { + jww.WARN.Printf("Unable to SendToPreferred %s via proxy "+ + "%s: %s", target, proxy.GetId(), err) + wasReplaced, err := s.checkReplace(proxy.GetId(), err) + if err != nil { + jww.ERROR.Printf("Unable to checkReplace: %+v", err) + } + // If the proxy was replaced, add as a bad proxy + if wasReplaced { + badProxies[proxy.String()] = nil + } } } } diff --git a/network/manager.go b/network/manager.go index 31adb444767b544e7c6a62da9489631293dbdd8a..1cf065d691b44ca061404b426af7c26df965ca40 100644 --- a/network/manager.go +++ b/network/manager.go @@ -130,7 +130,7 @@ func (m *manager) Follow(report interfaces.ClientErrorReport) (stoppable.Stoppab // Start the Network Tracker trackNetworkStopper := stoppable.NewSingle("TrackNetwork") - go m.followNetwork(report, trackNetworkStopper.Quit()) + go m.followNetwork(report, trackNetworkStopper.Quit(), trackNetworkStopper) multi.Add(trackNetworkStopper) // Message reception diff --git a/network/message/garbled_test.go b/network/message/garbled_test.go index 9d021ae488ed26717aade2d76d87ba688c7f9001..ab4919f16d674ea10a609ca6d0e46a442259789f 100644 --- a/network/message/garbled_test.go +++ b/network/message/garbled_test.go @@ -105,6 +105,7 @@ func TestManager_CheckGarbledMessages(t *testing.T) { contents := make([]byte, msg.ContentsSize()) prng := rand.New(rand.NewSource(42)) prng.Read(contents) + contents[len(contents)-1] = 0 fmp := parse.FirstMessagePartFromBytes(contents) binary.BigEndian.PutUint32(fmp.Type, uint32(message.Raw)) fmp.NumParts[0] = uint8(1) diff --git a/network/message/parse/firstMessagePart.go b/network/message/parse/firstMessagePart.go index 958a386992f161f007921476f52eb9749ea628bf..fa67b64411e0f2272178452eeb0a8deb91612271 100644 --- a/network/message/parse/firstMessagePart.go +++ b/network/message/parse/firstMessagePart.go @@ -9,92 +9,123 @@ package parse import ( "encoding/binary" - jww "github.com/spf13/jwalterweatherman" "gitlab.com/elixxir/client/interfaces/message" "time" ) -const numPartsLen = 1 -const typeLen = message.TypeLen -const timestampLen = 15 -const firstHeaderLen = headerLen + numPartsLen + typeLen + timestampLen +// Sizes of message parts, in bytes. +const ( + numPartsLen = 1 + typeLen = message.TypeLen + timestampLen = 8 + firstPartVerLen = 1 + firstHeaderLen = headerLen + numPartsLen + typeLen + timestampLen + firstPartVerLen +) + +// The current version of the firstMessagePart message format. +const firstMessagePartCurrentVersion = 0 type firstMessagePart struct { messagePart NumParts []byte Type []byte Timestamp []byte + Version []byte // Version of the message format; always the last bit } -//creates a new first message part for the passed in contents. Does no length checks +// newFirstMessagePart creates a new firstMessagePart for the passed in +// contents. Does no length checks. func newFirstMessagePart(mt message.Type, id uint32, numParts uint8, timestamp time.Time, contents []byte) firstMessagePart { - //create the message structure - data := make([]byte, len(contents)+firstHeaderLen) - m := FirstMessagePartFromBytes(data) - //Put the message type in the message + // Create the message structure + m := FirstMessagePartFromBytes(make([]byte, len(contents)+firstHeaderLen)) + + // Set the message type binary.BigEndian.PutUint32(m.Type, uint32(mt)) - //Add the message ID + // Set the message ID binary.BigEndian.PutUint32(m.Id, id) - // Add the part number to the message, its always zero because this is the - // first part. Because the default is zero this step could be skipped, but\ - // keep it in the code for clarity + // Set the part number. It is always zero because this is the first part. + // Because the default is zero this step could be skipped, but keep it in + // the code for clarity. m.Part[0] = 0 - // Add the number of parts to the message + // Set the number of parts to the message m.NumParts[0] = numParts - //Serialize and add the timestamp to the payload - timestampBytes, err := timestamp.MarshalBinary() - if err != nil { - jww.FATAL.Panicf("Failed to create firstMessagePart: %s", err.Error()) - } - copy(m.Timestamp, timestampBytes) + // Set the timestamp as unix nano + binary.BigEndian.PutUint64(m.Timestamp, uint64(timestamp.UnixNano())) - //set the contents length + // Set the length of the contents binary.BigEndian.PutUint16(m.Len, uint16(len(contents))) - //add the contents to the payload + // Set the contents copy(m.Contents[:len(contents)], contents) + // Set the version number + m.Version[0] = firstMessagePartCurrentVersion + return m } -// Builds a first message part mapped to the passed in data slice. Mapped by -// reference, a copy is not made. +// Map of firstMessagePart encoding version numbers to their map functions. +var firstMessagePartFromBytesVersions = map[uint8]func([]byte) firstMessagePart{ + firstMessagePartCurrentVersion: firstMessagePartFromBytesVer0, +} + +// FirstMessagePartFromBytes builds a firstMessagePart mapped to the passed in +// data slice. Mapped by reference; a copy is not made. func FirstMessagePartFromBytes(data []byte) firstMessagePart { - m := firstMessagePart{ + + // Map the data according to its version + version := data[len(data)-1] + mapFunc, exists := firstMessagePartFromBytesVersions[version] + if exists { + return mapFunc(data) + } + + return firstMessagePart{} +} + +func firstMessagePartFromBytesVer0(data []byte) firstMessagePart { + return firstMessagePart{ messagePart: messagePart{ Data: data, Id: data[:idLen], Part: data[idLen : idLen+partLen], Len: data[idLen+partLen : idLen+partLen+lenLen], - Contents: data[idLen+partLen+numPartsLen+typeLen+timestampLen+lenLen:], + Contents: data[idLen+partLen+lenLen+numPartsLen+typeLen+timestampLen : len(data)-firstPartVerLen-1], }, - NumParts: data[idLen+partLen+lenLen : idLen+partLen+numPartsLen+lenLen], - Type: data[idLen+partLen+numPartsLen+lenLen : idLen+partLen+numPartsLen+typeLen+lenLen], - Timestamp: data[idLen+partLen+numPartsLen+typeLen+lenLen : idLen+partLen+numPartsLen+typeLen+timestampLen+lenLen], + NumParts: data[idLen+partLen+lenLen : idLen+partLen+lenLen+numPartsLen], + Type: data[idLen+partLen+lenLen+numPartsLen : idLen+partLen+lenLen+numPartsLen+typeLen], + Timestamp: data[idLen+partLen+lenLen+numPartsLen+typeLen : idLen+partLen+lenLen+numPartsLen+typeLen+timestampLen], + Version: data[len(data)-firstPartVerLen:], } - return m } +// GetType returns the message type. func (m firstMessagePart) GetType() message.Type { return message.Type(binary.BigEndian.Uint32(m.Type)) } +// GetNumParts returns the number of message parts. func (m firstMessagePart) GetNumParts() uint8 { return m.NumParts[0] } -func (m firstMessagePart) GetTimestamp() (time.Time, error) { - var t time.Time - err := t.UnmarshalBinary(m.Timestamp) - return t, err +// GetTimestamp returns the timestamp as a time.Time. +func (m firstMessagePart) GetTimestamp() time.Time { + return time.Unix(0, int64(binary.BigEndian.Uint64(m.Timestamp))) +} + +// GetVersion returns the version number of the data encoding. +func (m firstMessagePart) GetVersion() uint8 { + return m.Version[0] } +// Bytes returns the serialised message data. func (m firstMessagePart) Bytes() []byte { return m.Data } diff --git a/network/message/parse/firstMessagePart_test.go b/network/message/parse/firstMessagePart_test.go index 676723247fec562607d43f9a29dec827890c76a8..2411dd4a6896453f08d2fd02ae2dd15946f0f76c 100644 --- a/network/message/parse/firstMessagePart_test.go +++ b/network/message/parse/firstMessagePart_test.go @@ -18,16 +18,19 @@ import ( // Expected firstMessagePart for checking against, generated by fmp in TestNewFirstMessagePart var efmp = firstMessagePart{ messagePart: messagePart{ - Data: []byte{0, 0, 4, 53, 0, 0, 13, 2, 0, 0, 0, 2, 1, 0, 0, 0, 14, 215, 133, 90, 117, 0, 0, 0, 0, 255, 255, - 116, 101, 115, 116, 105, 110, 103, 115, 116, 114, 105, 110, 103}, - Id: []byte{0, 0, 4, 53}, - Part: []byte{0}, - Len: []byte{0, 13}, - Contents: []byte{116, 101, 115, 116, 105, 110, 103, 115, 116, 114, 105, 110, 103}, + Data: []byte{0, 0, 4, 53, 0, 0, 13, 2, 0, 0, 0, 2, 22, 87, 28, 11, 215, + 220, 82, 0, 116, 101, 115, 116, 105, 110, 103, 115, 116, 114, 105, + 110, 103, 0, firstMessagePartCurrentVersion}, + Id: []byte{0, 0, 4, 53}, + Part: []byte{0}, + Len: []byte{0, 13}, + Contents: []byte{116, 101, 115, 116, 105, 110, 103, 115, 116, 114, 105, + 110, 103}, }, NumParts: []byte{2}, Type: []byte{0, 0, 0, 2}, - Timestamp: []byte{1, 0, 0, 0, 14, 215, 133, 90, 117, 0, 0, 0, 0, 255, 255}, + Timestamp: []byte{22, 87, 28, 11, 215, 220, 82, 0}, + Version: []byte{firstMessagePartCurrentVersion}, } // Test that newFirstMessagePart returns a correctly made firstMessagePart @@ -37,24 +40,19 @@ func TestNewFirstMessagePart(t *testing.T) { 1077, 2, time.Unix(1609786229, 0).UTC(), - []byte{'t', 'e', 's', 't', 'i', 'n', 'g', - 's', 't', 'r', 'i', 'n', 'g'}, + []byte{'t', 'e', 's', 't', 'i', 'n', 'g', 's', 't', 'r', 'i', 'n', 'g'}, ) - gotTime, err := fmp.GetTimestamp() - if err != nil { - t.Error(err) - } - expectedTime, err := fmp.GetTimestamp() - if err != nil { - t.Error(err) - } + gotTime := fmp.GetTimestamp() + expectedTime := time.Unix(1609786229, 0).UTC() if !gotTime.Equal(expectedTime) { - t.Errorf("Got time: %v, expected time: %v", gotTime, expectedTime) + t.Errorf("Failed to get expected timestamp."+ + "\nexpected: %s\nreceived: %s", expectedTime, gotTime) } if !reflect.DeepEqual(fmp, efmp) { - t.Errorf("Expected and got firstMessagePart did not match.\n\tGot: %#v\n\tExpected: %#v", fmp, efmp) + t.Errorf("Expected and got firstMessagePart did not match."+ + "\nexpected: %+v\nrecieved: %+v", efmp, fmp) } } @@ -83,10 +81,7 @@ func TestFirstMessagePart_GetNumParts(t *testing.T) { // Test that GetTimestamp returns the correct timestamp for a firstMessagePart func TestFirstMessagePart_GetTimestamp(t *testing.T) { - et, err := efmp.GetTimestamp() - if err != nil { - t.Error(err) - } + et := efmp.GetTimestamp() if !time.Unix(1609786229, 0).Equal(et) { t.Errorf("Got %v, expected %v", et, time.Unix(1609786229, 0)) } diff --git a/network/message/parse/messagePart.go b/network/message/parse/messagePart.go index 815544be80370e2c4f66482c903ae0cbe9e9ad92..01c514d7c33fe1654534a67aeaf8671744d93982 100644 --- a/network/message/parse/messagePart.go +++ b/network/message/parse/messagePart.go @@ -11,10 +11,17 @@ import ( "encoding/binary" ) -const idLen = 4 -const partLen = 1 -const lenLen = 2 -const headerLen = idLen + partLen + lenLen +// Sizes of message parts, in bytes. +const ( + idLen = 4 + partLen = 1 + lenLen = 2 + partVerLen = 1 + headerLen = idLen + partLen + lenLen + partVerLen +) + +// The current version of the messagePart message format. +const messagePartCurrentVersion = 0 type messagePart struct { Data []byte @@ -22,62 +29,90 @@ type messagePart struct { Part []byte Len []byte Contents []byte + Version []byte // Version of the message format; always the last bit } -//creates a new message part for the passed in contents. Does no length checks +// newMessagePart creates a new messagePart for the passed in contents. Does no +// length checks. func newMessagePart(id uint32, part uint8, contents []byte) messagePart { - //create the message structure + // Create the message structure data := make([]byte, len(contents)+headerLen) - m := MessagePartFromBytes(data) + m := messagePartFromBytes(data) - //add the message ID to the message + // Set the message ID binary.BigEndian.PutUint32(m.Id, id) - //set the message part number + // Set the message part number m.Part[0] = part - //set the contents length + // Set the contents length binary.BigEndian.PutUint16(m.Len, uint16(len(contents))) - //copy the contents into the message + // Copy the contents into the message copy(m.Contents[:len(contents)], contents) + + // Set the version number + m.Version[0] = messagePartCurrentVersion + return m } -// Builds a Message part mapped to the passed in data slice. Mapped by -// reference, a copy is not made. -func MessagePartFromBytes(data []byte) messagePart { - m := messagePart{ +// Map of messagePart encoding version numbers to their map functions. +var messagePartFromBytesVersions = map[uint8]func([]byte) messagePart{ + messagePartCurrentVersion: messagePartFromBytesVer0, +} + +// messagePartFromBytes builds a messagePart mapped to the passed in data slice. +// Mapped by reference; a copy is not made. +func messagePartFromBytes(data []byte) messagePart { + + // Map the data according to its version + version := data[len(data)-1] + mapFunc, exists := messagePartFromBytesVersions[version] + if exists { + return mapFunc(data) + } + + return messagePart{} +} + +func messagePartFromBytesVer0(data []byte) messagePart { + return messagePart{ Data: data, Id: data[:idLen], Part: data[idLen : idLen+partLen], Len: data[idLen+partLen : idLen+partLen+lenLen], - Contents: data[idLen+partLen+lenLen:], + Contents: data[idLen+partLen+lenLen : len(data)-partVerLen], + Version: data[len(data)-partVerLen:], } - return m } +// GetID returns the message ID. func (m messagePart) GetID() uint32 { return binary.BigEndian.Uint32(m.Id) } +// GetPart returns the message part number. func (m messagePart) GetPart() uint8 { return m.Part[0] } +// GetContents returns the entire contents slice. func (m messagePart) GetContents() []byte { return m.Contents } +// GetSizedContents returns the contents truncated to include only stored data. func (m messagePart) GetSizedContents() []byte { - size := m.GetContentsLength() - return m.Contents[:size] + return m.Contents[:m.GetContentsLength()] } +// GetContentsLength returns the length of the data in the contents. func (m messagePart) GetContentsLength() int { return int(binary.BigEndian.Uint16(m.Len)) } +// Bytes returns the serialised message data. func (m messagePart) Bytes() []byte { return m.Data } diff --git a/network/message/parse/messagePart_test.go b/network/message/parse/messagePart_test.go index 5ab1db0213c05a18f7615a836e627350a5879616..61ecc7467ff5c95dd2cf89830cacbb319cf9660f 100644 --- a/network/message/parse/messagePart_test.go +++ b/network/message/parse/messagePart_test.go @@ -15,17 +15,19 @@ import ( // Expected messagePart for checking against, generated by gotmp in Test_newMessagePart var emp = messagePart{ - Data: []uint8{0x0, 0x0, 0x0, 0x20, 0x6, 0x0, 0x7, 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67}, + Data: []uint8{0x0, 0x0, 0x0, 0x20, 0x6, 0x0, 0x7, 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, messagePartCurrentVersion}, Id: []uint8{0x0, 0x0, 0x0, 0x20}, Part: []uint8{0x6}, Len: []uint8{0x0, 0x7}, Contents: []uint8{0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67}, + Version: []uint8{messagePartCurrentVersion}, } // This tests that a new function part is successfully created func Test_newMessagePart(t *testing.T) { gotmp := newMessagePart(32, 6, []byte{'t', 'e', 's', 't', 'i', 'n', 'g'}) if !reflect.DeepEqual(gotmp, emp) { - t.Errorf("MessagePart received and MessagePart expected do not match.\n\tGot: %#v\n\tExpected: %#v", gotmp, emp) + t.Errorf("MessagePart received and MessagePart expected do not match."+ + "\nexpected: %#v\nreceived: %#v", emp, gotmp) } } diff --git a/network/message/parse/partition.go b/network/message/parse/partition.go index 0b690a5bef804dd269cd62cbcc0ecac6d2667439..e7fbbfd313379570d3ec522d23053fbd025456cf 100644 --- a/network/message/parse/partition.go +++ b/network/message/parse/partition.go @@ -9,7 +9,6 @@ package parse import ( "github.com/pkg/errors" - jww "github.com/spf13/jwalterweatherman" "gitlab.com/elixxir/client/interfaces/message" "gitlab.com/elixxir/client/storage" "gitlab.com/xx_network/primitives/id" @@ -44,23 +43,23 @@ func (p Partitioner) Partition(recipient *id.ID, mt message.Type, if len(payload) > p.maxSize { return nil, 0, errors.Errorf("Payload is too long, max payload "+ - "length is %v, received %v", p.maxSize, len(payload)) + "length is %d, received %d", p.maxSize, len(payload)) } - //Get the ID of the sent message + // Get the ID of the sent message fullMessageID, messageID := p.session.Conversations().Get(recipient).GetNextSendID() - // get the number of parts of the message. This equates to just a linear + // Get the number of parts of the message; this equates to just a linear // equation numParts := uint8((len(payload) + p.deltaFirstPart + p.partContentsSize - 1) / p.partContentsSize) parts := make([][]byte, numParts) - //Create the first message part + // Create the first message part var sub []byte sub, payload = splitPayload(payload, p.firstContentsSize) parts[0] = newFirstMessagePart(mt, messageID, numParts, timestamp, sub).Bytes() - //create all subsiquent message parts + // Create all subsequent message parts for i := uint8(1); i < numParts; i++ { sub, payload = splitPayload(payload, p.partContentsSize) parts[i] = newMessagePart(messageID, i, sub).Bytes() @@ -69,31 +68,25 @@ func (p Partitioner) Partition(recipient *id.ID, mt message.Type, return parts, fullMessageID, nil } -func (p Partitioner) HandlePartition(sender *id.ID, e message.EncryptionType, +func (p Partitioner) HandlePartition(sender *id.ID, _ message.EncryptionType, contents []byte, relationshipFingerprint []byte) (message.Receive, bool) { - //If it is the first message in a set, handle it as so if isFirst(contents) { - //decode the message structure + // If it is the first message in a set, then handle it as so + + // Decode the message structure fm := FirstMessagePartFromBytes(contents) - timestamp, err := fm.GetTimestamp() - if err != nil { - jww.FATAL.Panicf("Failed Handle Partition, failed to get "+ - "timestamp message from %s messageID %v: %s", sender, - fm.Timestamp, err) - } - - //Handle the message ID + + // Handle the message ID messageID := p.session.Conversations().Get(sender). ProcessReceivedMessageID(fm.GetID()) - //Return the return p.session.Partition().AddFirst(sender, fm.GetType(), - messageID, fm.GetPart(), fm.GetNumParts(), timestamp, + messageID, fm.GetPart(), fm.GetNumParts(), fm.GetTimestamp(), fm.GetSizedContents(), relationshipFingerprint) - //If it is a subsiquent message part, handle it as so } else { - mp := MessagePartFromBytes(contents) + // If it is a subsequent message part, handle it as so + mp := messagePartFromBytes(contents) messageID := p.session.Conversations().Get(sender). ProcessReceivedMessageID(mp.GetID()) diff --git a/network/message/parse/partition_test.go b/network/message/parse/partition_test.go index 933db1a01d4e95605d44d7cf5f5dce4429f2a9b5..9351a1e77b7e80dfc74938fefe01203dd4f0b705 100644 --- a/network/message/parse/partition_test.go +++ b/network/message/parse/partition_test.go @@ -32,28 +32,28 @@ func TestNewPartitioner(t *testing.T) { 4096, p.baseMessageSize) } - if p.deltaFirstPart != 20 { + if p.deltaFirstPart != firstHeaderLen-headerLen { t.Errorf("deltaFirstPart content mismatch"+ "\n\texpected: %v\n\treceived: %v", - 20, p.deltaFirstPart) + firstHeaderLen-headerLen, p.deltaFirstPart) } - if p.firstContentsSize != 4069 { + if p.firstContentsSize != 4096-firstHeaderLen { t.Errorf("firstContentsSize content mismatch"+ "\n\texpected: %v\n\treceived: %v", - 4069, p.firstContentsSize) + 4096-firstHeaderLen, p.firstContentsSize) } - if p.maxSize != 1042675 { + if p.maxSize != (4096-firstHeaderLen)+(MaxMessageParts-1)*(4096-headerLen) { t.Errorf("maxSize content mismatch"+ "\n\texpected: %v\n\treceived: %v", - 1042675, p.maxSize) + (4096-firstHeaderLen)+(MaxMessageParts-1)*(4096-headerLen), p.maxSize) } - if p.partContentsSize != 4089 { + if p.partContentsSize != 4088 { t.Errorf("partContentsSize content mismatch"+ "\n\texpected: %v\n\treceived: %v", - 4089, p.partContentsSize) + 4088, p.partContentsSize) } if p.session != storeSession { diff --git a/network/message/sendCmix.go b/network/message/sendCmix.go index 2a7095843eb57c6f9af2af16ea9725fab0aac627..b608e8c6e2c62ace780a8ce8391f943ac1712bb1 100644 --- a/network/message/sendCmix.go +++ b/network/message/sendCmix.go @@ -40,7 +40,7 @@ const sendTimeBuffer = 2500 * time.Millisecond // Public manager function to send a message over CMIX func (m *Manager) SendCMIX(sender *gateway.Sender, msg format.Message, recipient *id.ID, param params.CMIX) (id.Round, ephemeral.Id, error) { msgCopy := msg.Copy() - return sendCmixHelper(sender, msgCopy, recipient, param, m.Instance, m.Session, m.nodeRegistration, m.Rng, m.TransmissionID, m.Comms) + return sendCmixHelper(sender, msgCopy, recipient, m.param, param, m.Instance, m.Session, m.nodeRegistration, m.Rng, m.TransmissionID, m.Comms) } // Payloads send are not End to End encrypted, MetaData is NOT protected with @@ -51,7 +51,7 @@ func (m *Manager) SendCMIX(sender *gateway.Sender, msg format.Message, recipient // If the message is successfully sent, the id of the round sent it is returned, // which can be registered with the network instance to get a callback on // its status -func sendCmixHelper(sender *gateway.Sender, msg format.Message, recipient *id.ID, param params.CMIX, instance *network.Instance, +func sendCmixHelper(sender *gateway.Sender, msg format.Message, recipient *id.ID, messageParams params.Messages, cmixParams params.CMIX, instance *network.Instance, session *storage.Session, nodeRegistration chan network.NodeGateway, rng *fastRNG.StreamGenerator, senderId *id.ID, comms sendCmixCommsInterface) (id.Round, ephemeral.Id, error) { @@ -61,13 +61,13 @@ func sendCmixHelper(sender *gateway.Sender, msg format.Message, recipient *id.ID jww.INFO.Printf("Looking for round to send cMix message to %s "+ "(msgDigest: %s)", recipient, msg.Digest()) - for numRoundTries := uint(0); numRoundTries < param.RoundTries; numRoundTries++ { + for numRoundTries := uint(0); numRoundTries < cmixParams.RoundTries; numRoundTries++ { elapsed := netTime.Now().Sub(timeStart) - if elapsed > param.Timeout { + if elapsed > cmixParams.Timeout { jww.INFO.Printf("No rounds to send to %s (msgDigest: %s) "+ "were found before timeout %s", recipient, msg.Digest(), - param.Timeout) + cmixParams.Timeout) return 0, ephemeral.Id{}, errors.New("Sending cmix message timed out") } if numRoundTries > 0 { @@ -76,7 +76,7 @@ func sendCmixHelper(sender *gateway.Sender, msg format.Message, recipient *id.ID msg.Digest()) } - remainingTime := param.Timeout - elapsed + remainingTime := cmixParams.Timeout - elapsed //find the best round to send to, excluding attempted rounds bestRound, _ := instance.GetWaitingRounds().GetUpcomingRealtime(remainingTime, attempted, sendTimeBuffer) if bestRound == nil { @@ -128,7 +128,7 @@ func sendCmixHelper(sender *gateway.Sender, msg format.Message, recipient *id.ID "(msgDigest: %s) due to missing relationships with nodes: %s", bestRound.ID, recipient, msg.Digest(), missingKeys) go handleMissingNodeKeys(instance, nodeRegistration, missingKeys) - time.Sleep(param.RetryDelay) + time.Sleep(cmixParams.RetryDelay) continue } @@ -175,7 +175,7 @@ func sendCmixHelper(sender *gateway.Sender, msg format.Message, recipient *id.ID encMsg.Digest(), firstGateway.String()) // Send the payload - result, err := sender.SendToSpecific(firstGateway, func(host *connect.Host, target *id.ID) (interface{}, bool, error) { + sendFunc := func(host *connect.Host, target *id.ID) (interface{}, bool, error) { wrappedMsg.Target = target.Marshal() result, err := comms.SendPutMessage(host, wrappedMsg) if err != nil { @@ -203,7 +203,13 @@ func sendCmixHelper(sender *gateway.Sender, msg format.Message, recipient *id.ID } } return result, false, err - }) + } + var result interface{} + if messageParams.ProxySending { + result, err = sender.SendToSpecific(firstGateway, sendFunc) + } else { + result, err = sender.SendToSpecific(firstGateway, sendFunc) + } //if the comm errors or the message fails to send, continue retrying. //return if it sends properly diff --git a/network/message/sendCmix_test.go b/network/message/sendCmix_test.go index 04da108426dda151bec4777338fe4a0036366832..28a2cdbab74a68f12ce6e45814bde8ff521adcf1 100644 --- a/network/message/sendCmix_test.go +++ b/network/message/sendCmix_test.go @@ -143,7 +143,7 @@ func Test_attemptSendCmix(t *testing.T) { msgCmix := format.NewMessage(m.Session.Cmix().GetGroup().GetP().ByteLen()) msgCmix.SetContents([]byte("test")) e2e.SetUnencrypted(msgCmix, m.Session.User().GetCryptographicIdentity().GetTransmissionID()) - _, _, err = sendCmixHelper(sender, msgCmix, sess2.GetUser().ReceptionID, params.GetDefaultCMIX(), + _, _, err = sendCmixHelper(sender, msgCmix, sess2.GetUser().ReceptionID, params.GetDefaultMessage(), params.GetDefaultCMIX(), m.Instance, m.Session, m.nodeRegistration, m.Rng, m.TransmissionID, &MockSendCMIXComms{t: t}) if err != nil { diff --git a/network/message/sendUnsafe.go b/network/message/sendUnsafe.go index df7f05cb8df4ba368f3a3a19368dcb13214f7d49..19f7d5d5ce0bfe6dd14df77b76f0a21c824b2404 100644 --- a/network/message/sendUnsafe.go +++ b/network/message/sendUnsafe.go @@ -82,7 +82,7 @@ func (m *Manager) SendUnsafe(msg message.Send, param params.Unsafe) ([]id.Round, return nil, errors.Errorf("Failed to send %v/%v sub payloads:"+ " %s", numFail, len(partitions), errRtn) } else { - jww.INFO.Printf("Sucesfully Unsafe sent %d/%d to %s", + jww.INFO.Printf("Successfully Unsafe sent %d/%d to %s", len(partitions)-numFail, len(partitions), msg.Recipient) } diff --git a/stoppable/single.go b/stoppable/single.go index 8821db88eb4934a06db4f96484ef700b2c6beeff..2e8fa78a2a1c3f4f12752f045cb93c541da8412b 100644 --- a/stoppable/single.go +++ b/stoppable/single.go @@ -52,7 +52,6 @@ func (s *Single) Name() string { func (s *Single) Close(timeout time.Duration) error { var err error s.once.Do(func() { - atomic.StoreUint32(&s.running, 0) timer := time.NewTimer(timeout) select { case <-timer.C: @@ -61,6 +60,7 @@ func (s *Single) Close(timeout time.Duration) error { err = errors.Errorf("%s failed to close", s.name) case s.quit <- struct{}{}: } + atomic.StoreUint32(&s.running, 0) }) return err } diff --git a/storage/partition/store.go b/storage/partition/store.go index de601693828ccd159dbdaefad11139942df2c15c..52f7f330f06aa4887c64d991f3f384714073b3cb 100644 --- a/storage/partition/store.go +++ b/storage/partition/store.go @@ -8,11 +8,11 @@ package partition import ( - "crypto/md5" "encoding/binary" "gitlab.com/elixxir/client/interfaces/message" "gitlab.com/elixxir/client/storage/versioned" "gitlab.com/xx_network/primitives/id" + "golang.org/x/crypto/blake2b" "sync" "time" ) @@ -69,7 +69,15 @@ func (s *Store) load(partner *id.ID, messageID uint64) *multiPartMessage { } func getMultiPartID(partner *id.ID, messageID uint64) multiPartID { + h, _ := blake2b.New256(nil) + + h.Write(partner.Bytes()) b := make([]byte, 8) binary.BigEndian.PutUint64(b, messageID) - return md5.Sum(append(partner[:], b...)) + h.Write(b) + + var mpID multiPartID + copy(mpID[:], h.Sum(nil)) + + return mpID } diff --git a/storage/reception/store.go b/storage/reception/store.go index bd78f0b7682d3c06c2b47211f518729cb63cbfc1..08498aa5c0aa856727fe60c989419f2aeb18616a 100644 --- a/storage/reception/store.go +++ b/storage/reception/store.go @@ -2,7 +2,6 @@ package reception import ( "bytes" - "crypto/md5" "encoding/json" "github.com/pkg/errors" jww "github.com/spf13/jwalterweatherman" @@ -11,6 +10,7 @@ import ( "gitlab.com/xx_network/primitives/id" "gitlab.com/xx_network/primitives/id/ephemeral" "gitlab.com/xx_network/primitives/netTime" + "golang.org/x/crypto/blake2b" "io" "strconv" "sync" @@ -46,12 +46,11 @@ type storedReference struct { type idHash [16]byte func makeIdHash(ephID ephemeral.Id, source *id.ID) idHash { - h := md5.New() + h, _ := blake2b.New256(nil) h.Write(ephID[:]) h.Write(source.Bytes()) - idHashBytes := h.Sum(nil) idH := idHash{} - copy(idH[:], idHashBytes) + copy(idH[:], h.Sum(nil)) return idH } diff --git a/storage/utility/blockStore.go b/storage/utility/blockStore.go index a405e9b966175b77f8a9803e2efbe72bf2cf27af..b29dcd12d56037d6e7d0622b1fbc47f8faea62b9 100644 --- a/storage/utility/blockStore.go +++ b/storage/utility/blockStore.go @@ -21,6 +21,7 @@ const ( const ( bsBuffLengthErr = "length of buffer %d != %d expected" bsKvSaveErr = "failed to save blockStore to KV: %+v" + bsKvInitSaveErr = "failed to save initial block: %+v" bsKvLoadErr = "failed to get BlockStore from storage: %+v" bsKvUnmarshalErr = "failed to unmarshal BlockStore loaded from storage: %+v" bJsonMarshalErr = "failed to JSON marshal block %d: %+v" @@ -218,6 +219,12 @@ func (bs *BlockStore) save() error { return errors.Errorf(bsKvSaveErr, err) } + // Save initial block + err = bs.saveBlock() + if err != nil { + return errors.Errorf(bsKvInitSaveErr, err) + } + return nil } diff --git a/storage/utility/cmixMessageBuffer.go b/storage/utility/cmixMessageBuffer.go index 6091c65bc59ee0836384d4a475a15f8c8f7a940e..8c67658932ab64e75d91e2272f3b94c9c90f6314 100644 --- a/storage/utility/cmixMessageBuffer.go +++ b/storage/utility/cmixMessageBuffer.go @@ -8,7 +8,6 @@ package utility import ( - "crypto/md5" "encoding/json" "github.com/pkg/errors" jww "github.com/spf13/jwalterweatherman" @@ -16,6 +15,7 @@ import ( "gitlab.com/elixxir/primitives/format" "gitlab.com/xx_network/primitives/id" "gitlab.com/xx_network/primitives/netTime" + "golang.org/x/crypto/blake2b" ) const currentCmixMessageVersion = 0 @@ -80,8 +80,14 @@ func (cmh *cmixMessageHandler) DeleteMessage(kv *versioned.KV, key string) error // HashMessage generates a hash of the message. func (cmh *cmixMessageHandler) HashMessage(m interface{}) MessageHash { - sm := m.(storedMessage) - return md5.Sum(sm.Marshal()) + h, _ := blake2b.New256(nil) + + h.Write(m.(storedMessage).Marshal()) + + var messageHash MessageHash + copy(messageHash[:], h.Sum(nil)) + + return messageHash } // CmixMessageBuffer wraps the message buffer to store and load raw cmix diff --git a/storage/utility/e2eMessageBuffer.go b/storage/utility/e2eMessageBuffer.go index b8de8f65d3219f662df87680d174aec47743b97f..259c6407a2c08c45b4f2e486182964031669b98c 100644 --- a/storage/utility/e2eMessageBuffer.go +++ b/storage/utility/e2eMessageBuffer.go @@ -8,7 +8,6 @@ package utility import ( - "crypto/md5" "encoding/binary" "encoding/json" jww "github.com/spf13/jwalterweatherman" @@ -17,6 +16,7 @@ import ( "gitlab.com/elixxir/client/storage/versioned" "gitlab.com/xx_network/primitives/id" "gitlab.com/xx_network/primitives/netTime" + "golang.org/x/crypto/blake2b" ) const currentE2EMessageVersion = 0 @@ -80,17 +80,19 @@ func (emh *e2eMessageHandler) DeleteMessage(kv *versioned.KV, key string) error // Do not include the params in the hash so it is not needed to resubmit the // message into succeeded or failed func (emh *e2eMessageHandler) HashMessage(m interface{}) MessageHash { - msg := m.(e2eMessage) - - var digest []byte - digest = append(digest, msg.Recipient...) - digest = append(digest, msg.Payload...) + h, _ := blake2b.New256(nil) + msg := m.(e2eMessage) + h.Write(msg.Recipient) + h.Write(msg.Payload) mtBytes := make([]byte, 4) binary.BigEndian.PutUint32(mtBytes, msg.MessageType) - digest = append(digest, mtBytes...) + h.Write(mtBytes) + + var messageHash MessageHash + copy(messageHash[:], h.Sum(nil)) - return md5.Sum(digest) + return messageHash } // E2eMessageBuffer wraps the message buffer to store and load raw e2eMessages. diff --git a/storage/utility/messageBuffer_test.go b/storage/utility/messageBuffer_test.go index fc4de8be8dd5573520d02c9a35fae07593bb6a90..5e30960f9ccc3ad7060a876b7924fd3f0d8f3016 100644 --- a/storage/utility/messageBuffer_test.go +++ b/storage/utility/messageBuffer_test.go @@ -9,11 +9,11 @@ package utility import ( "bytes" - "crypto/md5" "encoding/json" "gitlab.com/elixxir/client/storage/versioned" "gitlab.com/elixxir/ekv" "gitlab.com/xx_network/primitives/netTime" + "golang.org/x/crypto/blake2b" "math/rand" "os" "reflect" @@ -48,10 +48,14 @@ func (th *testHandler) DeleteMessage(kv *versioned.KV, key string) error { } func (th *testHandler) HashMessage(m interface{}) MessageHash { - mBytes := m.([]byte) - // Sum returns a array that is the exact same size as the MessageHash and Go - // apparently automatically casts it - return md5.Sum(mBytes) + h, _ := blake2b.New256(nil) + + h.Write(m.([]byte)) + + var messageHash MessageHash + copy(messageHash[:], h.Sum(nil)) + + return messageHash } func newTestHandler() *testHandler { @@ -343,7 +347,13 @@ func makeTestMessages(n int) ([][]byte, map[MessageHash]struct{}) { for i := range msgs { msgs[i] = make([]byte, 256) prng.Read(msgs[i]) - mh[md5.Sum(msgs[i])] = struct{}{} + + h, _ := blake2b.New256(nil) + h.Write(msgs[i]) + var messageHash MessageHash + copy(messageHash[:], h.Sum(nil)) + + mh[messageHash] = struct{}{} } return msgs, mh diff --git a/storage/utility/meteredCmixMessageBuffer.go b/storage/utility/meteredCmixMessageBuffer.go index 719faa3883ebf6d47e5abf86931c3e9e1b8e0143..dd5ade5a31a51469587c4dd8a32d67f07b9c515e 100644 --- a/storage/utility/meteredCmixMessageBuffer.go +++ b/storage/utility/meteredCmixMessageBuffer.go @@ -8,13 +8,13 @@ package utility import ( - "crypto/md5" "encoding/json" "github.com/pkg/errors" jww "github.com/spf13/jwalterweatherman" "gitlab.com/elixxir/client/storage/versioned" "gitlab.com/elixxir/primitives/format" "gitlab.com/xx_network/primitives/netTime" + "golang.org/x/crypto/blake2b" "time" ) @@ -77,9 +77,14 @@ func (*meteredCmixMessageHandler) DeleteMessage(kv *versioned.KV, key string) er // HashMessage generates a hash of the message. func (*meteredCmixMessageHandler) HashMessage(m interface{}) MessageHash { - msg := m.(meteredCmixMessage) + h, _ := blake2b.New256(nil) + + h.Write(m.(meteredCmixMessage).M) + + var messageHash MessageHash + copy(messageHash[:], h.Sum(nil)) - return md5.Sum(msg.M) + return messageHash } // CmixMessageBuffer wraps the message buffer to store and load raw cmix