55 "database/sql"
66 "errors"
77 "math"
8+ "strings"
89 "time"
910
1011 "github.com/ethereum/go-ethereum/common"
@@ -25,7 +26,26 @@ import (
2526 "google.golang.org/protobuf/proto"
2627)
2728
28- var (
29+ const (
30+ // https://github.com/xmtp/libxmtp/blob/main/crates/xmtp_id/src/associations/association_log.rs#L10
31+ associationErrorGeneric = "Error creating association"
32+ associationErrorMultipleCreate = "Multiple create operations detected"
33+ associationErrorNotCreated = "XID not yet created"
34+ associationErrorSignature = "Signature validation failed"
35+ associationErrorMemberNotAllowed = "not allowed to add"
36+ associationErrorMissingExistingMember = "Missing existing member"
37+ associationErrorLegacySignatureReuse = "Legacy key is only allowed to be associated using a legacy signature with nonce 0"
38+ associationErrorNewMemberIDSignatureMismatch = "The new member identifier does not match the signer"
39+ associationErrorWrongInboxID = "Wrong inbox_id specified on association"
40+ associationErrorSignatureNotAllowed = "Signature not allowed for role"
41+ associationErrorReplay = "Replay detected"
42+ associationErrorDeserialization = "Deserialization error"
43+ associationErrorMissingIdentityUpdate = "Missing identity update"
44+ associationErrorChainIDMismatch = "Wrong chain id."
45+ associationErrorInvalidAccountAddress = "Invalid account address: Must be 42 hex characters, starting with '0x'."
46+ associationErrorNotIdentifier = "are not a public identifier"
47+ associationErrorConvert = "Conversion error"
48+
2949 ErrAdvisoryLockSequence = "advisory lock failed"
3050 ErrParseIdentityUpdate = "error parsing identity update"
3151 ErrGetLatestSequenceID = "get latest sequence id failed"
3454 ErrRevokeAddressFromLog = "revoke address from log failed"
3555)
3656
57+ var associationErrorPatterns = []string {
58+ associationErrorGeneric ,
59+ associationErrorMultipleCreate ,
60+ associationErrorNotCreated ,
61+ associationErrorSignature ,
62+ associationErrorMemberNotAllowed ,
63+ associationErrorMissingExistingMember ,
64+ associationErrorLegacySignatureReuse ,
65+ associationErrorNewMemberIDSignatureMismatch ,
66+ associationErrorWrongInboxID ,
67+ associationErrorSignatureNotAllowed ,
68+ associationErrorReplay ,
69+ associationErrorDeserialization ,
70+ associationErrorMissingIdentityUpdate ,
71+ associationErrorChainIDMismatch ,
72+ associationErrorInvalidAccountAddress ,
73+ associationErrorNotIdentifier ,
74+ associationErrorConvert ,
75+ }
76+
3777type IdentityUpdateStorer struct {
3878 contract * iu.IdentityUpdateBroadcaster
3979 db * sql.DB
@@ -156,6 +196,7 @@ func (s *IdentityUpdateStorer) StoreLog(
156196
157197 inboxID := utils .HexEncode (msgSent .InboxId [:])
158198
199+ // TODO: Batch insert address log entries
159200 for _ , newMember := range associationState .StateDiff .NewMembers {
160201 if s .logger .Core ().Enabled (zap .DebugLevel ) {
161202 s .logger .Debug ("new member" , utils .BodyField (newMember ))
@@ -185,6 +226,7 @@ func (s *IdentityUpdateStorer) StoreLog(
185226 }
186227 }
187228
229+ // TODO: Batch revoke address log entries
188230 for _ , removedMember := range associationState .StateDiff .RemovedMembers {
189231 if s .logger .Core ().Enabled (zap .DebugLevel ) {
190232 s .logger .Debug ("removed member" , utils .BodyField (removedMember ))
@@ -325,7 +367,14 @@ func (s *IdentityUpdateStorer) validateIdentityUpdate(
325367 identityUpdate .IdentityUpdate ,
326368 )
327369 if err != nil {
328- return nil , re .NewRecoverableError (
370+ if shouldRetryValidationError (err ) {
371+ return nil , re .NewRecoverableError (
372+ "could not get association state from envelopes" ,
373+ err ,
374+ )
375+ }
376+
377+ return nil , re .NewNonRecoverableError (
329378 "could not get association state from envelopes" ,
330379 err ,
331380 )
@@ -373,3 +422,17 @@ func buildSignedOriginatorEnvelope(
373422 },
374423 }, nil
375424}
425+
426+ // shouldRetryValidationError returns true if the error is a validation error that should be retried.
427+ // Note: this approach is fragile as it depends on us creating new error messages for new validation errors.
428+ // This function should rely on gRPC error codes instead, but it's not possible at the moment.
429+ // Read https://github.com/xmtp/libxmtp/issues/3130
430+ func shouldRetryValidationError (err error ) bool {
431+ errMsg := err .Error ()
432+ for _ , pattern := range associationErrorPatterns {
433+ if strings .Contains (errMsg , pattern ) {
434+ return false
435+ }
436+ }
437+ return true
438+ }
0 commit comments