diff --git a/execution/evm/vm_test.go b/execution/evm/vm_test.go
index 4e8beb6884ccd45a1ceef7a6cce688ebd655c7e4..c6599ccf58807a05956d0dbd241e7b1069226ade 100644
--- a/execution/evm/vm_test.go
+++ b/execution/evm/vm_test.go
@@ -31,14 +31,16 @@ import (
 	. "github.com/hyperledger/burrow/execution/evm/asm"
 	. "github.com/hyperledger/burrow/execution/evm/asm/bc"
 	evm_events "github.com/hyperledger/burrow/execution/evm/events"
-	"github.com/hyperledger/burrow/logging/lifecycle"
 	"github.com/hyperledger/burrow/logging/loggers"
 	"github.com/hyperledger/burrow/permission"
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/require"
+	"golang.org/x/crypto/ripemd160"
 )
 
-var logger, _ = lifecycle.NewStdErrLogger()
+// Test output is a bit clearer if we /dev/null the logging, but can be re-enabled by uncommenting the below
+//var logger, _ = lifecycle.NewStdErrLogger()
+var logger = loggers.NewNoopInfoTraceLogger()
 
 func newAppState() *FakeAppState {
 	fas := &FakeAppState{
@@ -61,9 +63,11 @@ func newParams() Params {
 	}
 }
 
-func newAccount(address ...byte) acm.MutableAccount {
+func newAccount(seed ...byte) acm.MutableAccount {
+	hasher := ripemd160.New()
+	hasher.Write(seed)
 	return acm.ConcreteAccount{
-		Address: acm.AddressFromWord256(RightPadWord256(address)),
+		Address: acm.MustAddressFromBytes(hasher.Sum(nil)),
 	}.MutableAccount()
 }
 
@@ -286,6 +290,53 @@ func TestMemoryBounds(t *testing.T) {
 	assert.Error(t, err, "Should hit memory out of bounds")
 }
 
+func TestMsgSender(t *testing.T) {
+	st := newAppState()
+	account1 := newAccount(1, 2, 3)
+	account2 := newAccount(3, 2, 1)
+	st.accounts[account1.Address()] = account1
+	st.accounts[account2.Address()] = account2
+
+	ourVm := NewVM(st, DefaultDynamicMemoryProvider, newParams(), acm.ZeroAddress, nil, logger)
+
+	var gas uint64 = 100000
+
+	/*
+			pragma solidity ^0.4.0;
+
+			contract SimpleStorage {
+		                function get() public constant returns (address) {
+		        	        return msg.sender;
+		    	        }
+			}
+	*/
+
+	// This bytecode is compiled from Solidity contract above using remix.ethereum.org online compiler
+	code, err := hex.DecodeString("6060604052341561000f57600080fd5b60ca8061001d6000396000f30060606040526004361060" +
+		"3f576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680636d4ce63c14604457" +
+		"5b600080fd5b3415604e57600080fd5b60546096565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ff" +
+		"ffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6000339050905600a165627a" +
+		"7a72305820b9ebf49535372094ae88f56d9ad18f2a79c146c8f56e7ef33b9402924045071e0029")
+	require.NoError(t, err)
+
+	// Run the contract initialisation code to obtain the contract code that would be mounted at account2
+	contractCode, err := ourVm.Call(account1, account2, code, code, 0, &gas)
+	require.NoError(t, err)
+
+	// Not needed for this test (since contract code is passed as argument to vm), but this is what an execution
+	// framework must do
+	account2.SetCode(contractCode)
+
+	// Input is the function hash of `get()`
+	input, err := hex.DecodeString("6d4ce63c")
+
+	output, err := ourVm.Call(account1, account2, contractCode, input, 0, &gas)
+	require.NoError(t, err)
+
+	assert.Equal(t, account1.Address().Word256().Bytes(), output)
+
+}
+
 // These code segment helpers exercise the MSTORE MLOAD MSTORE cycle to test
 // both of the memory operations. Each MSTORE is done on the memory boundary
 // (at MSIZE) which Solidity uses to find guaranteed unallocated memory.