-
Notifications
You must be signed in to change notification settings - Fork 20.7k
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
core/types: add method to compute transaction intrinsic gas #31109
base: master
Are you sure you want to change the base?
core/types: add method to compute transaction intrinsic gas #31109
Conversation
Please use this method to prevent potential future expansion of the |
core/types/transaction.go
Outdated
if byt != 0 { | ||
nz++ | ||
} | ||
} |
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.
While you're at it, you might as well change the loop to:
z := uint64(bytes.Count(data, []byte{0}))
nz := uint64(len(data)) - z
bytes.Count() uses an optimized assembly implementation to count bytes.
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.
+1
Hi @rjl493456442. Please, can you give me more details on what you mean? |
He means the function |
Okay. I will push the changes. |
Hi @rjl493456442 Can you review the these changes please? |
core/bench_test.go
Outdated
Data: data, | ||
GasPrice: gasPrice, | ||
}) | ||
gas, _ := tx0.IntrinsicGas(&rules) |
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.
Repeating the tx construction here is not great, and hightlights a shortcoming of having IntrinsicGas
as a method of Transaction
: you can't compute the intrinsic gas without creating the tx first, but it's often called to fill in the Gas
of a new transaction. We need to think a bit harder how to solve this one. I have a hunch IntrinsicGas
could be defined over types.TxData
. But then we'd need to implement TxData
in Transaction
.
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 think TxData is already in Transaction as the inner field.
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.
OK, I've figured it out. What we need to do is, add a function IntrinsicGas(TxData, *params.Rules)
to core/types
. Keep the IntrinsicGas
method on Transaction
, and make it call this new function on tx.inner
.
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.
OK. I wonder if the IntrinsicGas
function could not have this signature instead: func (data []byte, accessList types.AccessList, authList []types.SetCodeAuthorization, isContractCreation, rules *params.Rules) (uint64, error)
.
It allows to pass fields in tx.inner
instead of tx.inner
, we can then do without a variable of type TxData
if necessary. However, review the modifications please.
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.
Left a few comments. Need to decide how to pass the txdata in state_transition.
Please rebase also when you can.
core/state_transition.go
Outdated
Gas: msg.GasLimit, | ||
Data: msg.Data, | ||
GasPrice: msg.GasPrice, | ||
}) |
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 think this isn't great.
By going tx -> msg -> back to tx we require ourselves to convert to msg correct and back correctly. TxData
seems like the right thing to feed IntrinsicGas
, but forcing stuff into a legacy tx when we don't exactly know the origin (or it isn't defined) isn't correct.
This currently fails to compute the intrinsic gas correctly for SetCode
txs, because when converting from msg to a tx, the conversion is for a tx that does not have authorizations. Since SetCode
seems like a perfect superset of all possible values which goes into InstrinsicGas
, but if a new tx type comes along without auths and needs a new input to the IntrinsicGas
computation, we'll have the same problem again.
Seems like there are two paths here:
-
add new struct like
GenericTxData
that implementsTxData
and use this in places where we don't know the tx type -
add a new method on
Message
that infers the tx type and constructs the correctTxData
-
is probably less code, but adds a weird export. 2) is more code, but still has the problem occasionally in other places outside
core
like tests where we want to generically compute some intrinsic gas.
I think I lean towards 1) ?
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.
Thanks for the review. I understand the problems posed. I'm going to look into the new GenericTxData
structure. But I would also like to know if we should then put the IntrinsicGas
method on TxData
or leave it on Transaction
.
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 think it should be on Transaction
like you have it.
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 also think we can have it on both Transaction and as a standalone function.
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.
Ahh, wait, I see the issue now. So we would need to implement TxData with Message somehow, but that's not possible because it's supposed to be a private interface. One thing we could do is making the intrinsic gas a part of Message as a field. Then we'd compute it earlier, like in ApplyTransaction. Just unsure how much of a ripple effect this has on other code.
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.
Right. I kinda like this idea of precomputing earlier though.
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.
It will then remove the need for GenericTxData
struct.
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.
Hello @fjl @lightclient. The effect is that the gas must be computed in Message
before calling ApplyMessage
wherever it is executed. Not just at the ApplyTransaction
level. A method SetGas(tx types.TxData, rules *params.Rules)
for Message
can be useful for that.
core/types/transaction.go
Outdated
if byt != 0 { | ||
nz++ | ||
} | ||
} |
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.
+1
core/types/transaction.go
Outdated
data = txdata.data() | ||
accessList = txdata.accessList() | ||
authList = txdata.setCodeAuthorizations() |
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 think these can be removed and use the txdata
getter directly
97a96f3
to
ac10896
Compare
@cedrickah You force-pushed over my commit. Git must have warned about un-synced commits which you probably ignored. Please double check before force pushing. I have now pushed it again. It fixes the TransactionTest in Btw after the latest refactor now many more tests are failing. Please look into them. You can see them on appveyor: https://ci.appveyor.com/project/ethereum/go-ethereum/builds/51553192 (it started another run now so wait a bit). |
Ooh sorry. I'll be more careful. I'm leaning towards |
Hello @s1na . I saw the logs. As we are trying to computer gas in |
f7c61f9
to
16e7133
Compare
I moved the computation of the intrinsic gas from There are some places in the code base like the RPC and some tests where there is the concept of untyped "generic" transaction. I considered adding an intrinsic gas calculator where the caller can directly pass in the relevant fields like |
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.
Pushed some changes, LGTM.
Will wait for @fjl to approve this since I know he cares about API implications of this PR. |
The effect of pre-computation was quite significant, I felt it was necessary to get your opinion on some points on the best approach for you to avoid situations where the caller forgets to set the |
eth/tracers/api.go
Outdated
@@ -269,10 +269,11 @@ func (api *API) traceChain(start, end *types.Block, config *TraceConfig, closed | |||
var ( | |||
signer = types.MakeSigner(api.backend.ChainConfig(), task.block.Number(), task.block.Time()) | |||
blockCtx = core.NewEVMBlockContext(task.block.Header(), api.chainContext(ctx), nil) | |||
rules = api.backend.ChainConfig().Rules(task.block.Number(), task.block.Difficulty().BitLen() == 0, task.block.Time()) |
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 think we should do something like this. Everywhere else in the codebase we use random != nil to determine the post-merge blocks
rules = api.backend.ChainConfig().Rules(task.block.Number(), task.block.Difficulty().BitLen() == 0, task.block.Time()) | |
rules = api.backend.ChainConfig().Rules(blockCtx.BlockNumber, blockCtx.Random != nil, blockCtx.Time) |
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 think we can change to Random != nil
where it makes sense, but there are some cases where it is not easy to e.g. traceBlockParallel
where the block context is not safe for concurrent access and gets redefined each iteration. Yeah we can usually construct a block context that is only used for this purpose, but under the hood it also is just checking if Difficultly is zero under the hood.
Maybe it makes sense to create another function RulesFromHeader
or a helper IsPostMerge
. But I think creating block contexts just to check if it is post merge is unnecessary.
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.
You can see that we do check Difficulty.Sign() != 0
in a few places already with:
grep -r "Difficulty\.Sign" .
eth/tracers/api.go
Outdated
@@ -652,6 +657,7 @@ func (api *API) traceBlockParallel(ctx context.Context, block *types.Block, stat | |||
signer = types.MakeSigner(api.backend.ChainConfig(), block.Number(), block.Time()) | |||
results = make([]*txTraceResult, len(txs)) | |||
pend sync.WaitGroup | |||
rules = api.backend.ChainConfig().Rules(block.Number(), block.Difficulty().BitLen() == 0, block.Time()) |
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.
Same here, we should stay consistent and use blockCtx.Random != nil (and move blockCtx up here)
eth/tracers/api.go
Outdated
@@ -883,7 +892,8 @@ func (api *API) TraceTransaction(ctx context.Context, hash common.Hash, config * | |||
return nil, err | |||
} | |||
defer release() | |||
msg, err := core.TransactionToMessage(tx, types.MakeSigner(api.backend.ChainConfig(), block.Number(), block.Time()), block.BaseFee()) | |||
rules := api.backend.ChainConfig().Rules(block.Number(), block.Difficulty().BitLen() == 0, block.Time()) |
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.
here we can use vmctx.Random != nil
eth/tracers/api.go
Outdated
@@ -962,7 +972,8 @@ func (api *API) TraceCall(ctx context.Context, args ethapi.TransactionArgs, bloc | |||
return nil, err | |||
} | |||
var ( | |||
msg = args.ToMessage(vmctx.BaseFee, true, true) | |||
rules = api.backend.ChainConfig().Rules(block.Number(), block.Difficulty().BitLen() == 0, block.Time()) |
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.
Here vmctx.Random != nil
internal/ethapi/api.go
Outdated
@@ -693,7 +693,8 @@ func applyMessage(ctx context.Context, b Backend, args TransactionArgs, state *s | |||
if err := args.CallDefaults(gp.Gas(), blockContext.BaseFee, b.ChainConfig().ChainID); err != nil { | |||
return nil, err | |||
} | |||
msg := args.ToMessage(header.BaseFee, skipChecks, skipChecks) | |||
rules := b.ChainConfig().Rules(header.Number, header.Difficulty.BitLen() == 0, header.Time) |
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.
blockContext.Random != nil
internal/ethapi/api.go
Outdated
@@ -837,7 +838,8 @@ func DoEstimateGas(ctx context.Context, b Backend, args TransactionArgs, blockNr | |||
if err := args.CallDefaults(gasCap, header.BaseFee, b.ChainConfig().ChainID); err != nil { | |||
return 0, err | |||
} | |||
call := args.ToMessage(header.BaseFee, true, true) | |||
rules := b.ChainConfig().Rules(header.Number, header.Difficulty.BitLen() == 0, header.Time) |
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.
Maybe something like
evmContext = core.NewEVMBlockContext(opts.Header, opts.Chain, nil)
rules := b.ChainConfig().Rules(header.Number, evmContext.Random != nil, header.Time=
```
…ated computation bytes count algo
bd93294
to
0f28070
Compare
rebased |
Resolves: #31058
Added an
IntrinsicGas()
method incore/types
to compute transaction intrinsic gas.