Skip to content
This repository has been archived by the owner on Apr 4, 2024. It is now read-only.

state is not reverted when exception get recovered in smart contract #338

Closed
yihuang opened this issue Jul 21, 2021 · 5 comments · Fixed by #399
Closed

state is not reverted when exception get recovered in smart contract #338

yihuang opened this issue Jul 21, 2021 · 5 comments · Fixed by #399
Assignees

Comments

@yihuang
Copy link
Contributor

yihuang commented Jul 21, 2021

System info: ethermint main branch

Steps to reproduce:

Since we don't implement StateDB's Snapshot and RevertToSnapshot methods, which are critical for exception implementation in evm.

Expected behavior: exception should undo all changes made to the state in the current call

Actual behavior: I'm afraid state is not reverted when exception raised and caught
Additional info:

@yihuang yihuang changed the title smart contract can't do exception recovering state is not reverted when exception get caught in smart contract Jul 21, 2021
@yihuang
Copy link
Contributor Author

yihuang commented Jul 22, 2021

just confirmed with this test case:

// SPDX-License-Identifier: MIT-Modern-Variant
pragma solidity >=0.8.0;

contract State {
    uint256 a = 0;
    function set(uint256 input) public { 
        a = input; 
        require(a < 10);
    }
    function force_set(uint256 input) public { 
        a = input; 
    }
    function query() public view returns(uint256) {
        return a;
    }
}

contract Consumer {
    State state;
    constructor() {
        state = new State();
    }
    function try_set(uint256 input) public {
        try state.set(input) {
        } catch (bytes memory) {
        }
    }
    function set(uint256 input) public {
        state.force_set(input);
    }
    function query() public view returns(uint256) { 
        return state.query();
    }
}

In geth, the call consumer.try_set(10) succeed, but consumer.query() is 0.
but in ethermint, consumer.query() is 10.

@yihuang yihuang changed the title state is not reverted when exception get caught in smart contract state is not reverted when exception get recovered in smart contract Jul 22, 2021
@fedekunze
Copy link
Contributor

fedekunze commented Jul 23, 2021

can you create a solidity test for the revert logic? I can work on the fix

@fedekunze fedekunze self-assigned this Jul 23, 2021
@fedekunze
Copy link
Contributor

fedekunze commented Jul 23, 2021

the EVM Call and Create both end with RevertToSnapshot when there is a vmError

func (evm *EVM) EvmFunc {
	// core logic
	if err != nil {
		evm.StateDB.RevertToSnapshot(snapshot)
		if err != ErrExecutionReverted {
			gas = 0
		}
	}
	return ret, gas, err

but then we don't commit the changes unless the state transition is successful:

func (k *Keeper) ApplyTransaction(tx *ethtypes.Transaction) (*types.MsgEthereumTxResponse, error) {
	// ...
	cacheCtx, commit := k.ctx.CacheContext()
	
	// ...
	// pass false to execute in real mode, which do actual gas refunding
	res, err := k.ApplyMessage(evm, msg, ethCfg, false)
	if err != nil {
		return nil, stacktrace.Propagate(err, "failed to apply ethereum core message")
	}

	txHash := tx.Hash()
	res.Hash = txHash.Hex()
	logs := k.GetTxLogs(txHash)

	// Commit and switch to original context
	if !res.Failed() {
		commit()
	}
	
	// ...

we should investigate why the state is getting persisted regardless of this condition

@yihuang
Copy link
Contributor Author

yihuang commented Jul 24, 2021

The thing is the Consumer.try_set don't result in a vm error, because the internal error is caught and recovered, but the sub call should be reverted while the tx itself not.

@yihuang
Copy link
Contributor Author

yihuang commented Jul 24, 2021

Added the test case in the PR, it currently fail with ethermint, while success with ganache

yihuang referenced this issue in yihuang/ethermint Aug 10, 2021
Closes #338

add exception revert test case

verify partial revert

mutate state after the reverted subcall

polish

update comments

name the module after the type name

remove the unnecessary Snapshot in outer layer

and add snapshot unit test

assert context stack is clean after tx processing

cleanups

fix context revert

fix comments

update comments

it's ok to commit in failed case too

Update x/evm/keeper/context_stack.go

Co-authored-by: Federico Kunze Küllmer <[email protected]>

Update x/evm/keeper/context_stack.go

Co-authored-by: Federico Kunze Küllmer <[email protected]>

Update x/evm/keeper/context_stack.go

Co-authored-by: Federico Kunze Küllmer <[email protected]>

update comment and error message

add comment to cacheContext

k -> cs

Update x/evm/keeper/context_stack.go

Co-authored-by: Federico Kunze Küllmer <[email protected]>

evm can handle state revert

renames and unit tests
fedekunze added a commit that referenced this issue Aug 10, 2021
* use stack of contexts to implement snapshot revert

Closes #338

add exception revert test case

verify partial revert

mutate state after the reverted subcall

polish

update comments

name the module after the type name

remove the unnecessary Snapshot in outer layer

and add snapshot unit test

assert context stack is clean after tx processing

cleanups

fix context revert

fix comments

update comments

it's ok to commit in failed case too

Update x/evm/keeper/context_stack.go

Co-authored-by: Federico Kunze Küllmer <[email protected]>

Update x/evm/keeper/context_stack.go

Co-authored-by: Federico Kunze Küllmer <[email protected]>

Update x/evm/keeper/context_stack.go

Co-authored-by: Federico Kunze Küllmer <[email protected]>

update comment and error message

add comment to cacheContext

k -> cs

Update x/evm/keeper/context_stack.go

Co-authored-by: Federico Kunze Küllmer <[email protected]>

evm can handle state revert

renames and unit tests

* use table driven tests

* keep all the cosmos events

* changelog

* check for if commit function is nil

* fix changelog

* Update x/evm/keeper/context_stack.go

Co-authored-by: Federico Kunze Küllmer <[email protected]>
mmsqe added a commit to mmsqe/ethermint that referenced this issue Sep 9, 2023
* Problem: native action don't support events

Solution:
- manage the events and reverts

* Update x/evm/statedb/statedb.go

Signed-off-by: yihuang <[email protected]>

* gofumpt

* fix nil pointer

* Update x/evm/statedb/statedb.go

Co-authored-by: mmsqe <[email protected]>
Signed-off-by: yihuang <[email protected]>

* fix unit test

---------

Signed-off-by: yihuang <[email protected]>
Co-authored-by: mmsqe <[email protected]>
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants