From d3b785fedb20e945d856a482f2ce78070abe77d2 Mon Sep 17 00:00:00 2001 From: Benjamin Bollen <ben@erisindustries.com> Date: Wed, 7 Sep 2016 13:00:24 +0200 Subject: [PATCH] vm: implement DELEGATECALL instruction opcode --- manager/eris-mint/evm/vm.go | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/manager/eris-mint/evm/vm.go b/manager/eris-mint/evm/vm.go index 45438f7f..cb451f34 100644 --- a/manager/eris-mint/evm/vm.go +++ b/manager/eris-mint/evm/vm.go @@ -152,11 +152,11 @@ func (vm *VM) Call(caller, callee *Account, code, input []byte, value int64, gas // while preserving the original caller to the previous callee. // Different to the normal CALL or CALLCODE, the value does not need to be transferred to the callee. func (vm *VM) DelegateCall(caller, callee *Account, code, input []byte, value int64, gas *int64) (output []byte, err error) { - + exception := new(string) // fire the post call event (including exception if applicable) defer vm.fireCallEvent(exception, &output, caller, callee, input, value, gas) - + // DelegateCall does not transfer the value to the callee. if len(code) > 0 { @@ -770,12 +770,20 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value int64, gas stack.Push(newAccount.Address) } - case CALL, CALLCODE: // 0xF1, 0xF2 + case CALL, CALLCODE, DELEGATECALL: // 0xF1, 0xF2, 0xF4 if !HasPermission(vm.appState, callee, ptypes.Call) { return nil, ErrPermission{"call"} } gasLimit := stack.Pop64() - addr, value := stack.Pop(), stack.Pop64() + addr := stack.Pop() + // NOTE: for DELEGATECALL value is preserved from the original + // caller, as such it is not stored on stack as an argument + // for DELEGATECALL and should not be popped. Instead previous + // caller value is used. for CALL and CALLCODE value is stored + // on stack and needs to be overwritten from the given value. + if op != DELEGATECALL { + value = stack.Pop64() + } inOffset, inSize := stack.Pop64(), stack.Pop64() // inputs retOffset, retSize := stack.Pop64(), stack.Pop64() // outputs dbg.Printf(" => %X\n", addr) @@ -824,6 +832,11 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value int64, gas return nil, firstErr(err, ErrUnknownAddress) } ret, err = vm.Call(callee, callee, acc.Code, args, value, gas) + } else if op == DELEGATECALL { + if acc == nil { + return nil, firstErr(err, ErrUnknownAddress) + } + ret, err = vm.DelegateCall(caller, callee, acc.Code, args, value, gas) } else { // nil account means we're sending funds to a new account if acc == nil { -- GitLab