-
Notifications
You must be signed in to change notification settings - Fork 20.1k
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/vm: avoid memory expansion check for trivial ops #24048
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,6 +17,8 @@ | |
package vm | ||
|
||
import ( | ||
"fmt" | ||
|
||
"github.com/ethereum/go-ethereum/params" | ||
) | ||
|
||
|
@@ -57,21 +59,39 @@ var ( | |
// JumpTable contains the EVM opcodes supported at a given fork. | ||
type JumpTable [256]*operation | ||
|
||
func validate(jt JumpTable) JumpTable { | ||
s1na marked this conversation as resolved.
Show resolved
Hide resolved
|
||
for i, op := range jt { | ||
if op == nil { | ||
panic(fmt.Sprintf("op 0x%x is not set", i)) | ||
} | ||
// The interpreter has an assumption that if the memorySize function is | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Considering they always go together, it would be better to merge these into single function that outputs new memory size and error. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nitpick: they don't "always go together". If dynamic memory, then dynamic gas, but not always the other way around. For example the But yes, maybe something could be changed in the strucutre at a higher level. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, what I meant in this case they should return unchanged memory size or 0. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Afaik, the validate is only performed during geth bootup, when the global vars are instantiated. Unless I misunderstood something. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I agree that it can be reworked, but I don't want to do it in this PR. I think merging memory funcs and gas funcs is going to be a very large change. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Correct. But my comment was about the design. Not needing
Make sense. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am doing this refactoring in #24113 |
||
// set, then the dynamicGas function is also set. This is a somewhat | ||
// arbitrary assumption, and can be removed if we need to -- but it | ||
// allows us to avoid a condition check. As long as we have that assumption | ||
// in there, this little sanity check prevents us from merging in a | ||
// change which violates it. | ||
if op.memorySize != nil && op.dynamicGas == nil { | ||
panic(fmt.Sprintf("op %v has dynamic memory but not dynamic gas", OpCode(i).String())) | ||
} | ||
} | ||
return jt | ||
} | ||
|
||
// newLondonInstructionSet returns the frontier, homestead, byzantium, | ||
// contantinople, istanbul, petersburg, berlin and london instructions. | ||
func newLondonInstructionSet() JumpTable { | ||
instructionSet := newBerlinInstructionSet() | ||
enable3529(&instructionSet) // EIP-3529: Reduction in refunds https://eips.ethereum.org/EIPS/eip-3529 | ||
enable3198(&instructionSet) // Base fee opcode https://eips.ethereum.org/EIPS/eip-3198 | ||
return instructionSet | ||
return validate(instructionSet) | ||
} | ||
|
||
// newBerlinInstructionSet returns the frontier, homestead, byzantium, | ||
// contantinople, istanbul, petersburg and berlin instructions. | ||
func newBerlinInstructionSet() JumpTable { | ||
instructionSet := newIstanbulInstructionSet() | ||
enable2929(&instructionSet) // Access lists for trie accesses https://eips.ethereum.org/EIPS/eip-2929 | ||
return instructionSet | ||
return validate(instructionSet) | ||
} | ||
|
||
// newIstanbulInstructionSet returns the frontier, homestead, byzantium, | ||
|
@@ -83,7 +103,7 @@ func newIstanbulInstructionSet() JumpTable { | |
enable1884(&instructionSet) // Reprice reader opcodes - https://eips.ethereum.org/EIPS/eip-1884 | ||
enable2200(&instructionSet) // Net metered SSTORE - https://eips.ethereum.org/EIPS/eip-2200 | ||
|
||
return instructionSet | ||
return validate(instructionSet) | ||
} | ||
|
||
// newConstantinopleInstructionSet returns the frontier, homestead, | ||
|
@@ -122,7 +142,7 @@ func newConstantinopleInstructionSet() JumpTable { | |
maxStack: maxStack(4, 1), | ||
memorySize: memoryCreate2, | ||
} | ||
return instructionSet | ||
return validate(instructionSet) | ||
} | ||
|
||
// newByzantiumInstructionSet returns the frontier, homestead and | ||
|
@@ -158,14 +178,14 @@ func newByzantiumInstructionSet() JumpTable { | |
maxStack: maxStack(2, 0), | ||
memorySize: memoryRevert, | ||
} | ||
return instructionSet | ||
return validate(instructionSet) | ||
} | ||
|
||
// EIP 158 a.k.a Spurious Dragon | ||
func newSpuriousDragonInstructionSet() JumpTable { | ||
instructionSet := newTangerineWhistleInstructionSet() | ||
instructionSet[EXP].dynamicGas = gasExpEIP158 | ||
return instructionSet | ||
return validate(instructionSet) | ||
|
||
} | ||
|
||
|
@@ -179,7 +199,7 @@ func newTangerineWhistleInstructionSet() JumpTable { | |
instructionSet[CALL].constantGas = params.CallGasEIP150 | ||
instructionSet[CALLCODE].constantGas = params.CallGasEIP150 | ||
instructionSet[DELEGATECALL].constantGas = params.CallGasEIP150 | ||
return instructionSet | ||
return validate(instructionSet) | ||
} | ||
|
||
// newHomesteadInstructionSet returns the frontier and homestead | ||
|
@@ -194,7 +214,7 @@ func newHomesteadInstructionSet() JumpTable { | |
maxStack: maxStack(6, 1), | ||
memorySize: memoryDelegateCall, | ||
} | ||
return instructionSet | ||
return validate(instructionSet) | ||
} | ||
|
||
// newFrontierInstructionSet returns the frontier instructions | ||
|
@@ -1010,5 +1030,5 @@ func newFrontierInstructionSet() JumpTable { | |
} | ||
} | ||
|
||
return tbl | ||
return validate(tbl) | ||
} |
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.
Yesterday I started a branch to experiment with moving all the gas calculation into another function (next to the implementation): https://github.com/ipsilon/go-ethereum/tree/gas-redesign
The constant gas instructions would have the same simple function charging the constant gas, others would have the dynamic calculation + memory expansion.
I am not sure if this will help everything considered, because it will always mean an indirect call, but at the same time it reduces most of the branching in this loop.
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.
Looked briefly at the last commit there -- I think it won't work that easily.
The way the dynamic gas has evolved, we need to first ensure that the caller can cover the static cost, because for some ops, actually calculating the dynamic cost is expensive: checking the existence of things in the trie.
So we can't just calculate everything and then charge.
We can get around it by either having the "chargeGas" function not only return the gas, but actually charge it via the
contract
.Alternatively, we can pass the availableGas into the "chargeGas" function.