Skip to content

Conversation

@speeddragon
Copy link

@speeddragon speeddragon commented Jan 13, 2026

We discovered an issue where the message was fetching data from cache 3 times during a call to a transaction ID.

Example: curl http://localhost:8734/ICC8rNh2ziKUDQHK7wnoaxtO0KNKYuW1dCwZc8B9e4g was accessed 2 more times than usual to the cache in hb_http:reply function because the message handed from dev_meta to hb_http:reply didn't contain the results fetched from cache.

Message was first loaded inside do_normalize_message call by dev_message:commit, which calls hb_message:convert and then hb_link:normalize, which loads the information in the cache.

In some cases, loading can be avoided by providing the header bundle: false, but this wasn't a solution here.

This is a list of the time spent in some function while processing the request.

sent, status: 200, duration: 23955, method: GET, path: /ICC8rNh2ziKUDQHK7wnoaxtO0KNKYuW1dCwZc8B9e4g, body_size: 570206867
-- store_read, path: ICC8r..B9e4g, duration: 595
-- store_read, path: ICC8r..B9e4g/data, duration: 6101
-- http_reply: duration: 15599
---- reply_handle_cookies: duration: 6710
------ store_read, path: ICC8r..B9e4g/data, duration: 6677
---- encode_reply: duration: 8883
------ store_read, path: ICC8r..B9e4g/data, duration: 5490

Improvement
http_reply: duration: 2703 (now) vs http_reply: duration: 15207 (previously).

case {UnsignedCommitments, SignedCommitments} of
{[], _} ->
{ok, #{ <<"commitments">> := NewCommitments }} =
{ok, #{ <<"commitments">> := NewCommitments } = LoadedMsg} =
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By discarding this LoadedMsg, we discarded the loaded values from the cache. Msg value didn't contain the full values, and was used to attach merged commitments.

_ -> {undefined, #{}}
end,
{ok, #{ <<"commitments">> := NormCommitments }} =
{ok, #{ <<"commitments">> := NormCommitments } = LoadedMsg} =
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changes under the verify made sense initially, but this breaks the dev_lua and dev_lua_test tests. The verify mode is called on dev_lua:decode and do_normalize_commitments fast mode.

speeddragon and others added 3 commits January 16, 2026 15:18
…fied

- Add `contains_links/1` helper to detect if a message contains lazy links
- Modify `do_normalize_commitments/3` to preserve the original message
  when it doesn't contain links, avoiding redundant loading operations
- Use the original Msg instead of LoadedMsg when appropriate to maintain
  data integrity and prevent multiple reloads
- Update test to reflect that cached values should not become links
  after reading (renamed to `encode_message_with_cache_values_test`)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
?assertEqual(dev_codec_flat:from(Lifted, #{}, #{}), {ok, Map}),
ok.

encode_message_with_links_test() ->
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure of the use case for this test. Is there a behaviour where we expect a message that fetches data from cache always to return a linkify version, or should we always expect the values loaded from cache to be returned downwards, so we can avoid loading them again?

Comment on lines +260 to +265
case {IsMsgLinked, IsLoadedMsgLinked} of
{true, false} ->
LoadedMsg#{ <<"commitments">> => MergedCommitments };
_ ->
Msg#{ <<"commitments">> => MergedCommitments }
end;
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Initially, I was using LoadedMsg to return instead of Msg. This works for the use case of fetching an ID, but it breaks in the hb_cache match linked message test, because now the expected value is a linkify version, but the value itself isn't.

We can see the expected value as following:

#{<<"a">>=>#{<<"b">>=><<"c">>,<<"commitments">>=>#{<<"WnTWQDw6An5hmZioVWeN1C1xvYCxyrshVPBoBZvMCUU">>=>#{<<"commitment-device">>=><<"httpsig@1.0">>,<<"committed">>=>[<<"b">>,<<"d">>],<<"keyid">>=><<"constant:ao">>,<<"signature">>=><<"WnTWQDw6An5hmZioVWeN1C1xvYCxyrshVPBoBZvMCUU">>,<<"type">>=><<"hmac-sha256">>}},<<"d">>=><<"e">>}}

And the loaded value (the one returned) as:

#{<<"a+link">>=><<"WnTWQDw6An5hmZioVWeN1C1xvYCxyrshVPBoBZvMCUU">>}

I'm not sure if the test is wrong and we should always return the LoadedMsg, or we should check which one is the linkify version and return the other one.

@speeddragon speeddragon marked this pull request as ready for review January 16, 2026 17:31
@speeddragon speeddragon changed the title Fix multiple reloaded msg Fix multiple cache loading message Jan 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants