Skip to content
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

Make CommonTx have TransactionMisc as pointer #9977

Closed

Conversation

ImTei
Copy link

@ImTei ImTei commented Apr 18, 2024

This is a follow-up of the previous PR: #9667

As described in the previous PR, we must not copy atomic.Value, but TransactionMisc has atomic.Value, and it is implicitly copied in such codes (like #9667 (comment)).

So I made CommonTx have TransactionMisc as a pointer to prevent implicit copy.
And added store/load methods for atomic.Value to prevent nil pointer error at the initial time.

The concern about this change is there could be two TX objects which are sharing a same TransactionMisc pointer. This could make performance improvement(because cache is preserved), but may make bugs. I wanna ask your opinion. Thanks!

Add store & load methods for atomic.Values to prevent nil pointer error
@yperbasis
Copy link
Member

W/o this PR, are the implicit copies of TransactionMisc theoretical or do you have concrete examples?

@ImTei
Copy link
Author

ImTei commented Apr 26, 2024

@yperbasis This issue was encountered when we were developing op-erigon.
We were trying to add a rollup-related field to TransactionMisc, but the linter said it must not be copied. See the following CI logs:

This CI error occurs because of atomic.Pointer, which is not in the upstream erigon, but atomic.Value is also not allowed to be copied. I have no idea why golang linter cannot catch the copy of atomic.Value, it seems to be an issue of golang linter. Anyway you can see the implicit copies in the CI logs.

This CI error was fixed after this PR is applied (testinprod-io#1)

@yperbasis yperbasis added the imp2 Medium importance label Apr 29, 2024
@yperbasis yperbasis changed the base branch from release/2.60 to main May 1, 2024 07:18
@ImTei
Copy link
Author

ImTei commented Jun 17, 2024

@yperbasis @somnathb1 Hi team, could you please let me know when it might be reviewed?

func (ct *CommonTx) StoreFrom(val any) {
ct.initializeMisc()
ct.from.Store(val)
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Shouldn't the receivers be for TransactionMisc instead

Copy link
Author

Choose a reason for hiding this comment

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

If then, we can't wrap initializeMisc()

@@ -455,13 +455,13 @@ func (tx *AccessListTx) FakeSign(address libcommon.Address) (Transaction, error)
cpy.R.Set(u256.Num1)
cpy.S.Set(u256.Num1)
cpy.V.Set(u256.Num4)
cpy.from.Store(address)
cpy.StoreFrom(address)
Copy link
Contributor

Choose a reason for hiding this comment

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

Rather than wrapping, checking nil should be a part of the accessing code

Copy link
Author

Choose a reason for hiding this comment

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

So you prefer like this?

if cpy.TransactionMisc == nil {
	cpy.TransactionMisc = &TransactionMisc{}
}
cpy.from.Store(address)

I think it's easy to make nil pointer errors if developer forget to check nil. So I wrap store/load methods like this. Can you tell me why you prefer manual nil check?

Copy link
Contributor

Choose a reason for hiding this comment

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

Because it's never intended to be used with a nil, and if the developer forgets to check nil, it must be a bug before that point

Copy link
Author

@ImTei ImTei Jun 19, 2024

Choose a reason for hiding this comment

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

@somnathb1 Got it. I have some questions:

  1. Are you talking about only this method(FakeSign)? if so, I agree that it's never called with nil TransactionMisc because it's initialized in copy().
  2. Or are you talking about every code using the new Load/Store methods in this PR?

I made these new Load/Store methods because I changed the TransactionMisc in TX structs to a pointer, so TransactionMisc won't be initialized automatically when TX instances are initialized. Actually, I saw the nil pointer error before I made these methods.

As you know, TransactionMisc is used as cache in the current code, so I believe calling load/store methods before creating it is possible.
What do you think? Please let me know if I'm missing something!

Copy link
Contributor

Choose a reason for hiding this comment

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

All code, in general.
I think, though, that making TransactionMisc a pointer isn't the right way to go. It should rather be that all places that make use of "creating" a xyz_Tx object should do it with a store() call. Thus, this PR, I don't fully agree with

Copy link
Author

Choose a reason for hiding this comment

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

@somnathb1 May I ask you why you don't think making TransactionMisc as a pointer is the right way?

@yperbasis
Copy link
Member

Superseded by PR #11512

@yperbasis yperbasis closed this Aug 7, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
imp2 Medium importance
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants