Skip to content
Snippets Groups Projects
Unverified Commit 83fb255e authored by smblucker's avatar smblucker Committed by Silas Davis
Browse files

WIP implementation of REVERT opcode


Signed-off-by: default avatarsmblucker <smblucker@outlook.com>
Signed-off-by: default avatarSilas Davis <silas@monax.io>
parent 0fa31e4c
No related branches found
No related tags found
No related merge requests found
......@@ -182,6 +182,7 @@ const (
DELEGATECALL
// 0x70 range - other
REVERT = 0xfd
SELFDESTRUCT = 0xff
)
......@@ -334,6 +335,7 @@ var opCodeNames = map[OpCode]string{
DELEGATECALL: "DELEGATECALL",
// 0x70 range - other
REVERT: "REVERT",
SELFDESTRUCT: "SELFDESTRUCT",
}
......
......@@ -48,6 +48,7 @@ var (
ErrDataStackUnderflow = errors.New("Data stack underflow")
ErrInvalidContract = errors.New("Invalid contract")
ErrNativeContractCodeCopy = errors.New("Tried to copy native contract code")
ErrExecutionReverted = errors.New("Execution reverted")
)
type ErrPermission struct {
......@@ -773,6 +774,10 @@ func (vm *VM) call(caller, callee acm.MutableAccount, code, input []byte, value
stack.Push(newAccount.Address().Word256())
}
if err_ == ErrExecutionReverted {
return ret, nil
}
case CALL, CALLCODE, DELEGATECALL: // 0xF1, 0xF2, 0xF4
if !HasPermission(vm.state, callee, permission.Call) {
return nil, ErrPermission{"call"}
......@@ -863,6 +868,10 @@ func (vm *VM) call(caller, callee acm.MutableAccount, code, input []byte, value
// TODO: we probably don't want to return the error - decide
//err = firstErr(err, callErr)
stack.Push(Zero256)
if callErr == ErrExecutionReverted {
memory.Write(retOffset, RightPadBytes(ret, int(retSize)))
}
} else {
stack.Push(One256)
......@@ -891,6 +900,17 @@ func (vm *VM) call(caller, callee acm.MutableAccount, code, input []byte, value
vm.Debugf(" => [%v, %v] (%d) 0x%X\n", offset, size, len(output), output)
return output, nil
case REVERT: // 0xFD
offset, size := stack.PopBigInt(), stack.PopBigInt()
output, memErr := memory.Read(offset, size)
if memErr != nil {
vm.Debugf(" => Memory err: %s", memErr)
return nil, firstErr(err, ErrMemoryOutOfBounds)
}
vm.Debugf(" => [%v, %v] (%d) 0x%X\n", offset, size, len(output), output)
return output, ErrExecutionReverted
case SELFDESTRUCT: // 0xFF
addr := stack.Pop()
if useGasNegative(gas, GasGetAccount, &err) {
......
......@@ -158,6 +158,28 @@ func TestSubcurrency(t *testing.T) {
}
}
//This test case is taken from EIP-140 (https://github.com/ethereum/EIPs/blob/master/EIPS/eip-140.md);
//it is meant to test the implementation of the REVERT opcode
func TestRevert(t *testing.T) {
ourVm := NewVM(newAppState(), DefaultDynamicMemoryProvider, newParams(), acm.ZeroAddress, nil, logger)
// Create accounts
account1 := newAccount(1)
account2 := newAccount(1, 0, 1)
var gas uint64 = 100000
bytecode := MustSplice(PUSH32, 0x72, 0x65, 0x76, 0x65, 0x72, 0x74, 0x20, 0x6D, 0x65, 0x73, 0x73, 0x61,
0x67, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, PUSH1, 0x00, MSTORE, PUSH1, 0x0E, PUSH1, 0x00, REVERT)
start := time.Now()
output, err := ourVm.Call(account1, account2, bytecode, []byte{}, 0, &gas)
assert.Error(t, err, "Expected execution reverted error")
fmt.Printf("Output: %v Error: %v\n", output, err)
fmt.Println("Call took:", time.Since(start))
}
// Test sending tokens from a contract to another account
func TestSendCall(t *testing.T) {
fakeAppState := newAppState()
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment