diff --git a/bindings/e2eHandler.go b/bindings/e2eHandler.go index 2e7d002599bdee81b0894076a43a031e220f5a86..95256801441ed19654d1d516e824149c3ee040ea 100644 --- a/bindings/e2eHandler.go +++ b/bindings/e2eHandler.go @@ -10,12 +10,12 @@ package bindings import ( "encoding/json" "fmt" + "github.com/pkg/errors" jww "github.com/spf13/jwalterweatherman" "gitlab.com/elixxir/client/catalog" "gitlab.com/elixxir/client/cmix/identity/receptionID" "gitlab.com/elixxir/client/cmix/rounds" - "gitlab.com/elixxir/client/e2e" "gitlab.com/elixxir/primitives/format" "gitlab.com/xx_network/primitives/id" ) @@ -123,20 +123,24 @@ func (e *E2e) RemoveService(tag string) error { // - []byte - the JSON marshalled bytes of the E2ESendReport object, which can // be passed into Cmix.WaitForRoundResult to see if the send succeeded. func (e *E2e) SendE2E(messageType int, recipientId, payload, - e2eParams []byte) ([]byte, error) { - // Note that specifically these are the Base params from xxdk.E2EParams - params := e2e.GetDefaultParams() - err := params.UnmarshalJSON(e2eParams) + e2eParamsJSON []byte) ([]byte, error) { + if len(e2eParamsJSON) == 0 { + jww.WARN.Printf("e2e params not specified, using defaults...") + e2eParamsJSON = GetDefaultE2EParams() + } + params, err := parseE2EParams(e2eParamsJSON) if err != nil { return nil, err } + recipient, err := id.Unmarshal(recipientId) if err != nil { return nil, err } sendReport, err := e.api.GetE2E().SendE2E( - catalog.MessageType(messageType), recipient, payload, params) + catalog.MessageType(messageType), recipient, payload, + params.Base) if err != nil { return nil, err } diff --git a/cmix/sendCmix.go b/cmix/sendCmix.go index 73dfcfbd2c02b6f1cafcf49cd4662826edf7e3e8..f0c97a6ffc47f7611bc73d22132f2d0e087abe72 100644 --- a/cmix/sendCmix.go +++ b/cmix/sendCmix.go @@ -109,6 +109,12 @@ func sendCmixHelper(sender gateway.Sender, msg format.Message, recipient *id.ID, nodes nodes.Registrar, rng *fastRNG.StreamGenerator, events event.Reporter, senderId *id.ID, comms SendCmixCommsInterface) (id.Round, ephemeral.Id, error) { + if cmixParams.RoundTries == 0 { + return 0, ephemeral.Id{}, + errors.Errorf("invalid parameter set, "+ + "RoundTries cannot be 0: %+v", cmixParams) + } + timeStart := netTime.Now() maxTimeout := sender.GetHostParams().SendTimeout @@ -120,7 +126,8 @@ func sendCmixHelper(sender gateway.Sender, msg format.Message, recipient *id.ID, } jww.INFO.Printf("[Send-%s] Looking for round to send cMix message to "+ - "%s (msgDigest: %s)", cmixParams.DebugTag, recipient, msg.Digest()) + "%s (msgDigest: %s)", cmixParams.DebugTag, recipient, + msg.Digest()) stream := rng.GetStream() defer stream.Close() @@ -129,7 +136,8 @@ func sendCmixHelper(sender gateway.Sender, msg format.Message, recipient *id.ID, // See cmix.SetGroupBits for more info. cmix.SetGroupBits(msg, grp, stream) - for numRoundTries := uint(0); numRoundTries < cmixParams.RoundTries; numRoundTries++ { + for numRoundTries := uint( + 0); numRoundTries < cmixParams.RoundTries; numRoundTries++ { elapsed := netTime.Since(timeStart) jww.TRACE.Printf("[Send-%s] try %d, elapsed: %s", cmixParams.DebugTag, numRoundTries, elapsed) @@ -137,42 +145,50 @@ func sendCmixHelper(sender gateway.Sender, msg format.Message, recipient *id.ID, if elapsed > cmixParams.Timeout { jww.INFO.Printf("[Send-%s] No rounds to send to %s "+ "(msgDigest: %s) were found before timeout %s", - cmixParams.DebugTag, recipient, msg.Digest(), cmixParams.Timeout) - return 0, ephemeral.Id{}, errors.New("Sending cmix message timed out") + cmixParams.DebugTag, recipient, msg.Digest(), + cmixParams.Timeout) + return 0, ephemeral.Id{}, errors.New( + "Sending cmix message timed out") } if numRoundTries > 0 { - jww.INFO.Printf("[Send-%s] Attempt %d to find round to send "+ - "message to %s (msgDigest: %s)", cmixParams.DebugTag, + jww.INFO.Printf("[Send-%s] Attempt %d to find round"+ + " to send message to %s (msgDigest: %s)", + cmixParams.DebugTag, numRoundTries+1, recipient, msg.Digest()) } // Find the best round to send to, excluding attempted rounds remainingTime := cmixParams.Timeout - elapsed - bestRound, err := instance.GetWaitingRounds().GetUpcomingRealtime( + waitingRounds := instance.GetWaitingRounds() + bestRound, err := waitingRounds.GetUpcomingRealtime( remainingTime, attempted, sendTimeBuffer) if err != nil { - jww.WARN.Printf("[Send-%s] Failed to GetUpcomingRealtime "+ - "(msgDigest: %s): %+v", cmixParams.DebugTag, msg.Digest(), err) + jww.WARN.Printf("[Send-%s] GetUpcomingRealtime failed "+ + "(msgDigest: %s): %+v", cmixParams.DebugTag, + msg.Digest(), err) } if bestRound == nil { jww.WARN.Printf( - "[Send-%s] Best round on send is nil", cmixParams.DebugTag) + "[Send-%s] Best round on send is nil", + cmixParams.DebugTag) continue } jww.TRACE.Printf("[Send-%s] Best round found: %+v", cmixParams.DebugTag, bestRound) - // Determine whether the selected round contains any nodes that are - // blacklisted by the CMIXParams object + // Determine whether the selected round contains any + // nodes that are blacklisted by the CMIXParams object containsBlacklisted := false if cmixParams.BlacklistedNodes != nil { + blacklist := cmixParams.BlacklistedNodes for _, nodeId := range bestRound.Topology { var nid id.ID copy(nid[:], nodeId) - if _, isBlacklisted := cmixParams.BlacklistedNodes[nid]; isBlacklisted { + _, isBlacklisted := blacklist[nid] + if isBlacklisted { containsBlacklisted = true break } @@ -180,8 +196,10 @@ func sendCmixHelper(sender gateway.Sender, msg format.Message, recipient *id.ID, } if containsBlacklisted { - jww.WARN.Printf("[Send-%s] Round %d contains blacklisted "+ - "nodes, skipping...", cmixParams.DebugTag, bestRound.ID) + jww.WARN.Printf("[Send-%s] Round %d "+ + "contains blacklisted nodes, skipping...", + cmixParams.DebugTag, + bestRound.ID) continue } @@ -290,5 +308,5 @@ func sendCmixHelper(sender gateway.Sender, msg format.Message, recipient *id.ID, } return 0, ephemeral.Id{}, - errors.New("failed to send the message, unknown error") + errors.New("failed to send the message, out of round retries") } diff --git a/e2e/params.go b/e2e/params.go index 2702d490656342e975883177b115f63dbf2df961..ce0b72ff54282a5798c0ea2e085d8cd3143bc734 100644 --- a/e2e/params.go +++ b/e2e/params.go @@ -100,3 +100,9 @@ func (p *Params) UnmarshalJSON(data []byte) error { return nil } + +// String implements stringer interface by returning a json string +func (p *Params) String() string { + json, _ := p.MarshalJSON() + return string(json) +} diff --git a/e2e/sendE2E.go b/e2e/sendE2E.go index db231f74d8a68efbbfe8bfe0692f96ea09f080c1..3a181f3c7f2e508fe7372d7c2d8684919f016de8 100644 --- a/e2e/sendE2E.go +++ b/e2e/sendE2E.go @@ -76,23 +76,25 @@ func (m *manager) prepareSendE2E(mt catalog.MessageType, recipient *id.ID, partitions, internalMsgId, err := m.partitioner.Partition(recipient, mt, ts, payload) if err != nil { - return nil, - errors.WithMessage(err, "failed to send unsafe message") + return nil, errors.WithMessage(err, + "failed to send unsafe message") } - jww.INFO.Printf("E2E sending %d messages to %s", len(partitions), recipient) + jww.INFO.Printf("E2E sending %d messages to %s", + len(partitions), recipient) - // When sending E2E messages, we first partition into cMix packets and then - // send each partition over cMix + // When sending E2E messages, we first partition into cMix + // packets and then send each partition over cMix roundIds := make([]id.Round, len(partitions)) errCh := make(chan error, len(partitions)) - // The Key manager for the partner (recipient) ensures single use of each - // key negotiated for the ratchet + // The Key manager for the partner (recipient) ensures single + // use of each key negotiated for the ratchet partner, err := m.Ratchet.GetPartner(recipient) if err != nil { return nil, errors.WithMessagef(err, - "cannot send E2E message no relationship found with %s", recipient) + "cannot send E2E message no relationship found with %s", + recipient) } msgID := e2e.NewMessageID( @@ -103,14 +105,17 @@ func (m *manager) prepareSendE2E(mt catalog.MessageType, recipient *id.ID, for i, p := range partitions { if mt != catalog.KeyExchangeTrigger { // Check if any rekeys need to happen and trigger them - rekeySendFunc := func(mt catalog.MessageType, recipient *id.ID, - payload []byte, cmixParams cmix.CMIXParams) (e2e.SendReport, error) { + rekeySendFunc := func(mt catalog.MessageType, + recipient *id.ID, + payload []byte, cmixParams cmix.CMIXParams) ( + e2e.SendReport, error) { par := params par.CMIXParams = cmixParams return m.SendE2E(mt, recipient, payload, par) } - rekey.CheckKeyExchanges(m.net.GetInstance(), m.grp, rekeySendFunc, - m.events, partner, m.rekeyParams, 1*time.Minute) + rekey.CheckKeyExchanges(m.net.GetInstance(), m.grp, + rekeySendFunc, m.events, partner, + m.rekeyParams, 1*time.Minute) } var keyGetter func() (session.Cypher, error) @@ -120,27 +125,29 @@ func (m *manager) prepareSendE2E(mt catalog.MessageType, recipient *id.ID, keyGetter = partner.PopSendCypher } - // FIXME: remove this wait, it is weird. Why is it here? we cant remember. + // FIXME: remove this wait, it is weird. Why is it + // here? we cant remember. key, err := waitForKey( - keyGetter, params.KeyGetRetryCount, params.KeyGeRetryDelay, + keyGetter, params.KeyGetRetryCount, + params.KeyGeRetryDelay, params.Stop, recipient, format.DigestContents(p), i) if err != nil { return nil, errors.WithMessagef(err, "Failed to get key for end-to-end encryption") } - // This does not encrypt for cMix but instead end-to-end encrypts the - // cMix message + // This does not encrypt for cMix but instead + // end-to-end encrypts the cMix message contentsEnc, mac, residue := key.Encrypt(p) // Carry the first key residue to the top level if i == 0 { keyResidue = residue } - jww.INFO.Printf( - "E2E sending %d/%d to %s with key fp: %s, msgID: %s (msgDigest %s)", - i+i, len(partitions), recipient, key.Fingerprint(), msgID, - format.DigestContents(p)) + jww.INFO.Printf("E2E sending %d/%d to %s with key fp: %s, "+ + "msgID: %s (msgDigest %s)", + i+i, len(partitions), recipient, key.Fingerprint(), + msgID, format.DigestContents(p)) var s message.Service if i == len(partitions)-1 { @@ -149,16 +156,20 @@ func (m *manager) prepareSendE2E(mt catalog.MessageType, recipient *id.ID, s = partner.MakeService(params.ServiceTag) } - // We send each partition in its own thread here; some may send in round - // X, others in X+1 or X+2, and so on + // We send each partition in its own thread here; some + // may send in round X, others in X+1 or X+2, and so + // on localI := i thisSendFunc := func() { wg.Add(1) go func(i int) { var err error roundIds[i], _, err = m.net.Send(recipient, - key.Fingerprint(), s, contentsEnc, mac, params.CMIXParams) + key.Fingerprint(), s, contentsEnc, mac, + params.CMIXParams) if err != nil { + jww.DEBUG.Printf("[E2E] cMix error on "+ + "Send: %+v", err) errCh <- err } wg.Done() @@ -183,11 +194,12 @@ func (m *manager) prepareSendE2E(mt catalog.MessageType, recipient *id.ID, numFail, len(partitions), errRtn) } else { jww.INFO.Printf("Successfully E2E sent %d/%d to %s", - len(partitions)-numFail, len(partitions), recipient) + len(partitions)-numFail, len(partitions), + recipient) } - jww.INFO.Printf("Successful E2E Send of %d messages to %s with msgID %s", - len(partitions), recipient, msgID) + jww.INFO.Printf("Successful E2E Send of %d messages to %s "+ + "with msgID %s", len(partitions), recipient, msgID) return e2e.SendReport{ RoundList: roundIds,