Skip to content

Commit

Permalink
Do not error on state change for transient objects (#229)
Browse files Browse the repository at this point in the history
  • Loading branch information
ferranbt authored Mar 28, 2024
1 parent 858b058 commit cc42af4
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 3 deletions.
13 changes: 11 additions & 2 deletions internal/ethapi/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -1948,14 +1948,21 @@ func (s *TransactionAPI) SendRawTransaction(ctx context.Context, input hexutil.B
}

type mevmStateLogger struct {
suappAddr common.Address
hasStoredState bool
}

func (m *mevmStateLogger) CaptureStart(env *vm.EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) {
}

func (m *mevmStateLogger) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, rData []byte, depth int, err error) {
if op == vm.SSTORE {
if op == vm.SSTORE && scope.Contract.Address() == m.suappAddr {
// Modify the state storage is a nil operation in a Suapp, since the changes are not synced up with the
// consensus state. It is confusing an a bad UX for users that modify the state and nothing happens.
// Thus, we capture the state storage modification and return an error.
// However, we do leverage this volatile state to create temporal Contracts that act as Objects in the traditional sense.
// Only valid during the scope of the Confidential request. Thus, we need to differentiate between the two state changes:
// the ones performed on the Suapp itself (confusing for users) and the ones performed on temporal Contracts.
m.hasStoredState = true
}
}
Expand Down Expand Up @@ -1995,7 +2002,9 @@ func runMEVM(ctx context.Context, b Backend, state *state.StateDB, header *types
return nil, nil, nil, err
}

storageAccessTracer := &mevmStateLogger{}
storageAccessTracer := &mevmStateLogger{
suappAddr: *msg.To,
}

blockCtx := core.NewEVMBlockContext(header, NewChainContext(ctx, b), nil)
suaveCtx := b.SuaveContext(tx, confidentialRequest)
Expand Down
6 changes: 5 additions & 1 deletion suave/e2e/workflow_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1168,9 +1168,13 @@ func TestE2EOnChainStateTransition(t *testing.T) {
contractAddr := common.Address{0x3}
sourceContract := sdk.GetContract(contractAddr, exampleCallSourceContract.Abi, clt)

// a confidential request cannot make a state change
// a confidential request cannot make a state change in the Suapp
_, err := sourceContract.SendTransaction("ilegalStateTransition", []interface{}{}, nil)
require.Error(t, err)

// a confidential request can create a new "temporal" contract and change the state there
_, err = sourceContract.SendTransaction("offchainCreateNewContract", []interface{}{}, nil)
require.NoError(t, err)
}

func TestE2EConsoleLog(t *testing.T) {
Expand Down
14 changes: 14 additions & 0 deletions suave/sol/standard_peekers/example.sol
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,20 @@ contract ExampleEthCallSource {
function offchain() public pure returns (bytes memory) {
return abi.encodeWithSelector(this.onchain.selector);
}

function offchainCreateNewContract() public returns (bytes memory) {
Other o = new Other();
o.setValue(10);
return abi.encodeWithSelector(this.onchain.selector);
}
}

contract Other {
uint256 value;

function setValue(uint256 _value) public {
value = _value;
}
}

contract ExampleEthCallTarget {
Expand Down

0 comments on commit cc42af4

Please sign in to comment.