diff --git a/core/vm/gas_table.go b/core/vm/gas_table.go
index 8a6c2741de796b68385c9658c435774ee32a28bd..6cdbc5c39b5a6524ea489079c200ff1725cddd6c 100644
--- a/core/vm/gas_table.go
+++ b/core/vm/gas_table.go
@@ -91,6 +91,32 @@ func gasCalldataCopy(gt params.GasTable, evm *EVM, contract *Contract, stack *St
 	return gas, nil
 }
 
+func gasReturnDataCopy(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
+	gas, err := memoryGasCost(mem, memorySize)
+	if err != nil {
+		return 0, err
+	}
+
+	var overflow bool
+	if gas, overflow = math.SafeAdd(gas, GasFastestStep); overflow {
+		return 0, errGasUintOverflow
+	}
+
+	words, overflow := bigUint64(stack.Back(2))
+	if overflow {
+		return 0, errGasUintOverflow
+	}
+
+	if words, overflow = math.SafeMul(toWordSize(words), params.CopyGas); overflow {
+		return 0, errGasUintOverflow
+	}
+
+	if gas, overflow = math.SafeAdd(gas, words); overflow {
+		return 0, errGasUintOverflow
+	}
+	return gas, nil
+}
+
 func gasSStore(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
 	var (
 		y, x = stack.Back(1), stack.Back(0)
diff --git a/core/vm/instructions.go b/core/vm/instructions.go
index aaa8d7945e6ee5a5aa6efe6675a4a23bef9054ed..0dd9af09681676e93bc902c79e8796e932fc69b4 100644
--- a/core/vm/instructions.go
+++ b/core/vm/instructions.go
@@ -31,6 +31,7 @@ import (
 var (
 	bigZero            = new(big.Int)
 	errWriteProtection = errors.New("evm: write protection")
+	errReadOutOfBound  = errors.New("evm: read out of bound")
 )
 
 func opAdd(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
@@ -360,6 +361,28 @@ func opCalldataCopy(pc *uint64, evm *EVM, contract *Contract, memory *Memory, st
 	return nil, nil
 }
 
+func opReturnDataSize(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+	stack.push(evm.interpreter.intPool.get().SetUint64(uint64(len(evm.interpreter.returnData))))
+	return nil, nil
+}
+
+func opReturnDataCopy(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+	var (
+		mOff = stack.pop()
+		cOff = stack.pop()
+		l    = stack.pop()
+	)
+	defer evm.interpreter.intPool.put(mOff, cOff, l)
+
+	cEnd := new(big.Int).Add(cOff, l)
+	if cEnd.BitLen() > 64 || uint64(len(evm.interpreter.returnData)) < cEnd.Uint64() {
+		return nil, errReadOutOfBound
+	}
+	memory.Set(mOff.Uint64(), l.Uint64(), evm.interpreter.returnData[cOff.Uint64():cEnd.Uint64()])
+
+	return nil, nil
+}
+
 func opExtCodeSize(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
 	a := stack.pop()
 
diff --git a/core/vm/interpreter.go b/core/vm/interpreter.go
index 661ada6910c9370e398f724354c541454164584b..1c7481bc5d46dc3146ca038460b3cadcbce33c6a 100644
--- a/core/vm/interpreter.go
+++ b/core/vm/interpreter.go
@@ -60,6 +60,8 @@ type Interpreter struct {
 	intPool  *intPool
 
 	readonly bool
+	// returnData contains the last call's return data
+	returnData []byte
 }
 
 // NewInterpreter returns a new instance of the Interpreter.
@@ -113,6 +115,10 @@ func (in *Interpreter) Run(snapshot int, contract *Contract, input []byte) (ret
 	in.evm.depth++
 	defer func() { in.evm.depth-- }()
 
+	// Reset the previous call's return data. It's unimportant to preserve the old buffer
+	// as every returning call will return new data anyway.
+	in.returnData = nil
+
 	// Don't bother with the execution if there's no code.
 	if len(contract.Code) == 0 {
 		return nil, nil
@@ -213,10 +219,10 @@ func (in *Interpreter) Run(snapshot int, contract *Contract, input []byte) (ret
 		case !operation.jumps:
 			pc++
 		}
-		// if the operation returned a value make sure that is also set
-		// the last return data.
-		if res != nil {
-			mem.lastReturn = ret
+		// if the operation clears the return data (e.g. it has returning data)
+		// set the last return to the result of the operation.
+		if operation.clearsReturndata {
+			in.returnData = res
 		}
 	}
 	return nil, nil
diff --git a/core/vm/jump_table.go b/core/vm/jump_table.go
index f6e8dae6651a3511bbc4d680b0d0868dee05e918..7fb11021f08487eac16b4d951f491aee4d1a35b5 100644
--- a/core/vm/jump_table.go
+++ b/core/vm/jump_table.go
@@ -53,6 +53,8 @@ type operation struct {
 	valid bool
 	// reverts determined whether the operation reverts state
 	reverts bool
+	// clearsReturndata determines whether the opertions clears the return data
+	clearsReturndata bool
 }
 
 var (
@@ -73,6 +75,19 @@ func NewMetropolisInstructionSet() [256]operation {
 		memorySize:    memoryStaticCall,
 		valid:         true,
 	}
+	instructionSet[RETURNDATASIZE] = operation{
+		execute:       opReturnDataSize,
+		gasCost:       constGasFunc(GasQuickStep),
+		validateStack: makeStackFunc(0, 1),
+		valid:         true,
+	}
+	instructionSet[RETURNDATACOPY] = operation{
+		execute:       opReturnDataCopy,
+		gasCost:       gasReturnDataCopy,
+		validateStack: makeStackFunc(3, 0),
+		memorySize:    memoryReturnDataCopy,
+		valid:         true,
+	}
 	return instructionSet
 }
 
@@ -861,26 +876,29 @@ func NewFrontierInstructionSet() [256]operation {
 			writes:        true,
 		},
 		CREATE: {
-			execute:       opCreate,
-			gasCost:       gasCreate,
-			validateStack: makeStackFunc(3, 1),
-			memorySize:    memoryCreate,
-			valid:         true,
-			writes:        true,
+			execute:          opCreate,
+			gasCost:          gasCreate,
+			validateStack:    makeStackFunc(3, 1),
+			memorySize:       memoryCreate,
+			valid:            true,
+			writes:           true,
+			clearsReturndata: true,
 		},
 		CALL: {
-			execute:       opCall,
-			gasCost:       gasCall,
-			validateStack: makeStackFunc(7, 1),
-			memorySize:    memoryCall,
-			valid:         true,
+			execute:          opCall,
+			gasCost:          gasCall,
+			validateStack:    makeStackFunc(7, 1),
+			memorySize:       memoryCall,
+			valid:            true,
+			clearsReturndata: true,
 		},
 		CALLCODE: {
-			execute:       opCallCode,
-			gasCost:       gasCallCode,
-			validateStack: makeStackFunc(7, 1),
-			memorySize:    memoryCall,
-			valid:         true,
+			execute:          opCallCode,
+			gasCost:          gasCallCode,
+			validateStack:    makeStackFunc(7, 1),
+			memorySize:       memoryCall,
+			valid:            true,
+			clearsReturndata: true,
 		},
 		RETURN: {
 			execute:       opReturn,
diff --git a/core/vm/memory_table.go b/core/vm/memory_table.go
index 9d293a2f2cc739e005bb2ca8e036ca899146d8e6..9f6533bbcea2ed8c5fc2d6c6428dd2f2eeb93c4d 100644
--- a/core/vm/memory_table.go
+++ b/core/vm/memory_table.go
@@ -30,6 +30,10 @@ func memoryCalldataCopy(stack *Stack) *big.Int {
 	return calcMemSize(stack.Back(0), stack.Back(2))
 }
 
+func memoryReturnDataCopy(stack *Stack) *big.Int {
+	return calcMemSize(stack.Back(0), stack.Back(2))
+}
+
 func memoryCodeCopy(stack *Stack) *big.Int {
 	return calcMemSize(stack.Back(0), stack.Back(2))
 }
diff --git a/core/vm/opcodes.go b/core/vm/opcodes.go
index 51925e8ddd096e5c3c0b93e293e3a893aa8984be..be87cae18b9ce29266c942a13f7b0f344e41e0b9 100644
--- a/core/vm/opcodes.go
+++ b/core/vm/opcodes.go
@@ -82,10 +82,11 @@ const (
 	GASPRICE
 	EXTCODESIZE
 	EXTCODECOPY
+	RETURNDATASIZE
+	RETURNDATACOPY
 )
 
 const (
-
 	// 0x40 range - block operations
 	BLOCKHASH OpCode = 0x40 + iota
 	COINBASE
@@ -239,27 +240,29 @@ var opCodeToString = map[OpCode]string{
 	SHA3: "SHA3",
 
 	// 0x30 range - closure state
-	ADDRESS:      "ADDRESS",
-	BALANCE:      "BALANCE",
-	ORIGIN:       "ORIGIN",
-	CALLER:       "CALLER",
-	CALLVALUE:    "CALLVALUE",
-	CALLDATALOAD: "CALLDATALOAD",
-	CALLDATASIZE: "CALLDATASIZE",
-	CALLDATACOPY: "CALLDATACOPY",
-	CODESIZE:     "CODESIZE",
-	CODECOPY:     "CODECOPY",
-	GASPRICE:     "GASPRICE",
+	ADDRESS:        "ADDRESS",
+	BALANCE:        "BALANCE",
+	ORIGIN:         "ORIGIN",
+	CALLER:         "CALLER",
+	CALLVALUE:      "CALLVALUE",
+	CALLDATALOAD:   "CALLDATALOAD",
+	CALLDATASIZE:   "CALLDATASIZE",
+	CALLDATACOPY:   "CALLDATACOPY",
+	CODESIZE:       "CODESIZE",
+	CODECOPY:       "CODECOPY",
+	GASPRICE:       "GASPRICE",
+	EXTCODESIZE:    "EXTCODESIZE",
+	EXTCODECOPY:    "EXTCODECOPY",
+	RETURNDATASIZE: "RETURNDATASIZE",
+	RETURNDATACOPY: "RETURNDATACOPY",
 
 	// 0x40 range - block operations
-	BLOCKHASH:   "BLOCKHASH",
-	COINBASE:    "COINBASE",
-	TIMESTAMP:   "TIMESTAMP",
-	NUMBER:      "NUMBER",
-	DIFFICULTY:  "DIFFICULTY",
-	GASLIMIT:    "GASLIMIT",
-	EXTCODESIZE: "EXTCODESIZE",
-	EXTCODECOPY: "EXTCODECOPY",
+	BLOCKHASH:  "BLOCKHASH",
+	COINBASE:   "COINBASE",
+	TIMESTAMP:  "TIMESTAMP",
+	NUMBER:     "NUMBER",
+	DIFFICULTY: "DIFFICULTY",
+	GASLIMIT:   "GASLIMIT",
 
 	// 0x50 range - 'storage' and execution
 	POP: "POP",
@@ -374,137 +377,139 @@ func (o OpCode) String() string {
 }
 
 var stringToOp = map[string]OpCode{
-	"STOP":         STOP,
-	"ADD":          ADD,
-	"MUL":          MUL,
-	"SUB":          SUB,
-	"DIV":          DIV,
-	"SDIV":         SDIV,
-	"MOD":          MOD,
-	"SMOD":         SMOD,
-	"EXP":          EXP,
-	"NOT":          NOT,
-	"LT":           LT,
-	"GT":           GT,
-	"SLT":          SLT,
-	"SGT":          SGT,
-	"EQ":           EQ,
-	"ISZERO":       ISZERO,
-	"SIGNEXTEND":   SIGNEXTEND,
-	"AND":          AND,
-	"OR":           OR,
-	"XOR":          XOR,
-	"BYTE":         BYTE,
-	"ADDMOD":       ADDMOD,
-	"MULMOD":       MULMOD,
-	"SHA3":         SHA3,
-	"ADDRESS":      ADDRESS,
-	"BALANCE":      BALANCE,
-	"ORIGIN":       ORIGIN,
-	"CALLER":       CALLER,
-	"CALLVALUE":    CALLVALUE,
-	"CALLDATALOAD": CALLDATALOAD,
-	"CALLDATASIZE": CALLDATASIZE,
-	"CALLDATACOPY": CALLDATACOPY,
-	"DELEGATECALL": DELEGATECALL,
-	"STATICCALL":   STATICCALL,
-	"CODESIZE":     CODESIZE,
-	"CODECOPY":     CODECOPY,
-	"GASPRICE":     GASPRICE,
-	"BLOCKHASH":    BLOCKHASH,
-	"COINBASE":     COINBASE,
-	"TIMESTAMP":    TIMESTAMP,
-	"NUMBER":       NUMBER,
-	"DIFFICULTY":   DIFFICULTY,
-	"GASLIMIT":     GASLIMIT,
-	"EXTCODESIZE":  EXTCODESIZE,
-	"EXTCODECOPY":  EXTCODECOPY,
-	"POP":          POP,
-	"MLOAD":        MLOAD,
-	"MSTORE":       MSTORE,
-	"MSTORE8":      MSTORE8,
-	"SLOAD":        SLOAD,
-	"SSTORE":       SSTORE,
-	"JUMP":         JUMP,
-	"JUMPI":        JUMPI,
-	"PC":           PC,
-	"MSIZE":        MSIZE,
-	"GAS":          GAS,
-	"JUMPDEST":     JUMPDEST,
-	"PUSH1":        PUSH1,
-	"PUSH2":        PUSH2,
-	"PUSH3":        PUSH3,
-	"PUSH4":        PUSH4,
-	"PUSH5":        PUSH5,
-	"PUSH6":        PUSH6,
-	"PUSH7":        PUSH7,
-	"PUSH8":        PUSH8,
-	"PUSH9":        PUSH9,
-	"PUSH10":       PUSH10,
-	"PUSH11":       PUSH11,
-	"PUSH12":       PUSH12,
-	"PUSH13":       PUSH13,
-	"PUSH14":       PUSH14,
-	"PUSH15":       PUSH15,
-	"PUSH16":       PUSH16,
-	"PUSH17":       PUSH17,
-	"PUSH18":       PUSH18,
-	"PUSH19":       PUSH19,
-	"PUSH20":       PUSH20,
-	"PUSH21":       PUSH21,
-	"PUSH22":       PUSH22,
-	"PUSH23":       PUSH23,
-	"PUSH24":       PUSH24,
-	"PUSH25":       PUSH25,
-	"PUSH26":       PUSH26,
-	"PUSH27":       PUSH27,
-	"PUSH28":       PUSH28,
-	"PUSH29":       PUSH29,
-	"PUSH30":       PUSH30,
-	"PUSH31":       PUSH31,
-	"PUSH32":       PUSH32,
-	"DUP1":         DUP1,
-	"DUP2":         DUP2,
-	"DUP3":         DUP3,
-	"DUP4":         DUP4,
-	"DUP5":         DUP5,
-	"DUP6":         DUP6,
-	"DUP7":         DUP7,
-	"DUP8":         DUP8,
-	"DUP9":         DUP9,
-	"DUP10":        DUP10,
-	"DUP11":        DUP11,
-	"DUP12":        DUP12,
-	"DUP13":        DUP13,
-	"DUP14":        DUP14,
-	"DUP15":        DUP15,
-	"DUP16":        DUP16,
-	"SWAP1":        SWAP1,
-	"SWAP2":        SWAP2,
-	"SWAP3":        SWAP3,
-	"SWAP4":        SWAP4,
-	"SWAP5":        SWAP5,
-	"SWAP6":        SWAP6,
-	"SWAP7":        SWAP7,
-	"SWAP8":        SWAP8,
-	"SWAP9":        SWAP9,
-	"SWAP10":       SWAP10,
-	"SWAP11":       SWAP11,
-	"SWAP12":       SWAP12,
-	"SWAP13":       SWAP13,
-	"SWAP14":       SWAP14,
-	"SWAP15":       SWAP15,
-	"SWAP16":       SWAP16,
-	"LOG0":         LOG0,
-	"LOG1":         LOG1,
-	"LOG2":         LOG2,
-	"LOG3":         LOG3,
-	"LOG4":         LOG4,
-	"CREATE":       CREATE,
-	"CALL":         CALL,
-	"RETURN":       RETURN,
-	"CALLCODE":     CALLCODE,
-	"SELFDESTRUCT": SELFDESTRUCT,
+	"STOP":           STOP,
+	"ADD":            ADD,
+	"MUL":            MUL,
+	"SUB":            SUB,
+	"DIV":            DIV,
+	"SDIV":           SDIV,
+	"MOD":            MOD,
+	"SMOD":           SMOD,
+	"EXP":            EXP,
+	"NOT":            NOT,
+	"LT":             LT,
+	"GT":             GT,
+	"SLT":            SLT,
+	"SGT":            SGT,
+	"EQ":             EQ,
+	"ISZERO":         ISZERO,
+	"SIGNEXTEND":     SIGNEXTEND,
+	"AND":            AND,
+	"OR":             OR,
+	"XOR":            XOR,
+	"BYTE":           BYTE,
+	"ADDMOD":         ADDMOD,
+	"MULMOD":         MULMOD,
+	"SHA3":           SHA3,
+	"ADDRESS":        ADDRESS,
+	"BALANCE":        BALANCE,
+	"ORIGIN":         ORIGIN,
+	"CALLER":         CALLER,
+	"CALLVALUE":      CALLVALUE,
+	"CALLDATALOAD":   CALLDATALOAD,
+	"CALLDATASIZE":   CALLDATASIZE,
+	"CALLDATACOPY":   CALLDATACOPY,
+	"DELEGATECALL":   DELEGATECALL,
+	"STATICCALL":     STATICCALL,
+	"CODESIZE":       CODESIZE,
+	"CODECOPY":       CODECOPY,
+	"GASPRICE":       GASPRICE,
+	"EXTCODESIZE":    EXTCODESIZE,
+	"EXTCODECOPY":    EXTCODECOPY,
+	"RETURNDATASIZE": RETURNDATASIZE,
+	"RETURNDATACOPY": RETURNDATACOPY,
+	"BLOCKHASH":      BLOCKHASH,
+	"COINBASE":       COINBASE,
+	"TIMESTAMP":      TIMESTAMP,
+	"NUMBER":         NUMBER,
+	"DIFFICULTY":     DIFFICULTY,
+	"GASLIMIT":       GASLIMIT,
+	"POP":            POP,
+	"MLOAD":          MLOAD,
+	"MSTORE":         MSTORE,
+	"MSTORE8":        MSTORE8,
+	"SLOAD":          SLOAD,
+	"SSTORE":         SSTORE,
+	"JUMP":           JUMP,
+	"JUMPI":          JUMPI,
+	"PC":             PC,
+	"MSIZE":          MSIZE,
+	"GAS":            GAS,
+	"JUMPDEST":       JUMPDEST,
+	"PUSH1":          PUSH1,
+	"PUSH2":          PUSH2,
+	"PUSH3":          PUSH3,
+	"PUSH4":          PUSH4,
+	"PUSH5":          PUSH5,
+	"PUSH6":          PUSH6,
+	"PUSH7":          PUSH7,
+	"PUSH8":          PUSH8,
+	"PUSH9":          PUSH9,
+	"PUSH10":         PUSH10,
+	"PUSH11":         PUSH11,
+	"PUSH12":         PUSH12,
+	"PUSH13":         PUSH13,
+	"PUSH14":         PUSH14,
+	"PUSH15":         PUSH15,
+	"PUSH16":         PUSH16,
+	"PUSH17":         PUSH17,
+	"PUSH18":         PUSH18,
+	"PUSH19":         PUSH19,
+	"PUSH20":         PUSH20,
+	"PUSH21":         PUSH21,
+	"PUSH22":         PUSH22,
+	"PUSH23":         PUSH23,
+	"PUSH24":         PUSH24,
+	"PUSH25":         PUSH25,
+	"PUSH26":         PUSH26,
+	"PUSH27":         PUSH27,
+	"PUSH28":         PUSH28,
+	"PUSH29":         PUSH29,
+	"PUSH30":         PUSH30,
+	"PUSH31":         PUSH31,
+	"PUSH32":         PUSH32,
+	"DUP1":           DUP1,
+	"DUP2":           DUP2,
+	"DUP3":           DUP3,
+	"DUP4":           DUP4,
+	"DUP5":           DUP5,
+	"DUP6":           DUP6,
+	"DUP7":           DUP7,
+	"DUP8":           DUP8,
+	"DUP9":           DUP9,
+	"DUP10":          DUP10,
+	"DUP11":          DUP11,
+	"DUP12":          DUP12,
+	"DUP13":          DUP13,
+	"DUP14":          DUP14,
+	"DUP15":          DUP15,
+	"DUP16":          DUP16,
+	"SWAP1":          SWAP1,
+	"SWAP2":          SWAP2,
+	"SWAP3":          SWAP3,
+	"SWAP4":          SWAP4,
+	"SWAP5":          SWAP5,
+	"SWAP6":          SWAP6,
+	"SWAP7":          SWAP7,
+	"SWAP8":          SWAP8,
+	"SWAP9":          SWAP9,
+	"SWAP10":         SWAP10,
+	"SWAP11":         SWAP11,
+	"SWAP12":         SWAP12,
+	"SWAP13":         SWAP13,
+	"SWAP14":         SWAP14,
+	"SWAP15":         SWAP15,
+	"SWAP16":         SWAP16,
+	"LOG0":           LOG0,
+	"LOG1":           LOG1,
+	"LOG2":           LOG2,
+	"LOG3":           LOG3,
+	"LOG4":           LOG4,
+	"CREATE":         CREATE,
+	"CALL":           CALL,
+	"RETURN":         RETURN,
+	"CALLCODE":       CALLCODE,
+	"SELFDESTRUCT":   SELFDESTRUCT,
 }
 
 func StringToOp(str string) OpCode {