Repository navigation
Conversation
… fork EVM-internal CREATE used hash(txHash||origin), so every CREATE inside one transaction produced the same address. EVM.Create also accepted an existing account silently, so a factory deploying two children in one call had the second overwrite the first while the transaction still reported success. Gate the Ethereum behaviour behind ForkEVMContractCreateV2. Registered at MaxHeight (off by default, opt-in per chain) like ForkEVMTransferRevert: enabling it from genesis on an existing chain would rewrite historical execution. - CREATE address = CreateAddress(executing account, its nonce); the caller nonce is incremented before any create snapshot and persisted in contract state, so it survives across transactions and failed creates. - Newly created contracts start at nonce 1 (EIP-161); an account with a nonce is no longer treated as non-existent. - CREATE/CREATE2 fail with ErrContractAddressCollision (consuming the forwarded gas) when the target already has a nonce or code. - ErrCodeStoreOutOfGas rolls the creation back instead of keeping the account and pushing its address. - CREATE/CREATE2 forward 63/64 of the remaining gas (EIP-150); CREATE2 no longer halves it, and converts value precision for ETH-signed transactions the same way CREATE does. Address construction for the new path bypasses the chain33 address driver: a btc-format driver cannot parse a 0x hex string and produced an all-zero raw address. Fork-off execution is unchanged; the nonceChange KV write is gated on the same fork. Co-authored-by: Claude <noreply@anthropic.com>
bysomeone
force-pushed
the
feat/evm-contract-create-v2
branch
from
November 11, 2026 06:22
b121b23 to
86b4b37
Compare
Co-authored-by: Claude <noreply@anthropic.com>
withdrawTicketBalance compared the post-withdraw coins balance with the pre-withdraw ticket balance. The ticket balance also grows with mining rewards, so the check only held when it happened to be exactly 100000 and failed intermittently otherwise (observed 100005 vs 100001 on the same head). Record the coins balance before the withdraw and assert the increase is the withdrawn amount, allowing a small tolerance for fees and rounding. Co-authored-by: Claude <noreply@anthropic.com>
The withdraw moves 100000 coins minus a ~0.1 coin fee, so the expected increase is exactly 99999.9 and the previous 99999.9 lower bound sat on the floating-point boundary: the same balances can compare either side of it depending on their magnitude and on the awk implementation. Use a 99999 lower bound instead, and make jq fail on a missing balance rather than silently comparing a null as zero. Co-authored-by: Claude <noreply@anthropic.com>
ForkEVMContractCreateV2 and ForkEVMTransferRevert are independent forks, but the full Ethereum semantics need both: this fork keeps the nonce of a failed CREATE, and the transfer-revert fork rolls back the value attached to it. Add a test that enables both, and document the pairing next to the fork. Co-authored-by: Claude <noreply@anthropic.com>
Collaborator
Author
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Fixes the EVM-internal
CREATEaddress derivation described in #1351.opCreatederived the address fromhash(txHash || origin), so every internalCREATEin a transaction got the same address.EVM.Createadditionally accepted an existing account, so a second child silently overwrote the first while the transaction still reported success.How
New dapp fork
ForkEVMContractCreateV2. LikeForkEVMTransferRevert, it is registered atMaxHeight(off by default) and the templates set-1, so every chain opts in with a concrete height in its deployment configuration. Enabling it from genesis on an existing chain would rewrite historical execution. Fork-off execution is unchanged.Fork-on:
CREATEaddress =CreateAddress(executing account, its nonce). The caller nonce is incremented before any create snapshot and persisted in contract state, so it survives across transactions and failed creates.CREATE/CREATE2returnErrContractAddressCollisionand consume the forwarded gas when the target already has a nonce or code.ErrCodeStoreOutOfGasrolls the creation back instead of keeping the account and pushing its address.CREATE/CREATE2forward 63/64 of the remaining gas (EIP-150).CREATE2no longer halves the gas and converts value precision for ETH-signed transactions the same wayCREATEdoes.Address construction for the new path bypasses the chain33 address driver: a btc-format driver cannot parse a
0xhex string and produced an all-zero raw address.Testing
go test ./plugin/dapp/evm/...hash(txHash||origin)and no nonce is written to contract statecrypto.CreateAddress, twice in one transactiongo test ./plugin/dapp/evm/executor/ -shuffle=<seed>is order-independent; a pre-existing global address-driver leak fromquery_test.gowas fixed for that.Deployment note
The fork has to be enabled with a real height in the deployment repository; the templates here keep it off (
-1).ForkEVMTransferRevert. This fork keeps the nonce of a failedCREATE; only the transfer-revert fork rolls back the value attached to it, so the full Ethereum semantics need both.[exec.sub.evm] addressDriver="eth". The internal CREATE path here does not depend on the driver, but the pre-existing top-level ETH-signed deploy path still does.CREATEdoes not match Ethereum exactly; contracts deployed after the fork match exactly.