-
Notifications
You must be signed in to change notification settings - Fork 39
Standardize logging #1262
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Standardize logging #1262
Conversation
How to use the Graphite Merge QueueAdd either label to this PR to merge it via the merge queue:
You must have a Graphite account in order to use the merge queue. Sign up using this link. An organization admin has enabled the Graphite Merge Queue in this repository. Please do not merge from GitHub as this will restart CI on PRs being processed by the merge queue. |
pkg/indexer/settlement_chain/contracts/payer_registry_storer.go
Outdated
Show resolved
Hide resolved
pkg/indexer/settlement_chain/contracts/payer_report_manager_storer.go
Outdated
Show resolved
Hide resolved
cmd/xmtpd-cli/commands/funds.go
Outdated
| logger.Info("successfully minted mock underlying fee token", | ||
| zap.String("to", to.Hex()), | ||
| zap.String("amountRaw", amount.String()), | ||
| zap.String("amount_raw", amount.String()), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess neither of these names is great. The user passes in --amount so we could use that. Or if we wanted to remind them its raw amount (raw) maybe?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
or raw_amount? I'm not sure to be honest. It's the CLI so I'm happy if it's readable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ended with amount for the sake of simplicity.
| return logger, &cfg, nil | ||
| } | ||
|
|
||
| /* Fields */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like this
mkysel
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
QOL goes to the moon
Standardize logging across services and components by adopting
pkg/utils/log.gofield helpers and named loggers, lowercasing messages, and renaming public APIs that carry logger parameters and fieldsUnifies logging by introducing shared logger names and field helpers, lowercasing messages, and refactoring logger parameters and fields from
logtologgeracross services, blockchain admins, indexers, workers, and CLIs; renames select public methods and constants to CamelCase and updates callers and tests accordingly; adds minor error-wrapping fixes and small utility features.pkg/utils/log.gowith standardized logger names andzap.Fieldhelpers; updates components to use named loggers and consistent snake_case keys; lowers message casing throughout log.goLogger/loggerand propagates named loggers across API servers, gateway, sync, indexer, migrator, workers, and blockchain packages; adjusts startup/shutdown logs and messagesSetHTTPAddress, parameter keys, originator IDs) and updates tests and call sites%win several constructors and helpers; adds minor utilities (currency.PicoDollar.String,ToDollars) and package comments📍Where to Start
Start with the logging utilities in
pkg/utils/log.goto see the new logger names and field helpers, then review how a representative service adopts them inpkg/api/server.go(https://github.com/xmtp/xmtpd/pull/1262/files#diff-734f9c34b34af099d24da13054e167f7df72706dc733edf21c61c0cc1548224a) and a blockchain component inpkg/blockchain/node_registry_admin.go(https://github.com/xmtp/xmtpd/pull/1262/files#diff-a06914b44c66a242a54ae2cfff18376479af3d12f90918be03417260f4674ea9).Changes since #1262 opened
📊 Macroscope summarized e19e281. 53 files reviewed, 101 issues evaluated, 96 issues filtered, 0 comments posted
🗂️ Filtered Issues
cmd/prune/main.go — 0 comments posted, 2 evaluated, 2 filtered
mainopens a database connection viadb.ConnectToDBand never closes it. There is nodefer dbInstance.Close()or any explicit close on success, error, or early termination paths. This causes a resource leak of the DB connection pool both on normal completion and on error paths (e.g.,fatal(...)exits). Given this is a short-lived command, leaking is still a bug per the single paired cleanup invariant. Adddefer dbInstance.Close()immediately after a successful connection, ensuring it runs on all exit paths. [ Invalidated by documentation search ]maincallsprune.NewPruneExecutor(...)after acquiring the DB connection.NewPruneExecutorpanics whenconfig.BatchSize <= 0. If that panic occurs, the DB connection remains open becausemaindoes notdefer dbInstance.Close(). This violates the single paired cleanup invariant on a panic path. Guard against panic by validatingBatchSizebefore calling, or at minimumdefer dbInstance.Close()immediately after successful connect to ensure cleanup in all paths. [ Invalidated by documentation search ]cmd/replication/main.go — 0 comments posted, 2 evaluated, 1 filtered
Versioncannot be parsed as semver, the code logs the error but continues, passing a potentiallynilversionintoserver.WithServerVersion(version). Downstream components (e.g.,registrant.NewRegistrant) may assume a non-nil version and could error or behave inconsistently. At minimum, this causes an externally visible contract ambiguity (version required earlier but not validated for semver correctness) and may lead to runtime errors depending on downstream expectations. Consider failing fast when semver parsing fails or providing a safe non-nil fallback. [ Low confidence ]cmd/xmtpd-cli/commands/admin_setup.go — 0 comments posted, 1 evaluated, 1 filtered
setupFundsAdmincreates two RPC clients (chainClientSettlementandchainClientApp) but does not close them on any error path after they are created. If any subsequent step fails (e.g., signer construction orblockchain.NewFundsAdmin), the function returns an error with both clients left open. This is a resource leak (open network connections) and violates the single paired cleanup requirement after introducing external effects. AddClose()calls for the clients on every error path after their creation (or use a scoped cleanup viadeferthat is canceled when returning success). [ Low confidence ]pkg/api/message/publish_worker.go — 0 comments posted, 5 evaluated, 5 filtered
startPublishWorkerassumesloggerandstoreare non-nil. It immediately callslogger.Named(utils.PublishWorkerName)andqueries.New(store). Ifloggerorstoreare nil, this will cause a runtime panic (nil pointer dereference) in the worker initialization goroutine. The caller does not guard these inputs before calling this function.Concrete failure paths:
logger == nil→ line 39logger.Named(...)→ panic.store == nil→ line 42queries.New(store)returns aQuerieswith nildb; later the subscription query will callQueryContexton nildb→ panic.Additionally,
feeCalculatorandregistrantare stored into the worker without validation, creating latent panic/logic issues when used later. [ Low confidence ]originatorID := int32(p.registrant.NodeID())narrows auint32toint32without bounds checking. If a node ID exceedsmath.MaxInt32(2,147,483,647), the conversion will wrap to a negative or otherwise incorrect value. This corruptedoriginatorIDis then used in database parameters (InsertGatewayEnvelopeParams.OriginatorNodeIDandIncrementUnsettledUsageParams.OriginatorID) and logs, leading to incorrect persisted data and potential downstream logic errors. [ Low confidence ]NewPayerEnvelopeFromByteserror), invalid topic (ParseTopicerror), and invalid signature (RecoverSignererror). In these cases,publishStagedEnvelopereturnsfalsewithout any remediation or dead-letter path, andstart()loops forever on the same staged envelope. [ Low confidence ]retentionDaysfrom the payer envelope is forwarded toRegistrant.SignStagedEnvelopewithout validation. InSignStagedEnvelope,time.Hour * 24 * time.Duration(retentionDays)can overflowtime.Duration(anint64nanoseconds count) whenretentionDaysexceeds approximately 106,751 days, yielding incorrect expiry computation. This produces invalidExpiryUnixtimeand thus malformedExpirystored in the DB. The source ofretentionDays(env.RetentionDays()) is external input; no guard is present here. [ Low confidence ]SpendPicodollarsis computed asint64(baseFee) + int64(congestionFee)without guarding against negative values or overflow. Iffees.IFeeCalculatorreturns negative fees or values large enough to overflowint64on addition, this will produce an incorrect spend (potentially negative), which can corrupt unsettled usage accounting (e.g., decrement usage instead of increment). [ Low confidence ]pkg/api/message/service.go — 0 comments posted, 9 evaluated, 9 filtered
NewReplicationAPIServiceperforms a nil check only forvalidationServiceand then immediately invokesstartPublishWorkerandstartSubscribeWorkerwith other dependencies that are assumed non-nil (logger,store,registrant,feeCalculator,updater). If any of these are nil, downstream code will panic at runtime. Examples:startPublishWorkercallslogger.Named(...)which dereferenceslogger;queries.New(store)relies onstorebeing non-nil, and the resulting query function will callQueryContexton a nil DB handle. The service construction path has no guard, so a misconfigured startup will crash.Concrete failure paths:
logger == nil→startPublishWorkerline 39 callslogger.Named(...)→ nil pointer deref panic.store == nil→queries.New(store)creates aQuerieswith a nildb; later the subscription query will callq.db.QueryContext(...)→ nil pointer deref panic.feeCalculator == nilandregistrant == nilmay not crash immediately here but will be stored and used later, creating latent panic paths; since they are essential to the worker, these should be validated up-front.updater == nilmay lead to later uses failing (cursor updates) without clear error. The constructor should enforce required invariants before spawning goroutines. [ Low confidence ]PublishPayerEnvelopessilently ignores all but the firstPayerEnvelopein the request and only returns a singleOriginatorEnvelopein the response, creating a contract-parity mismatch and silent data loss for batch inputs. The request typePublishPayerEnvelopesRequestaccepts multiplePayerEnvelopes, and the response typePublishPayerEnvelopesResponsereturns a list ofOriginatorEnvelope. However, the implementation validates and processes onlyreq.GetPayerEnvelopes()[0]and constructsOriginatorEnvelopes: []*envelopesProto.OriginatorEnvelope{originatorEnv}, discarding any additional envelopes without error or notice. This is a runtime logic bug: batch requests are accepted but not fully processed, and the response does not correspond one-to-one with the input elements. [ Low confidence ]publishWorker.notifyStagedPublish()can be dropped silently, potentially causingwaitForGatewayPublishto hit its 30s timeout unnecessarily if the publisher relies on notifications to wake up. The call site inPublishPayerEnvelopes(s.publishWorker.notifyStagedPublish()) does not check whether the notification was delivered. If the notifier channel is full or has no receiver, the notification is discarded, which can delay processing and lead to timeouts or increased latency. [ Low confidence ]waitForGatewayPublishtimes out or returns early onctx.Done()butPublishPayerEnvelopesdoes not propagate any failure or status and still returns a successful response with theOriginatorEnvelope. This can cause clients to receive a success response even though the publish may not have completed, violating expected publish semantics. Specifically,waitForGatewayPublishonly logs (at debug) on timeout or cancellation and returns; the caller then unconditionally builds and returns the response. If the API contract requires the publish to have completed before responding, this is a runtime behavior bug. At minimum, an explicit status or error should be returned to avoid silent partial completion. [ Low confidence ]req.Requests, builds an equally largeaddressesslice, and sends it to the database viaqueries.GetAddressLogs. This can create extremely large SQL array parameters and response allocations, causing memory spikes or heavy database load. Constants likemaxQueriesPerRequestexist but are not enforced here. [ Out of scope ]return nil, err), which gRPC will map to an Unknown code, while GetNewestEnvelope wraps DB errors usingstatus.Errorf(codes.Internal, ...). This inconsistency changes externally visible error codes for similar server-side failures, breaking contract parity across related endpoints. [ Out of scope ]req.Topicsand passes it to the DB, potentially creating extremely large array parameters and allocations. Constants such asmaxQueriesPerRequestandmaxTopicLengthare defined in this file but not enforced here, exposing the service to resource exhaustion or oversized inputs. [ Out of scope ]originalSort[string(topic)] = idxoverwrites earlier indices when the same topic appears multiple times, and later only a singleresults[idx]is populated. Earlier duplicate positions remainnil(or unpopulated), violating the intended 1:1 correspondence "The newest envelope for the given topic OR null" for each occurrence. This yields missing responses for earlier duplicates. [ Out of scope ]results := make([]*message_api.GetNewestEnvelopeResponse_Response, len(topics))and intentionally leaves entries asnilwhen there is no envelope for a given topic. Returning a repeated message field containingnilelements is invalid for protobuf v2 and will trigger a panic during gRPC/protobuf marshaling (historically: "proto: repeated field contains nil element"). The correct representation of "no envelope" should be a non-nilResponseelement with itsOriginatorEnvelopeoneof unset (zero-value), not anilentry in the slice. [ Out of scope ]pkg/api/message/subscribe_worker.go — 0 comments posted, 2 evaluated, 1 filtered
startSubscribeWorkerassumesloggerandstoreare non-nil. It immediately callslogger.Named(utils.SubscribeWorkerLoggerName)andqueries.New(store). Ifloggerorstoreare nil, this results in a runtime panic during worker initialization. The function lacks input validation and returns no error for this configuration issue, making the service crash instead of failing fast with a clear error. [ Low confidence ]pkg/api/payer/service.go — 0 comments posted, 2 evaluated, 2 filtered
PublishClientEnvelopesassumes the per-node response slice (originatorEnvelopes) has the exact same length and ordering as the request slice (payloadsWithIndex) and directly indexes into it withoriginatorEnvelopes[idx]while iteratingpayloadsWithIndex. If the downstream node returns fewer envelopes or a different ordering, this can cause an out-of-bounds panic or incorrectly assign envelopes to the wrong positions inout. There is no guard to verify length equality before indexing. The problematic lines are the loop assigningout[payloadsWithIndex[idx].originalIndex] = originatorEnvelopewithout validatinglen(originatorEnvelopes) == len(payloadsWithIndex). [ Low confidence ]utils.OriginatorIDFieldto log a node ID inpublishToBlockchainandpublishToNodeWithRetry. For example,s.logger.Debug("waiting for message to be processed by node", utils.OriginatorIDField(targetNodeID))and error logs in retry useutils.OriginatorIDField(nodeID). This labels the log field asoriginator_idwhile the value is a node ID, which can mislead observability and monitoring systems and cause incorrect attribution in metrics and logs. [ Low confidence ]pkg/blockchain/app_chain_admin.go — 0 comments posted, 2 evaluated, 2 filtered
NewAppChainAdmindoes not check forclient == nil,signer == nil, orparameterAdmin == nil. If any of these are nil, subsequent uses of the admin (e.g., reading or writing parameters, interacting with contracts) will dereference nil pointers and panic. The constructor should return an error when required dependencies are nil. [ Low confidence ]NewAppChainAdmindoes not validate the configured contract addresses. Passing an empty or malformed address string incontractsOptions.AppChain.IdentityUpdateBroadcasterAddress,GroupMessageBroadcasterAddress, orGatewayAddresswill result incommon.HexToAddressreturning the zero address, and the contract bindings will be created against0x0000000000000000000000000000000000000000. This will silently succeed and defer failures to later calls, causing hard-to-diagnose runtime errors. The constructor should explicitly validate that each address string is non-empty and a valid hex address, and reject invalid inputs with an error. [ Low confidence ]pkg/blockchain/blockchain_publisher.go — 0 comments posted, 5 evaluated, 4 filtered
NewBlockchainPublisherdoes not validate the configured contract addresses. IfcontractOptions.AppChain.GroupMessageBroadcasterAddressorIdentityUpdateBroadcasterAddressare empty or invalid,common.HexToAddresswill produce the zero address and the bindings will be created against it, leading to subtle runtime failures later. The constructor should validate addresses and return errors for invalid inputs. [ Low confidence ]NewBlockchainPublisherdoes not validate thatsignerandnonceManagerare non-nil. It callssigner.FromAddress()(line 68) and methods onnonceManager(lines 75 and 110). If either dependency is nil, the function will panic at runtime. Add explicit nil checks and return errors early to ensure safe operation. [ Low confidence ]NewBlockchainPublishercreates atime.NewTicker(10 * time.Second)inside the replenishment goroutine but never stops it. On context cancellation (select case<-innerCtx.Done()), the goroutine returns without callingticker.Stop(), leaking the ticker's underlying timer resource. Adddefer ticker.Stop()immediately after ticker creation to ensure cleanup on all exit paths. [ Invalidated by documentation search ]Cancelon any error after a successfulcreateintroduces a correctness bug: once a transaction has been created/submitted using the reserved nonce, a later failure inwait(e.g., timeout, context cancellation, transient RPC error) will causenonceContext.Cancel()to run via thedefer. Per theNonceContextcontract,Cancel"releases the nonce reservation, making it available for reuse". However, the transaction may still be pending or even mined; releasing the nonce risks assigning the same nonce to a new transaction, causing a collision and subsequentnonce too lowor replacement conflicts.This violates at-most-once semantics for nonce assignment and breaks invariants after an external effect (the transaction submission). Instead, the code should ensure the nonce is not reintroduced to the pool after the transaction is submitted—either consume immediately upon submission (with appropriate error handling) or mark as pending and ensure it’s not reused on
waitfailures. [ Invalidated by documentation search ]pkg/blockchain/funds_admin.go — 0 comments posted, 5 evaluated, 5 filtered
NewFundsAdmindoes not validate required contract addresses (FeeToken,UnderlyingFeeToken, settlementGatewayAddress, and appGatewayAddress). If any are empty or malformed,common.HexToAddresswill return the zero address without error, causing all subsequent contract bindings to point to0x000.... Interacting with these will fail at runtime (reverts or no contract). Add explicit validation that each address string is non-empty and a valid hex address before binding. [ Low confidence ]NewFundsAdminunconditionally binds aMockUnderlyingFeeTokencontract at the address provided byUnderlyingFeeToken. If the deployed contract at that address is a standard ERC-20 and not the mock, subsequent calls tomockUnderlyingFeeTokenmethods will fail at runtime due to ABI mismatch. This should be guarded by an environment/config flag or validation to ensure the address actually points to a mock contract when mock-only functionality is used. [ Low confidence ]NewFundsAdmin,NewNodeRegistryCaller, andNewContractRatesFetchercalllogger.Named(...)without checking ifloggeris non-nil. If a nil logger is passed, these calls cause a nil pointer dereference panic. Add a nil check and either default to a no-op logger or return an error. [ Low confidence ]NewFundsAdminsetsspendertocommon.HexToAddress(opts.ContractOptions.SettlementChain.GatewayAddress)without validating the address. If this is empty or invalid,spenderbecomes the zero address, which will cause incorrect approval flows (approving the zero address) and subsequent operations to fail or have unintended effects. ValidateGatewayAddressand fail fast if invalid. [ Invalidated by documentation search ]Withdrawchecks and logs the application-chain balance forfrom := f.settlement.Signer.FromAddress()but the transaction is executed withf.app.SignerviaExecuteTransaction. This means the preflight balance check and the "current balance" log are performed on the settlement signer’s address rather than the app signer’s address that will actually payopts.Valueand gas. As a result,Withdrawmay proceed even when the app signer lacks sufficient funds, causing the transaction to fail later at submission/mining, and the balance logs are misleading (they show the recipient’s or settlement signer’s app-chain balance, not the sender/app signer’s balance). The balance check should usef.app.Signer.FromAddress()for sender-side sufficiency, while still passing the intended recipient toWithdraw. [ Out of scope ]pkg/blockchain/node_registry_admin.go — 0 comments posted, 3 evaluated, 3 filtered
NewNodeRegistryAdmindoes not validatecontractsOptions.SettlementChain.NodeRegistryAddressbefore binding. If the address string is empty or malformed,common.HexToAddresswill produce the zero address, and the admin will be constructed against0x000.... Subsequent on-chain calls would target the wrong contract silently. Add explicit validation (non-empty, correct hex format, non-zero address) and return a clear error if invalid. [ Low confidence ]crypto.FromECDSAPub(signingKeyPub)is called without a nil check onsigningKeyPub. IfsigningKeyPubisnil, this call can panic at runtime. There is no guard inAddNodeto prevent a nil public key from being used. The upstream migrator path validates and returns a non-nil key, butAddNodeis a public method and can be called withnilfrom other paths. Add an explicit nil check and return a clear error rather than panicking. [ Low confidence ]AddNodedoes not verify that aNodeAddedevent was actually parsed and instead returns whatever value is left innodeID. If no matching event is found (e.g., the transaction succeeds but the parser rejects all logs),nodeIDremains0and is returned to the caller. This silently reports success with an invalid/ambiguous node ID (0), diverging from the stricter behavior used inSubmitPayerReport, which errors when no expected event is found. The method should track whether the event was found and return an error if not, to preserve contract parity and avoid propagating an invalid node ID. [ Invalidated by documentation search ]pkg/blockchain/node_registry_caller.go — 0 comments posted, 1 evaluated, 1 filtered
NewNodeRegistryCallerdoes not validatecontractsOptions.SettlementChain.NodeRegistryAddress. If it’s empty or invalid,common.HexToAddressyields the zero address and binds the contract to0x000..., causing runtime failures when calling methods. Add explicit address validation before binding. [ Low confidence ]pkg/blockchain/parameter_registry_admin.go — 0 comments posted, 3 evaluated, 3 filtered
NewParameterAdminWithRegistrydoes not check for nil dependencies (client,signer, orreg). If any are nil, later methods onParameterAdminthat use these fields will panic. The constructor should validate inputs and return an error when required dependencies are nil. [ Low confidence ]NewSettlementParameterAdmindoes not validatecontractsOptions.SettlementChain.ParameterRegistryAddressbefore using it to construct the settlement registry adapter. If this address is empty or invalid,common.HexToAddresswill resolve it to the zero address andsettleReg.NewSettlementChainParameterRegistrymay succeed, silently producing an admin bound to a zero-address contract. This misconfiguration will lead to later runtime failures when attempting reads/writes, but the constructor returns successfully, hiding the problem. The function should explicitly validate thatParameterRegistryAddressis a non-empty, valid hex address and fail fast with a clear error if not. [ Low confidence ]NewAppChainParameterAdmindoes not validate thatcontractsOptions.AppChain.ParameterRegistryAddressis a non-empty valid address string. If empty or invalid, the adapter will bind to the zero address viaHexToAddress, leading to subtle runtime failures. It should reject invalid addresses with an error ahead of binding. [ Low confidence ]pkg/blockchain/rate_registry_admin.go — 0 comments posted, 1 evaluated, 1 filtered
NewRatesAdmindoes not validatecontractsOptions.SettlementChain.RateRegistryAddressbefore binding. An empty or malformed input will result in binding to the zero address, leading to silent misdirected on-chain interactions. Validate the address and return an error if it is zero or invalid. [ Low confidence ]pkg/blockchain/settlement_chain_admin.go — 0 comments posted, 1 evaluated, 1 filtered
NewSettlementChainAdminbinds multiple contracts (SettlementChainGateway,PayerRegistry,DistributionManager,PayerReportManager,NodeRegistry,RateRegistry) using addresses fromcontractsOptions.SettlementChain.*Addresswithout validating any of them. If any address is empty or malformed, the binding will silently target the zero address. This can cause subtle misbehavior across many admin operations. Explicitly validate each address (non-empty, valid hex, non-zero) and surface a clear error. [ Low confidence ]pkg/fees/contract_rates.go — 0 comments posted, 4 evaluated, 4 filtered
NewContractRatesFetcherdoes not validateoptions.SettlementChain.RateRegistryAddress. If the address is empty or invalid,common.HexToAddressreturns the zero address, resulting in a contract bound to0x000...and runtime call failures. Validate the address string and fail fast if invalid. [ Low confidence ]currentIndexis not validated to be non-negative before use. Ifc.currentIndexis negative, the loop condition will hold and the code will callGetRateswith a negativefromIndex. This likely causes contract errors and the loop may not converge depending onpageSize. The code should enforcecurrentIndex >= 0and, ideally, initialize it to zero. [ Low confidence ]c.currentIndexis dereferenced without any prior nil check (c.currentIndex.Cmp(availableRatesCount)), which will panic ifc.currentIndexwas not initialized. There is no visible guard or constructor guarantee in the reviewed code ensuringc.currentIndexis non-nil beforerefreshDataruns. [ Low confidence ]pageSizeis not validated to be positive. Ifc.pageSize == 0, thentoFetchbecomes 0 andc.currentIndex = c.currentIndex.Add(c.currentIndex, toFetch)does not advance the index, causing an infinite loop that repeatedly callsGetRateswith a count of 0. Ifc.pageSize < 0,toFetchis negative; the loop will decrementcurrentIndex, and the conditionc.currentIndex.Cmp(availableRatesCount) < 0will likely remain true, resulting in a non-terminating loop and potentially invalid contract calls with a negative count. [ Low confidence ]pkg/indexer/app_chain/app_chain.go — 0 comments posted, 1 evaluated, 1 filtered
blockchain.NewRPCClientfails, the code callsrpcClient.Close()even thoughrpcClientwill benilwhen an error is returned fromethclient.DialContext. This results in a guaranteed nil pointer dereference. Specifically, inNewAppChain, after checkingif err != nil, the code executescancel()and thenrpcClient.Close()before returning. TheClose()call should be guarded with a nil check or omitted entirely when the client couldn't be constructed.Affected code:
rpcClient, err := blockchain.NewRPCClient(ctxwc, cfg.RPCURL)if err != nil { cancel(); rpcClient.Close(); return nil, fmt.Errorf("%v: %w", ErrInitializingAppChain, err) }[ Out of scope ]pkg/indexer/app_chain/contracts/group_message_storer.go — 0 comments posted, 2 evaluated, 2 filtered
StoreLogdoes not validate that the client envelope’s target topic identifier matches the on-chainGroupIdfrom theMessageSentevent. The only check performed isclientEnvelope.TopicMatchesPayload(), which verifies the topic kind against the payload type, but never confirms the identifier equality betweenclientEnvelope.TargetTopic()andtopic.NewTopic(topic.TopicKindGroupMessagesV1, msgSent.GroupId[:]). This can lead to storing an envelope under the wrong group topic when the payload kind is correct but the identifier is different, violating the contract’s intent and causing mis-association in the database. The issue is present at the construction oftopicStructand the subsequent check that only considers kind, not identifier. [ Out of scope ]msgSent.SequenceIdtoint64forOriginatorSequenceID. IfmsgSent.SequenceIdis auint64(typical for Solidityuint64/uint256-backed values), casting toint64withint64(msgSent.SequenceId)will produce a negative value or wrap for values greater thanmath.MaxInt64. This can lead to storing corrupted sequence IDs in the database and breaking ordering/invariants. There is no guard ensuringmsgSent.SequenceId <= math.MaxInt64before casting. [ Out of scope ]pkg/indexer/app_chain/contracts/identity_update_storer.go — 0 comments posted, 4 evaluated, 4 filtered
StoreLogwhen comparinglatestSequenceIDtomsgSent.SequenceId. The code doesif uint64(latestSequenceID) >= msgSent.SequenceId { ... }on line 114. IflatestSequenceIDis negative (e.g., due to an empty table defaulting to-1or any DB anomaly), converting it touint64produces a very large positive value, causing the condition to be true and the function to skip insertion erroneously. This yields incorrect behavior: identity updates may be skipped even though they are not present. The code must guardlatestSequenceID >= 0or otherwise handle absence explicitly before converting touint64. [ Low confidence ]msgSent.SequenceId(typeuint64) toint64in several places: logging viautils.SequenceIDField(int64(msgSent.SequenceId))(lines 119 and 171) and inserting viaInsertGatewayEnvelope(OriginatorSequenceID: int64(msgSent.SequenceId)on line 234-235). IfmsgSent.SequenceIdexceedsmath.MaxInt64, the cast wraps to a negativeint64, corrupting stored sequence values and misleading logs. This can break ordering guarantees and duplicate detection. [ Invalidated by documentation search ]associationState.StateDiff.NewMembersandRemovedMemberswithout checking thatassociationState.StateDiffis non-nil. IfGetAssociationStateFromEnvelopesreturns a result with a nilStateDiff, the loops on lines 149 and 177 will panic. Add a nil check onassociationStateandassociationState.StateDiffbefore iterating. [ Low confidence ]newMember.KindandremovedMember.Kindwithout verifying thatnewMember/removedMemberare non-nil. Elements of theNewMembers/RemovedMembersslices could benil. The type assertionaddress, ok := newMember.Kind.(*associations.MemberIdentifier_EthereumAddress)will panic ifnewMemberisnilbecause it dereferencesnewMember.Kind. Add checksif newMember == nil { continue }and similarly forremovedMember. Lines 154 and 182 are affected. [ Invalidated by documentation search ]pkg/indexer/indexer.go — 0 comments posted, 1 evaluated, 1 filtered
NewIndexerinitializesappChainand then proceeds to initializesettlementChain. Ifsettlementchain.NewSettlementChainfails (or any subsequent step afterappChaincreation), the function callscancel()on the indexer context and returns the error, but it does not perform any explicit teardown/cleanup of the already-createdappChaininstance. Depending onAppChain’s resource allocations (RPC/WebSocket clients, goroutines) and whether they respond to the parent context cancel, this can lead to resource leaks or partially initialized components lingering. To ensure correct cleanup and at-most-once semantics, add explicit teardown on failure (e.g., aClosemethod onAppChaininvoked on error) or guarantee that context cancellation deterministically releases all resources acquired duringNewAppChainconstruction. [ Invalidated by documentation search ]pkg/indexer/rpc_streamer/rpc_log_streamer.go — 0 comments posted, 3 evaluated, 1 filtered
sub.Err()returns a non-nil error, the code rebuilds the subscription and assigns the newsubwithout callingsub.Unsubscribe()on the old subscription (lines 202-206,lines 295-299). On exit paths (lines 193-196,lines 304-308) the function returns without unsubscribing the active subscription. EthereumSubscriptiontypically requiresUnsubscribe()to stop the underlying RPC notifications and free resources. Not callingUnsubscribe()when replacing or exiting can leak network resources and goroutines. [ Low confidence ]pkg/indexer/settlement_chain/contracts/payer_registry_storer.go — 0 comments posted, 3 evaluated, 3 filtered
parsedEvent.Amount(*big.Int) toint64viaparsedEvent.Amount.Int64()and then multiplying by1e6incurrency.FromMicrodollars. On-chain event amounts areuint256and can exceed the range ofint64.big.Int.Int64()will truncate on overflow, producing incorrect negative or wrapped values. Subsequently,microdollars * 1e6can overflowint64again, yielding an incorrectPicoDollar. This can cause incorrect ledger entries (wrong deposit amounts) without error or visibility. Consider validating the range before conversion, usingSetString/big.Intarithmetic, or using a wider integer type to avoid loss. [ Out of scope ]parsedEvent.Amount(*big.Int) toint64viaparsedEvent.Amount.Int64()and then multiplying by1e6incurrency.FromMicrodollars. For withdrawal requests, largeuint256amounts can exceedint64, causing truncation inInt64()and further overflow in the multiplication. This results in incorrect ledger withdrawal entries (wrong amounts applied) without any error. Use range checks andbig.Intarithmetic or a wider type. [ Out of scope ]parsedEvent.Amount(*big.Int) toint64viaparsedEvent.Amount.Int64()and then multiplying by1e6incurrency.FromMicrodollars. For usage settlements, largeuint256values can exceedint64, causing truncation uponInt64()and overflow in the* 1e6multiplication, leading to incorrect settlement amounts recorded in the ledger. Validate ranges and usebig.Intarithmetic or a wider integer representation. [ Out of scope ]pkg/indexer/settlement_chain/contracts/payer_report_manager_storer.go — 0 comments posted, 3 evaluated, 3 filtered
parsedEvent.StartSequenceIdandparsedEvent.EndSequenceIdfromuint64toint64for logging viautils.StartSequenceIDField(int64(parsedEvent.StartSequenceId))andutils.LastSequenceIDField(int64(parsedEvent.EndSequenceId))can overflow when the values exceedmath.MaxInt64. In Go, converting auint64larger thanMaxInt64toint64yields a negative number due to wraparound, resulting in incorrect (potentially negative) sequence IDs in logs. This is an externally visible artifact being malformed/incorrect. Usezap.Uint64or introduceutilshelpers that acceptuint64to preserve correctness. [ Low confidence ]strings.Contains(err.Error(), ErrReportAlreadyExists)to detect the duplicate-report case. This is a brittle control-flow dependency on the error string. If upstream code changes the message or wraps the error, this branch may fail to recognize the condition and incorrectly return a retryable or non-retryable error, altering external behavior. This should use a sentinel error, type assertion, orerrors.Is/errors.Asto robustly detect the condition. [ Low confidence ]parsedEvent.StartSequenceIdandparsedEvent.EndSequenceIdfromuint64toint64occurs in the "already exists" debug path as well, e.g.,utils.StartSequenceIDField(int64(parsedEvent.StartSequenceId))andutils.LastSequenceIDField(int64(parsedEvent.EndSequenceId)). If these values exceedmath.MaxInt64, the logged sequence IDs will be negative due to wraparound, misleading diagnostics in the duplicate-report path. [ Invalidated by documentation search ]pkg/integration/builders/xmtp_gateway_container_builder.go — 0 comments posted, 2 evaluated, 2 filtered
b.envVarsif it isnil. In both conditional blocks, the code writes to the map (b.envVars["XMTPD_SETTLEMENT_CHAIN_WSS_URL"] = b.wsURL,b.envVars["XMTPD_APP_CHAIN_WSS_URL"] = b.wsURL,b.envVars["XMTPD_SETTLEMENT_CHAIN_RPC_URL"] = b.rpcURL,b.envVars["XMTPD_APP_CHAIN_RPC_URL"] = b.rpcURL) without ensuringb.envVarsis non-nil. If a caller constructsXmtpdGatewayContainerBuilderwithout initializingenvVarsand provides a non-emptywsURLorrpcURL, this will cause a runtime panic due to nil map assignment. [ Low confidence ]req.Networksto[]string{b.networkName}without validatingb.networkName. Whenb.networkAlias == ""andb.networkName == "",Networkswill contain an empty string, which is likely invalid for testcontainers/Docker and can cause container creation to fail at runtime. The only guard (require.NotEmpty(t, b.networkName)) applies only whenb.networkAliasis non-empty. [ Low confidence ]pkg/integration/builders/xmtpd_container_builder.go — 0 comments posted, 3 evaluated, 3 filtered
b.envVarsis amap[string]stringbut there is no guard or initialization inBuild. On lines where the code sets environment variables (b.envVars["XMTPD_SETTLEMENT_CHAIN_WSS_URL"] = b.wsURL,b.envVars["XMTPD_APP_CHAIN_WSS_URL"] = b.wsURL,b.envVars["XMTPD_SETTLEMENT_CHAIN_RPC_URL"] = b.rpcURL,b.envVars["XMTPD_APP_CHAIN_RPC_URL"] = b.rpcURL), a zero-valuedXmtpdContainerBuilderor one constructed without initializingenvVarswill cause a runtime panic (assignment to entry in nil map). You should either initializeenvVarsduring construction or guard againstnilbefore writing. [ Low confidence ]Networks: The code always setsNetworks: []string{b.networkName}even whenb.networkNameis empty (no guard). This can produce a malformed container request with a single empty-name network, likely causing container start failures. Whenb.networkAliasis set, there is arequire.NotEmpty(t, b.networkName)guard, but whennetworkAliasis empty the guard does not run, leaving the empty network case unhandled. The fix is to conditionally setNetworksonly whenb.networkNameis non-empty, or passnil/omit the field otherwise. [ Low confidence ]Container:testcontainers.GenericContainercan return a non-nilerrand a nilxmtpdContainer. The code callstestcontainers.CleanupContainer(t, xmtpdContainer)unconditionally. IfCleanupContaineruses thecontainervalue to register termination (e.g., by invoking methods on it duringt.Cleanup), passingnilmay cause a panic later when the test ends. To be safe, guard the cleanup registration withif err == nil { testcontainers.CleanupContainer(t, xmtpdContainer) }. [ Invalidated by documentation search ]pkg/interceptors/server/auth.go — 0 comments posted, 1 evaluated, 1 filtered
AuthInterceptor.logIncomingAddressIfAvailableperforms a reverse DNS lookup (net.LookupAddr) on every incoming request when debug logging is enabled, without any timeout or context. This synchronous lookup can block the request path if DNS is slow or misconfigured, causing latency spikes or temporary stalls. It also ignores the request’s context for cancellation. A non-blocking or context-aware approach (e.g., lookup in a separate goroutine with timeout, caching, or disabled by default) is advisable. [ Low confidence ]pkg/metrics/metrics.go — 0 comments posted, 1 evaluated, 1 filtered
NewMetricsServer,s.httpis set to&proxyproto.Listener{Listener: httpListener}before checkingerrfromnet.Listen. Ifnet.Listenfails,httpListenerisnilands.httpwraps anillistener. While the function immediately returns the error and the wrappednillistener is not used, this is fragile ordering that risks future dereferences of a partially-initializedServerif the code changes.s.httpshould be assigned only after confirmingerr == nilto avoid temporarily storing an invalid listener. [ Code style ]pkg/migrator/migrator.go — 0 comments posted, 3 evaluated, 3 filtered
batchSizeis zero.maxInflight := int(m.batchSize) * 4yields 0,sem := make(chan struct{}, maxInflight)creates a zero-capacity channel with no tokens prefilled, and later the reader tries to acquire a token viaselect { case <-ctx.Done(): ...; case <-sem: }. Withctxnot cancelled, this select blocks indefinitely because no goroutine ever sends tosem(tokens are only returned bycleanupInflightafter processing records, but none can be processed before acquiring a token). This stalls the pipeline. The code should validatebatchSize > 0at startup or handle the zero case by skipping the semaphore or seeding at least one token. [ Invalidated by documentation search ]migrationWorkeruseslogger.Fatalon failure to read migration progress, which will terminate the entire process rather than just failing and retrying the reader loop. This is not in an initialization path and can be triggered by transient database errors, causing a full service crash and bypassing defers/cleanup in the goroutine. Specifically, after emitting a reader error metric, it callslogger.Fatal("failed to get migration progress", zap.Error(err)), which by default callsos.Exit(1). This violates the runtime termination guidance and resilience expectations for a long-running worker. The code should log an error and retry or back off (similar to the fetch error handling paths) instead of callingFatal. [ Low confidence ]inflightmap. The reader storesinflight[id] = startE2ELatencykeyed byrecord.GetID()(source record ID). Later, in the writer’s defer, it looks up and deletes usingint64(env.OriginatorSequenceID()). There is no explicit guarantee thatenv.OriginatorSequenceID()equalsrecord.GetID()for all tables. If they differ, then:existsis false (startTime, exists := inflight[int64(env.OriginatorSequenceID())]).delete(inflight, id)incleanupInflightdoes not remove the original entry (since it uses the sequence ID), leaving stale entries and growing the map.To fix, consistently use the same key for inflight tracking and cleanup (e.g., always use the source record ID, carry it through the envelope, or include it alongside the envelope when passing to writer). [ Low confidence ]
pkg/migrator/writer.go — 0 comments posted, 4 evaluated, 4 filtered
insertOriginatorEnvelopeDatabasecallsenv.UnsignedOriginatorEnvelope.PayerEnvelope.RecoverSigner()(line 32).RecoverSigner()accessesp.proto(p.proto.PayerSignature) without a nil check. IfPayerEnvelope.protois nil, this will panic. There is no visible guard in this function ensuring that thePayerEnvelope’sprotois non-nil, making a runtime nil pointer dereference possible. [ Low confidence ]IncrementUnsettledUsagecall:queries.IncrementUnsettledUsageParamsincludes aMessageCount int32field, butinsertOriginatorEnvelopeDatabasedoes not set it (lines 73–80). This results inMessageCountbeing sent as the zero value (0), which can corrupt usage accounting and violates the data-conversion boundary rule (all fields must be preserved or explicitly ignored with justification). [ Low confidence ]insertOriginatorEnvelopeDatabase:env.UnsignedOriginatorEnvelope.BaseFee()and.CongestionFee()(lines 77–78) dereferenceUnsignedOriginatorEnvelope.protowithout a nil check (the methods explicitly skip nil checks). IfUnsignedOriginatorEnvelope.protois nil, this will panic at runtime. There is no visible guard in this function ensuring this invariant. [ Invalidated by documentation search ]insertOriginatorEnvelopeBlockchaindereferencesenvwithout any nil guard. At function entry,env.TargetTopic().Identifier()(line 113) andenv.OriginatorSequenceID()(line 114) will panic ifenvis nil. Given the upstream writer pipeline forwards the envelope returned by the transformer without a concrete nil check, an(nil, nil)return from the transformer would flow into this function and cause a runtime nil pointer dereference. [ Low confidence ]pkg/payerreport/utils.go — 0 comments posted, 1 evaluated, 1 filtered
AddReportLogFieldscastsuint64fieldsStartSequenceIDandEndSequenceIDtoint64for logging:utils.StartSequenceIDField(int64(report.StartSequenceID))andutils.LastSequenceIDField(int64(report.EndSequenceID)). If these values exceedmath.MaxInt64, the cast will overflow and produce incorrect negative values in logs. This leads to misleading telemetry and can hinder debugging or monitoring. Use unsigned fields or string formatting to avoid overflow. [ Invalidated by documentation search ]pkg/payerreport/workers/generator.go — 0 comments posted, 2 evaluated, 2 filtered
maybeGenerateReportcan produce duplicate reports. The method performs a non-atomic check-then-act sequence: it first determines the last submitted report viagetLastSubmittedReport, then separately fetches existing pending/approved reports starting at that end sequence ID, and finally generates a new report if none are found. Between these steps, another component (e.g., a concurrent submitter) can transition a report or create a new one, causing this worker to miss it and generate a duplicate. This is explicitly noted in the TODO comments but not mitigated. There is no locking or transactional guarantee across these reads and the subsequent write (generateReport). This violates the no-double-application invariant and can lead to duplicated or overlapping reports. [ Out of scope ]uint64sequence IDs toint64for logging. InmaybeGenerateReport,existingReportEndSequenceIDis auint64, but is cast toint64inutils.LastSequenceIDField(int64(existingReportEndSequenceID)). If the sequence ID exceedsmath.MaxInt64, the value will wrap and become negative, corrupting the log output and potentially misleading operators and downstream log parsers expecting non-negative sequence IDs. [ Invalidated by documentation search ]pkg/payerreport/workers/submitter.go — 0 comments posted, 2 evaluated, 2 filtered
SetReportSubmitted(ctx, report.ID, reportIndex)usingreportIndexthat was returned alongside a non-nil error fromsubmitReport. There is no guarantee thatsubmitReportreturns a valid/meaningful index when it returns an error (e.g., onIsErrPayerReportAlreadySubmitted). This can cause the system to persist an incorrectSubmittedReportIndex(likely zero or stale) for the report. The code should derive or fetch the canonical index for the already-submitted report (e.g., by querying the chain or DB) or avoid writing a potentially invalid index when the submission failed. [ Low confidence ]submitReportis invoked withw.ctxinstead of the operation-scopedctxargument passed toSubmitReports. This can cause the blockchain submission to ignore per-iteration cancellations/timeouts, potentially delaying shutdown or causing work to continue after the caller canceled the operation. For consistency and proper cancellation semantics,submitReport(and thusreportsAdmin.SubmitPayerReport) should use thectxparameter ofSubmitReports. [ Low confidence ]pkg/registry/node_registry_contract.go — 0 comments posted, 3 evaluated, 3 filtered
SmartContractRegistry.processNewNodescallss.newNodesNotifier.trigger(nodes)before updating the internals.nodesmap. This can violate ordering invariants for observers: subscribers may be notified about new nodes whiles.nodesstill lacks those entries, leading to inconsistent reads or racey behavior in consumers that assume the registry reflects notifications immediately. The fix is to updates.nodesunder lock first, and only then trigger notifications, or document and enforce that notifications occur before the registry change with an explicit contract. [ Low confidence ]SmartContractRegistry.processNewNodesdoes not check whethers.newNodesNotifieris nil before callingtrigger. Sinces.newNodesNotifieris a pointer field with no visible guard or constructor guarantee here, a nil pointer dereference is reachable and would panic. Add a nil check before callingtriggeror ensure it is always initialized before use. [ Low confidence ]SingleNotificationNotifier.triggersends on subscriber channels while holding a read lock (RLock). If any send blocks (e.g., an unbuffered channel without a ready receiver or a buffered channel with a full buffer),processNewNodeswill block ontriggerand hold the read lock, potentially starving writers and causing deadlocks if other paths attempt to modifychannelsunder a write lock. The fix is to copy the subscriber set under lock, then release the lock before performing blocking sends, or use non-blocking send/select with a drop policy. [ Low confidence ]pkg/server/server.go — 0 comments posted, 1 evaluated, 1 filtered
startAPIServerstarts a background goroutine insidemetadata.NewCursorUpdaterbefore any of the subsequent service registrations, and if any later step returns an error (e.g., constructingreplicationService,metadataService, or creating the JWT verifier), the function exits without stopping the cursor updater. This leaks the goroutine and its resources becauses.cursorUpdateris not torn down on error paths. Specifically,s.cursorUpdater = metadata.NewCursorUpdater(s.ctx, cfg.Logger, cfg.DB)starts the updater, and then errors at lines following (e.g., returningerrat service construction or verifier creation) lead to an early return without callingRemoveSubscriber/Stop()or canceling its context. All exit paths after introducing this effect must provide a single paired cleanup; this code does not. [ Invalidated by documentation search ]pkg/sync/envelope_sink.go — 0 comments posted, 2 evaluated, 2 filtered
InsertGatewayEnvelopeAndIncrementUnsettledUsage, two goroutines are spawned to calltxQueries.IncrementUnsettledUsageandtxQueries.IncrementOriginatorCongestionconcurrently within a single transaction context.database/sqltransactions (*sql.Tx) are not safe for concurrent use; many drivers require operations on a transaction/connection to be strictly sequential. Running these queries in parallel on the sametxQueries(which likely wraps the*sql.Tx) risks runtime failures such asdatabase/sql: driver does not support concurrent transactionsor driver-specific errors, and can violate transactional invariants. Fix by executing these operations sequentially within the transaction, or by performing them in separate transactions if parallelism is desired (but that changes atomicity). [ Low confidence ]storeEnvelope,env.OriginatorSequenceID()returns auint64, but it is cast toint64forInsertGatewayEnvelopeParams.OriginatorSequenceIDand for logging viautils.SequenceIDField. If the sequence ID exceedsmath.MaxInt64, the cast will overflow and wrap to a negativeint64, resulting in incorrect database values and misleading logs. Similarly,env.OriginatorNodeID()returns auint32but is cast toint32(originatorID := int32(env.OriginatorNodeID())), which can overflow if the node ID exceedsmath.MaxInt32. These casts appear at lines141-142and163-164(sequence ID) and line128(originator ID). The same downcasts occur instoreReservedEnvelopewhen calling the payer report store functions that insert envelopes withOriginatorSequenceIDasint64andOriginatorNodeIDasint32. Fix by preserving the unsigned width end-to-end (useuint64/uint32where appropriate), or add explicit bounds checks and return an error when values are out of range to avoid silent corruption. [ Invalidated by documentation search ]pkg/sync/originator_stream.go — 0 comments posted, 5 evaluated, 5 filtered
originatorStream.listenlaunches a goroutine that continually callss.stream.Recv()and then sends results onrecvChan. There is no mechanism to stop this goroutine when the mainlistenloop exits (e.g., on context cancellation or error). SincerecvChanis unbuffered and never closed, iflistenreturns, the goroutine can block forever attempting to send onrecvChan, causing a goroutine leak and potential deadlock. Fix by: (a) selecting ons.ctx.Done()in the goroutine and returning; (b) closingrecvChanon exit; or (c) makingrecvChanbuffered and ensuring the goroutine terminates when the stream is closed/canceled. [ Low confidence ]originatorStream.listenwrites tos.writeQueueusing a blocking send (s.writeQueue <- parsedEnv) without any context or select. If the consumer ofwriteQueueis slow or absent (e.g., downstream failure), the listener will block indefinitely, preventing stream processing and potential cleanup on cancellation. Prefer a select withs.ctx.Done()and a bounded buffer or explicit error/timeout handling. [ Invalidated by documentation search ]originatorStream.validateEnvelope, metrics are emitted before full validation succeeds.EmitSyncLastSeenOriginatorSequenceIDandEmitSyncOriginatorReceivedMessagesCountare called before checking for out-of-order envelopes and before recovering the payer signature. If validation later fails (e.g., bad signature), the code already recorded the envelope as received and updated the last-seen sequence metric, leading to inconsistent metrics and misleading monitoring. Move metrics emission after all validations succeed, or record separate metrics for rejected envelopes without incrementing received counts. [ Low confidence ]originatorStream.validateEnvelope, the sequence ID is logged viautils.SequenceIDField(int64(env.OriginatorSequenceID())). Casting auint64toint64can overflow for values greater thanmath.MaxInt64, producing an incorrect negative number and misleading logs. Usezap.Uint64or changeutils.SequenceIDFieldto accept unsigned values, or validate the range before casting. [ Low confidence ]originatorStream.validateEnvelopecallsenv.UnsignedOriginatorEnvelope.PayerEnvelope.RecoverSigner()without verifying thatPayerEnvelope.protois non-nil. TheRecoverSignermethod dereferencesp.proto.PayerSignature; ifp.protois nil (e.g., due to a malformedUnsignedOriginatorEnvelope), this will panic. Add a nil check onPayerEnvelope.protobefore callingRecoverSigner, or ensureNewUnsignedOriginatorEnvelopeFromBytesguaranteesPayerEnvelope.protois non-nil for successfully parsed envelopes. [ Low confidence ]pkg/sync/sync_worker.go — 0 comments posted, 5 evaluated, 5 filtered
subscribeToRegistryreads from the channel returned bys.nodeRegistry.OnNewNodes()without checking for a nil channel. If an implementation ofNodeRegistryreturns a nil channel,case newNodes, ok := <-newNodesChwill permanently block (except for thectx.Done()case) and the goroutine will hang, preventing the worker from reacting to new nodes and causing a hidden liveness issue. [ Low confidence ]s.subscriptionsis written to without any visible initialization. Ats.subscriptions[nodeid] = struct{}{}a nil map will cause a runtime panic:assignment to entry in nil map. There is no guard in this function ensurings.subscriptionsis non-nil before use. [ Low confidence ]subscribeToNodecontains aselectwith adefaultbranch that immediately creates a new notifier context and callssubscribeToNodeRegistrationin a tight loop with no blocking or backoff. This results in a busy-spin that can consume CPU, repeatedly registering cancel functions viachangeListener.RegisterCancelFunction(notifierCancel)and repeatedly initiating subscriptions. It also rapidly creates manycontext.WithCancelcontexts that may not be cancelled promptly, causing resource leaks. This violates at-most-once callback and re-entrancy safeguards (multiple cancel functions registered), and can lead to multiple overlapping registrations/subscriptions and flood the downstream sink with work. The problematic code is thedefaultbranch executing continuously whenctxis not done. [ Low confidence ]subscribeToNodeRegistration’soperationcleanup,stream.stream.CloseSend()is called in adefereven thoughSubscribeEnvelopesalready callsCloseSend()immediately after sending the request. This results in a secondCloseSend()invocation on the same client stream. While the error return is ignored, double-closing the send side is a double-application of an effect and can lead to unexpected errors or warnings from the transport. The cleanup should avoid re-closing the send side when it has already been closed, or guard the call to only run when it’s still open. [ Invalidated by documentation search ]setupStreambuilds a singlecursor(c) from the last matching row inresult, even whenoriginatorNodeIDscontains multiple IDs (e.g., during migration). The loop assignscrepeatedly for each matching originator, resulting in the final value overwriting previous ones. This collapses per-originator state into a single cursor, which can cause incorrect downstream validation/ordering for envelopes from different originator IDs because only the last originator’s sequence/timestamp is retained. The correct behavior would be to maintain per-originator cursor state (e.g., a map keyed by originator ID) or otherwise ensure that validation/ordering is performed with the right per-originator reference. [ Low confidence ]pkg/utils/log.go — 0 comments posted, 1 evaluated, 1 filtered
PayerReportContractLoggerName(line 53) andPayerReportMainLoggerName(line 82) are both set to the same string value"payer-report". If these constants are used to derive child loggers (e.g., vialogger.Named(...)) for conceptually distinct components, the identical category names will collide. This can cause logs from different subsystems to be interleaved under the same logger, break per-component filtering/routing, skew metrics by aggregating unrelated events, and potentially override per-logger fields/handlers depending on the logging framework. Use distinct values (e.g.,"payer-report-contract"and"payer-report"or"payer-report-main") to preserve uniqueness and avoid unintended cross-component coupling. [ Low confidence ]