forked from cerc-io/laconicd-deprecated
evm: use stack of contexts to implement snapshot revert (#399)
* 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 <31522760+fedekunze@users.noreply.github.com> Update x/evm/keeper/context_stack.go Co-authored-by: Federico Kunze Küllmer <31522760+fedekunze@users.noreply.github.com> Update x/evm/keeper/context_stack.go Co-authored-by: Federico Kunze Küllmer <31522760+fedekunze@users.noreply.github.com> 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 <31522760+fedekunze@users.noreply.github.com> 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 <31522760+fedekunze@users.noreply.github.com>
This commit is contained in:
co-authored by
Federico Kunze Küllmer
parent
96328453e5
commit
9227e78c79
@@ -0,0 +1,44 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
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 TestRevert {
|
||||
State state;
|
||||
uint256 b = 0;
|
||||
uint256 c = 0;
|
||||
constructor() {
|
||||
state = new State();
|
||||
}
|
||||
function try_set(uint256 input) public {
|
||||
b = input;
|
||||
try state.set(input) {
|
||||
} catch (bytes memory) {
|
||||
}
|
||||
c = input;
|
||||
}
|
||||
function set(uint256 input) public {
|
||||
state.force_set(input);
|
||||
}
|
||||
function query_a() public view returns(uint256) {
|
||||
return state.query();
|
||||
}
|
||||
function query_b() public view returns(uint256) {
|
||||
return b;
|
||||
}
|
||||
function query_c() public view returns(uint256) {
|
||||
return c;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity >=0.8.0;
|
||||
|
||||
contract Migrations {
|
||||
address public owner = msg.sender;
|
||||
uint public last_completed_migration;
|
||||
|
||||
modifier restricted() {
|
||||
require(
|
||||
msg.sender == owner,
|
||||
"This function is restricted to the contract's owner"
|
||||
);
|
||||
_;
|
||||
}
|
||||
|
||||
function setCompleted(uint completed) public restricted {
|
||||
last_completed_migration = completed;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
const Migrations = artifacts.require("Migrations");
|
||||
|
||||
module.exports = function (deployer) {
|
||||
deployer.deploy(Migrations);
|
||||
};
|
||||
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"name": "exception",
|
||||
"version": "1.0.0",
|
||||
"author": "huangyi <huang@crypto.com>",
|
||||
"license": "GPL-3.0-or-later",
|
||||
"scripts": {
|
||||
"test-ganache": "yarn truffle test",
|
||||
"test-ethermint": "yarn truffle test --network ethermint"
|
||||
},
|
||||
"devDependencies": {
|
||||
"truffle": "^5.1.42",
|
||||
"truffle-assertions": "^0.9.2",
|
||||
"web3": "^1.2.11"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
const TestRevert = artifacts.require("TestRevert")
|
||||
const truffleAssert = require('truffle-assertions');
|
||||
|
||||
async function expectRevert(promise) {
|
||||
try {
|
||||
await promise;
|
||||
} catch (error) {
|
||||
if (error.message.indexOf('revert') === -1) {
|
||||
expect('revert').to.equal(error.message, 'Wrong kind of exception received');
|
||||
}
|
||||
return;
|
||||
}
|
||||
expect.fail('Expected an exception but none was received');
|
||||
}
|
||||
|
||||
contract('TestRevert', (accounts) => {
|
||||
let revert
|
||||
|
||||
beforeEach(async () => {
|
||||
revert = await TestRevert.new()
|
||||
})
|
||||
it('should revert', async () => {
|
||||
await revert.try_set(10)
|
||||
no = await revert.query_a()
|
||||
assert.equal(no, '0', 'The modification on a should be reverted')
|
||||
no = await revert.query_b()
|
||||
assert.equal(no, '10', 'The modification on b should not be reverted')
|
||||
no = await revert.query_c()
|
||||
assert.equal(no, '10', 'The modification on c should not be reverted')
|
||||
|
||||
await revert.set(10)
|
||||
no = await revert.query_a()
|
||||
assert.equal(no, '10', 'The force set should not be reverted')
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,17 @@
|
||||
module.exports = {
|
||||
networks: {
|
||||
// Development network is just left as truffle's default settings
|
||||
ethermint: {
|
||||
host: "127.0.0.1", // Localhost (default: none)
|
||||
port: 8545, // Standard Ethereum port (default: none)
|
||||
network_id: "*", // Any network (default: none)
|
||||
gas: 5000000, // Gas sent with each transaction
|
||||
gasPrice: 1000000000, // 1 gwei (in wei)
|
||||
},
|
||||
},
|
||||
compilers: {
|
||||
solc: {
|
||||
version: "0.8.6",
|
||||
},
|
||||
},
|
||||
}
|
||||
Reference in New Issue
Block a user