Skip to content
Snippets Groups Projects
Commit 9214f236 authored by Silas Davis's avatar Silas Davis Committed by GitHub
Browse files

Merge pull request #261 from benjaminbollen/issue260_delegatecall_on_develop

Issue260 delegatecall on develop
parents 39c75dfb d3b785fe
No related branches found
No related tags found
No related merge requests found
...@@ -167,6 +167,7 @@ const ( ...@@ -167,6 +167,7 @@ const (
CALL CALL
CALLCODE CALLCODE
RETURN RETURN
DELEGATECALL
// 0x70 range - other // 0x70 range - other
SUICIDE = 0xff SUICIDE = 0xff
...@@ -317,10 +318,11 @@ var opCodeToString = map[OpCode]string{ ...@@ -317,10 +318,11 @@ var opCodeToString = map[OpCode]string{
LOG4: "LOG4", LOG4: "LOG4",
// 0xf0 range // 0xf0 range
CREATE: "CREATE", CREATE: "CREATE",
CALL: "CALL", CALL: "CALL",
RETURN: "RETURN", RETURN: "RETURN",
CALLCODE: "CALLCODE", CALLCODE: "CALLCODE",
DELEGATECALL: "DELEGATECALL",
// 0x70 range - other // 0x70 range - other
SUICIDE: "SUICIDE", SUICIDE: "SUICIDE",
......
...@@ -147,6 +147,30 @@ func (vm *VM) Call(caller, callee *Account, code, input []byte, value int64, gas ...@@ -147,6 +147,30 @@ func (vm *VM) Call(caller, callee *Account, code, input []byte, value int64, gas
return return
} }
// DelegateCall is executed by the DELEGATECALL opcode, introduced as off Ethereum Homestead.
// The intent of delegate call is to run the code of the callee in the storage context of the caller;
// 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 {
vm.callDepth += 1
output, err = vm.call(caller, callee, code, input, value, gas)
vm.callDepth -= 1
if err != nil {
*exception = err.Error()
}
}
return
}
// Try to deduct gasToUse from gasLeft. If ok return false, otherwise // Try to deduct gasToUse from gasLeft. If ok return false, otherwise
// set err and return true. // set err and return true.
func useGasNegative(gasLeft *int64, gasToUse int64, err *error) bool { func useGasNegative(gasLeft *int64, gasToUse int64, err *error) bool {
...@@ -746,12 +770,20 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value int64, gas ...@@ -746,12 +770,20 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value int64, gas
stack.Push(newAccount.Address) stack.Push(newAccount.Address)
} }
case CALL, CALLCODE: // 0xF1, 0xF2 case CALL, CALLCODE, DELEGATECALL: // 0xF1, 0xF2, 0xF4
if !HasPermission(vm.appState, callee, ptypes.Call) { if !HasPermission(vm.appState, callee, ptypes.Call) {
return nil, ErrPermission{"call"} return nil, ErrPermission{"call"}
} }
gasLimit := stack.Pop64() 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 inOffset, inSize := stack.Pop64(), stack.Pop64() // inputs
retOffset, retSize := stack.Pop64(), stack.Pop64() // outputs retOffset, retSize := stack.Pop64(), stack.Pop64() // outputs
dbg.Printf(" => %X\n", addr) dbg.Printf(" => %X\n", addr)
...@@ -800,6 +832,11 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value int64, gas ...@@ -800,6 +832,11 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value int64, gas
return nil, firstErr(err, ErrUnknownAddress) return nil, firstErr(err, ErrUnknownAddress)
} }
ret, err = vm.Call(callee, callee, acc.Code, args, value, gas) 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 { } else {
// nil account means we're sending funds to a new account // nil account means we're sending funds to a new account
if acc == nil { if acc == nil {
......
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