diff --git a/.gitignore b/.gitignore
index 062ac40a40e60a8deb295da0d715829b791ee5b6..c7f40537d814cb7864a2367604c295cfa919567c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -9,7 +9,6 @@ test_scratch/
 
 # Temporary / cached
 *.swp
-debug
 .idea
 .vscode
 
diff --git a/cmd/burrow/main.go b/cmd/burrow/main.go
index 7069d8bcdf8cc1a64649fdd1bc217d3aac855e3f..d7d56f08ef7059ecd7dad1c405c0a3469c463de9 100644
--- a/cmd/burrow/main.go
+++ b/cmd/burrow/main.go
@@ -3,14 +3,12 @@ package main
 import (
 	"context"
 	"fmt"
-	"log"
-	"net/http"
-	_ "net/http/pprof"
 	"os"
 	"strings"
 
 	"github.com/hyperledger/burrow/config"
 	"github.com/hyperledger/burrow/config/source"
+	"github.com/hyperledger/burrow/execution"
 	"github.com/hyperledger/burrow/genesis"
 	"github.com/hyperledger/burrow/genesis/spec"
 	"github.com/hyperledger/burrow/keys"
@@ -39,9 +37,6 @@ func main() {
 			fmt.Println(project.History.CurrentVersion().String())
 			os.Exit(0)
 		}
-		go func() {
-			log.Println(http.ListenAndServe("localhost:6060", nil))
-		}()
 		// We need to reflect on whether this obscures where values are coming from
 		conf := config.DefaultBurrowConfig()
 		// We treat logging a little differently in that if anything is set for logging we will not
@@ -143,8 +138,13 @@ func main() {
 			describeLoggingOpt := cmd.BoolOpt("describe-logging", false,
 				"Print an exhaustive list of logging instructions available with the --logging option")
 
+			debugOpt := cmd.BoolOpt("d debug", false, "Include maximal debug options in config "+
+				"including logging opcodes and dumping EVM tokens to disk these can be later pruned from the "+
+				"generated config.")
+
 			cmd.Spec = "[--keys-url=<keys URL>] [--genesis-spec=<GenesisSpec file> | --genesis-doc=<GenesisDoc file>] " +
-				"[--validator-index=<index>] [--toml-in] [--json-out] [--logging=<logging program>] [--describe-logging]"
+				"[--validator-index=<index>] [--toml-in] [--json-out] [--logging=<logging program>] " +
+				"[--describe-logging] [--debug]"
 
 			cmd.Action = func() {
 				conf := config.DefaultBurrowConfig()
@@ -219,6 +219,12 @@ func main() {
 					}
 				}
 
+				if *debugOpt {
+					conf.Execution = &execution.ExecutionConfig{
+						VMOptions: []execution.VMOption{execution.DumpTokens, execution.DebugOpcodes},
+					}
+				}
+
 				if *jsonOutOpt {
 					os.Stdout.WriteString(conf.JSONString())
 				} else {
diff --git a/config/config.go b/config/config.go
index 91c5331b490be27c398e9e8ce528a894092d63a7..160f240632db14485053c0f20a91a77f3678e97e 100644
--- a/config/config.go
+++ b/config/config.go
@@ -10,6 +10,7 @@ import (
 	"github.com/hyperledger/burrow/consensus/tendermint"
 	"github.com/hyperledger/burrow/consensus/tendermint/validator"
 	"github.com/hyperledger/burrow/core"
+	"github.com/hyperledger/burrow/execution"
 	"github.com/hyperledger/burrow/genesis"
 	"github.com/hyperledger/burrow/keys"
 	logging_config "github.com/hyperledger/burrow/logging/config"
@@ -25,6 +26,7 @@ type BurrowConfig struct {
 	ValidatorAddress *acm.Address                       `json:",omitempty" toml:",omitempty"`
 	GenesisDoc       *genesis.GenesisDoc                `json:",omitempty" toml:",omitempty"`
 	Tendermint       *tendermint.BurrowTendermintConfig `json:",omitempty" toml:",omitempty"`
+	Execution        *execution.ExecutionConfig         `json:",omitempty" toml:",omitempty"`
 	Keys             *keys.KeysConfig                   `json:",omitempty" toml:",omitempty"`
 	RPC              *rpc.RPCConfig                     `json:",omitempty" toml:",omitempty"`
 	Logging          *logging_config.LoggingConfig      `json:",omitempty" toml:",omitempty"`
@@ -57,7 +59,17 @@ func (conf *BurrowConfig) Kernel(ctx context.Context) (*core.Kernel, error) {
 	}
 	privValidator := validator.NewPrivValidatorMemory(val, keys.Signer(keyClient, val.Address()))
 
-	return core.NewKernel(ctx, privValidator, conf.GenesisDoc, conf.Tendermint.TendermintConfig(), conf.RPC, logger)
+	var exeOptions []execution.ExecutionOption
+	if conf.Execution != nil {
+		var err error
+		exeOptions, err = conf.Execution.ExecutionOptions()
+		if err != nil {
+			return nil, err
+		}
+	}
+
+	return core.NewKernel(ctx, privValidator, conf.GenesisDoc, conf.Tendermint.TendermintConfig(), conf.RPC, exeOptions,
+		logger)
 }
 
 func (conf *BurrowConfig) JSONString() string {
diff --git a/core/kernel.go b/core/kernel.go
index 4c734add643918dd9d2d635cbba792a981e437c4..c033098e393abbc52dc8254e7acb6a652863f2eb 100644
--- a/core/kernel.go
+++ b/core/kernel.go
@@ -17,6 +17,8 @@ package core
 import (
 	"context"
 	"fmt"
+	"net/http"
+	_ "net/http/pprof"
 	"os"
 	"os/signal"
 	"sync"
@@ -62,7 +64,8 @@ type Kernel struct {
 }
 
 func NewKernel(ctx context.Context, privValidator tm_types.PrivValidator, genesisDoc *genesis.GenesisDoc,
-	tmConf *tm_config.Config, rpcConfig *rpc.RPCConfig, logger *logging.Logger) (*Kernel, error) {
+	tmConf *tm_config.Config, rpcConfig *rpc.RPCConfig, exeOptions []execution.ExecutionOption,
+	logger *logging.Logger) (*Kernel, error) {
 
 	logger = logger.WithScope("NewKernel()").With(structure.TimeKey, kitlog.DefaultTimestampUTC)
 	tmLogger := logger.With(structure.CallerKey, kitlog.Caller(LoggingCallerDepth+1))
@@ -90,7 +93,7 @@ func NewKernel(ctx context.Context, privValidator tm_types.PrivValidator, genesi
 	checker := execution.NewBatchChecker(state, tmGenesisDoc.ChainID, blockchain, logger)
 
 	emitter := event.NewEmitter(logger)
-	committer := execution.NewBatchCommitter(state, tmGenesisDoc.ChainID, blockchain, emitter, logger)
+	committer := execution.NewBatchCommitter(state, tmGenesisDoc.ChainID, blockchain, emitter, logger, exeOptions...)
 	tmNode, err := tendermint.NewNode(tmConf, privValidator, tmGenesisDoc, blockchain, checker, committer, tmLogger)
 
 	if err != nil {
@@ -100,15 +103,25 @@ func NewKernel(ctx context.Context, privValidator tm_types.PrivValidator, genesi
 	transactor := execution.NewTransactor(blockchain, state, emitter, tendermint.BroadcastTxAsyncFunc(tmNode, txCodec),
 		logger)
 
-	// TODO: consider whether we need to be more explicit about pre-commit (check cache) versus committed (state) values
-	// Note we pass the checker as the StateIterable to NewService which means the RPC layers will query the check
-	// cache state. This is in line with previous behaviour of Burrow and chiefly serves to get provide a pre-commit
-	// view of sequence values on the node that a client is communicating with.
-	// Since we don't currently execute EVM code in the checker possible conflicts are limited to account creation
-	// which increments the creator's account Sequence and SendTxs
 	service := rpc.NewService(ctx, state, state, emitter, blockchain, transactor, query.NewNodeView(tmNode, txCodec), logger)
 
 	launchers := []process.Launcher{
+		{
+			Name:     "Profiling Server",
+			Disabled: rpcConfig.Profiler.Disabled,
+			Launch: func() (process.Process, error) {
+				debugServer := &http.Server{
+					Addr: ":6060",
+				}
+				go func() {
+					err := debugServer.ListenAndServe()
+					if err != nil {
+						logger.InfoMsg("Error from pprof debug server", structure.ErrorKey, err)
+					}
+				}()
+				return debugServer, nil
+			},
+		},
 		{
 			Name: "Database",
 			Launch: func() (process.Process, error) {
@@ -153,7 +166,8 @@ func NewKernel(ctx context.Context, privValidator tm_types.PrivValidator, genesi
 			},
 		},
 		{
-			Name: "RPC/tm",
+			Name:     "RPC/tm",
+			Disabled: rpcConfig.TM.Disabled,
 			Launch: func() (process.Process, error) {
 				listener, err := tm.StartServer(service, "/websocket", rpcConfig.TM.ListenAddress, emitter, logger)
 				if err != nil {
@@ -163,7 +177,8 @@ func NewKernel(ctx context.Context, privValidator tm_types.PrivValidator, genesi
 			},
 		},
 		{
-			Name: "RPC/V0",
+			Name:     "RPC/V0",
+			Disabled: rpcConfig.V0.Disabled,
 			Launch: func() (process.Process, error) {
 				codec := v0.NewTCodec()
 				jsonServer := v0.NewJSONServer(v0.NewJSONService(codec, service, logger))
diff --git a/core/kernel_test.go b/core/kernel_test.go
index 31f65710d65aeba1692a779a7951e1b068da35b1..aa1af7efc1aefc498cef965014a6d163d6e7f5ab 100644
--- a/core/kernel_test.go
+++ b/core/kernel_test.go
@@ -64,7 +64,7 @@ func bootWaitBlocksShutdown(privValidator tm_types.PrivValidator, genesisDoc *ge
 	tmConf *tm_config.Config, logger *logging.Logger,
 	blockChecker func(block *tm_types.EventDataNewBlock) (cont bool)) error {
 
-	kern, err := NewKernel(context.Background(), privValidator, genesisDoc, tmConf, rpc.DefaultRPCConfig(), logger)
+	kern, err := NewKernel(context.Background(), privValidator, genesisDoc, tmConf, rpc.DefaultRPCConfig(), nil, logger)
 	if err != nil {
 		return err
 	}
diff --git a/execution/config.go b/execution/config.go
new file mode 100644
index 0000000000000000000000000000000000000000..f90b6a02c529fcd5aa67fee1abf1011f725673d2
--- /dev/null
+++ b/execution/config.go
@@ -0,0 +1,39 @@
+package execution
+
+import (
+	"fmt"
+
+	"github.com/hyperledger/burrow/execution/evm"
+)
+
+type VMOption string
+
+const (
+	DebugOpcodes VMOption = "DebugOpcodes"
+	DumpTokens   VMOption = "DumpTokens"
+)
+
+type ExecutionConfig struct {
+	VMOptions []VMOption `json:",omitempty" toml:",omitempty"`
+}
+
+func DefaultExecutionConfig() *ExecutionConfig {
+	return &ExecutionConfig{}
+}
+
+func (ec *ExecutionConfig) ExecutionOptions() ([]ExecutionOption, error) {
+	var exeOptions []ExecutionOption
+	var vmOptions []func(*evm.VM)
+	for _, option := range ec.VMOptions {
+		switch option {
+		case DebugOpcodes:
+			vmOptions = append(vmOptions, evm.DebugOpcodes)
+		case DumpTokens:
+			vmOptions = append(vmOptions, evm.DumpTokens)
+		default:
+			return nil, fmt.Errorf("VM option '%s' not recognised", option)
+		}
+	}
+	exeOptions = append(exeOptions, VMOptions(vmOptions...))
+	return exeOptions, nil
+}
diff --git a/execution/evm/log_event_test.go b/execution/evm/log_event_test.go
index 3920a6511794cf2355d95269ec2ea09d52d740fd..3a054d51afd1281da7c51ef66aab91a68425337a 100644
--- a/execution/evm/log_event_test.go
+++ b/execution/evm/log_event_test.go
@@ -52,7 +52,7 @@ func TestLog4(t *testing.T) {
 	st.accounts[account1.Address()] = account1
 	st.accounts[account2.Address()] = account2
 
-	ourVm := NewVM(st, DefaultDynamicMemoryProvider, newParams(), acm.ZeroAddress, nil, logger)
+	ourVm := NewVM(st, newParams(), acm.ZeroAddress, nil, logger)
 
 	emitter := event.NewEmitter(logging.NewNoopLogger())
 
diff --git a/execution/evm/options.go b/execution/evm/options.go
new file mode 100644
index 0000000000000000000000000000000000000000..5081729daf98d75b1e5b46567451d9eb4578eb42
--- /dev/null
+++ b/execution/evm/options.go
@@ -0,0 +1,15 @@
+package evm
+
+func MemoryProvider(memoryProvider func() Memory) func(*VM) {
+	return func(vm *VM) {
+		vm.memoryProvider = memoryProvider
+	}
+}
+
+func DebugOpcodes(vm *VM) {
+	vm.debugOpcodes = true
+}
+
+func DumpTokens(vm *VM) {
+	vm.dumpTokens = true
+}
diff --git a/execution/evm/vm.go b/execution/evm/vm.go
index 5cb6ed3d172d2ebbdc124e22e7216ec1c012801c..9e2e35663ccdb68e0770fc01fce00432c62128f4 100644
--- a/execution/evm/vm.go
+++ b/execution/evm/vm.go
@@ -18,6 +18,9 @@ import (
 	"bytes"
 	"errors"
 	"fmt"
+	"io/ioutil"
+	"math/big"
+	"strings"
 
 	acm "github.com/hyperledger/burrow/account"
 	. "github.com/hyperledger/burrow/binary"
@@ -28,7 +31,6 @@ import (
 	"github.com/hyperledger/burrow/logging"
 	"github.com/hyperledger/burrow/permission"
 	ptypes "github.com/hyperledger/burrow/permission/types"
-	"math/big"
 )
 
 var (
@@ -53,8 +55,6 @@ const (
 	callStackCapacity = 100 // TODO ensure usage.
 )
 
-var Debug = false
-
 type ErrPermission struct {
 	typ string
 }
@@ -111,25 +111,30 @@ type VM struct {
 	nestedCallErrors []ErrNestedCall
 	publisher        event.Publisher
 	logger           *logging.Logger
+	debugOpcodes     bool
+	dumpTokens       bool
 }
 
-func NewVM(state acm.StateWriter, memoryProvider func() Memory, params Params, origin acm.Address, txid []byte,
-	logger *logging.Logger) *VM {
-	return &VM{
+func NewVM(state acm.StateWriter, params Params, origin acm.Address, txid []byte,
+	logger *logging.Logger, options ...func(*VM)) *VM {
+	vm := &VM{
 		state:          state,
-		memoryProvider: memoryProvider,
+		memoryProvider: DefaultDynamicMemoryProvider,
 		params:         params,
 		origin:         origin,
 		stackDepth:     0,
 		txHash:         txid,
 		logger:         logger.WithScope("NewVM"),
 	}
+	for _, option := range options {
+		option(vm)
+	}
+	return vm
 }
 
 func (vm *VM) Debugf(format string, a ...interface{}) {
-	if Debug {
-		//vm.logger.TraceMsg(fmt.Sprintf(format, a...), "tag", "vm_debug")
-		fmt.Printf(format, a...)
+	if vm.debugOpcodes {
+		vm.logger.TraceMsg(fmt.Sprintf(format, a...), "tag", "DebugOpcodes")
 	}
 }
 
@@ -249,18 +254,9 @@ func (vm *VM) call(caller, callee acm.MutableAccount, code, input []byte, value
 
 	logger := vm.logger.With("tx_hash", vm.txHash)
 
-	// TODO: provide this functionality via some debug flagging
-	//tokens, _ := acm.Bytecode(code).Tokens()
-	//if err != nil {
-	//	return nil, err
-	//}
-	//if len(vm.txHash) >= 4 {
-	//
-	//}
-	//err = ioutil.WriteFile(fmt.Sprintf("tokens-%X.txt", vm.txHash[:4]), []byte(strings.Join(tokens, "\n")), 0777)
-	//if err != nil {
-	//	return nil, err
-	//}
+	if vm.dumpTokens {
+		dumpTokens(vm.txHash, caller, callee, code)
+	}
 
 	var (
 		pc     int64 = 0
@@ -1128,3 +1124,28 @@ func transfer(from, to acm.MutableAccount, amount uint64) error {
 	}
 	return nil
 }
+
+// Dump the bytecode being sent to the EVM in the current working directory
+func dumpTokens(txHash []byte, caller, callee acm.Account, code []byte) {
+	var tokensString string
+	tokens, err := acm.Bytecode(code).Tokens()
+	if err != nil {
+		tokensString = fmt.Sprintf("error generating tokens from bytecode: %v", err)
+	} else {
+		tokensString = strings.Join(tokens, "\n")
+	}
+	txHashString := "tx-none"
+	if len(txHash) >= 4 {
+		txHashString = fmt.Sprintf("tx-%X", txHash[:4])
+	}
+	callerString := "caller-none"
+	if caller != nil {
+		callerString = fmt.Sprintf("caller-%v", caller.Address())
+	}
+	calleeString := "callee-none"
+	if callee != nil {
+		calleeString = fmt.Sprintf("callee-%s", caller.Address())
+	}
+	ioutil.WriteFile(fmt.Sprintf("tokens_%s_%s_%s.asm", txHashString, callerString, calleeString),
+		[]byte(tokensString), 0777)
+}
diff --git a/execution/evm/vm_test.go b/execution/evm/vm_test.go
index 9c47c4fd8849d2b95bf1a51fda4619bbb0158eb1..690f2c7970d04be7d0ad0dededa1d0fda8d8f5f3 100644
--- a/execution/evm/vm_test.go
+++ b/execution/evm/vm_test.go
@@ -72,7 +72,7 @@ func newAccount(seed ...byte) acm.MutableAccount {
 
 // Runs a basic loop
 func TestVM(t *testing.T) {
-	ourVm := NewVM(newAppState(), DefaultDynamicMemoryProvider, newParams(), acm.ZeroAddress, nil, logger)
+	ourVm := NewVM(newAppState(), newParams(), acm.ZeroAddress, nil, logger)
 
 	// Create accounts
 	account1 := newAccount(1)
@@ -95,7 +95,7 @@ func TestVM(t *testing.T) {
 
 //Test attempt to jump to bad destination (position 16)
 func TestJumpErr(t *testing.T) {
-	ourVm := NewVM(newAppState(), DefaultDynamicMemoryProvider, newParams(), acm.ZeroAddress, nil, logger)
+	ourVm := NewVM(newAppState(), newParams(), acm.ZeroAddress, nil, logger)
 
 	// Create accounts
 	account1 := newAccount(1)
@@ -132,7 +132,7 @@ func TestSubcurrency(t *testing.T) {
 	st.accounts[account1.Address()] = account1
 	st.accounts[account2.Address()] = account2
 
-	ourVm := NewVM(st, DefaultDynamicMemoryProvider, newParams(), acm.ZeroAddress, nil, logger)
+	ourVm := NewVM(st, newParams(), acm.ZeroAddress, nil, logger)
 
 	var gas uint64 = 1000
 
@@ -161,7 +161,7 @@ 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)
+	ourVm := NewVM(newAppState(), newParams(), acm.ZeroAddress, nil, logger)
 
 	// Create accounts
 	account1 := newAccount(1)
@@ -183,7 +183,7 @@ func TestRevert(t *testing.T) {
 // Test sending tokens from a contract to another account
 func TestSendCall(t *testing.T) {
 	fakeAppState := newAppState()
-	ourVm := NewVM(fakeAppState, DefaultDynamicMemoryProvider, newParams(), acm.ZeroAddress, nil, logger)
+	ourVm := NewVM(fakeAppState, newParams(), acm.ZeroAddress, nil, logger)
 
 	// Create accounts
 	account1 := newAccount(1)
@@ -221,7 +221,7 @@ func TestSendCall(t *testing.T) {
 // and then run it with 1 gas unit less, expecting a failure
 func TestDelegateCallGas(t *testing.T) {
 	state := newAppState()
-	ourVm := NewVM(state, DefaultDynamicMemoryProvider, newParams(), acm.ZeroAddress, nil, logger)
+	ourVm := NewVM(state, newParams(), acm.ZeroAddress, nil, logger)
 
 	inOff := 0
 	inSize := 0 // no call data
@@ -282,7 +282,7 @@ func TestMemoryBounds(t *testing.T) {
 	memoryProvider := func() Memory {
 		return NewDynamicMemory(1024, 2048)
 	}
-	ourVm := NewVM(state, memoryProvider, newParams(), acm.ZeroAddress, nil, logger)
+	ourVm := NewVM(state, newParams(), acm.ZeroAddress, nil, logger, MemoryProvider(memoryProvider))
 	caller, _ := makeAccountWithCode(state, "caller", nil)
 	callee, _ := makeAccountWithCode(state, "callee", nil)
 	gas := uint64(100000)
@@ -329,7 +329,7 @@ func TestMsgSender(t *testing.T) {
 	st.accounts[account1.Address()] = account1
 	st.accounts[account2.Address()] = account2
 
-	ourVm := NewVM(st, DefaultDynamicMemoryProvider, newParams(), acm.ZeroAddress, nil, logger)
+	ourVm := NewVM(st, newParams(), acm.ZeroAddress, nil, logger)
 
 	var gas uint64 = 100000
 
diff --git a/execution/execution.go b/execution/execution.go
index 2ea8e69b794d19d0da42a5cc050df54898f637d2..ca93e64cb5b79009ca08bb0191f6bc70128edbe4 100644
--- a/execution/execution.go
+++ b/execution/execution.go
@@ -63,6 +63,7 @@ type executor struct {
 	publisher    event.Publisher
 	eventCache   *event.Cache
 	logger       *logging.Logger
+	vmOptions    []func(*evm.VM)
 }
 
 var _ BatchExecutor = (*executor)(nil)
@@ -71,18 +72,21 @@ var _ BatchExecutor = (*executor)(nil)
 func NewBatchChecker(state *State,
 	chainID string,
 	tip bcm.Tip,
-	logger *logging.Logger) BatchExecutor {
+	logger *logging.Logger,
+	options ...ExecutionOption) BatchExecutor {
 	return newExecutor(false, state, chainID, tip, event.NewNoOpPublisher(),
-		logger.WithScope("NewBatchExecutor"))
+		logger.WithScope("NewBatchExecutor"), options...)
 }
 
 func NewBatchCommitter(state *State,
 	chainID string,
 	tip bcm.Tip,
 	publisher event.Publisher,
-	logger *logging.Logger) BatchCommitter {
+	logger *logging.Logger,
+	options ...ExecutionOption) BatchCommitter {
+
 	return newExecutor(true, state, chainID, tip, publisher,
-		logger.WithScope("NewBatchCommitter"))
+		logger.WithScope("NewBatchCommitter"), options...)
 }
 
 func newExecutor(runCall bool,
@@ -90,8 +94,9 @@ func newExecutor(runCall bool,
 	chainID string,
 	tip bcm.Tip,
 	eventFireable event.Publisher,
-	logger *logging.Logger) *executor {
-	return &executor{
+	logger *logging.Logger,
+	options ...ExecutionOption) *executor {
+	exe := &executor{
 		chainID:      chainID,
 		tip:          tip,
 		runCall:      runCall,
@@ -102,6 +107,10 @@ func newExecutor(runCall bool,
 		eventCache:   event.NewEventCache(eventFireable),
 		logger:       logger.With(structure.ComponentKey, "Executor"),
 	}
+	for _, option := range options {
+		option(exe)
+	}
+	return exe
 }
 
 // Accounts
@@ -398,8 +407,7 @@ func (exe *executor) Execute(tx txs.Tx) (err error) {
 				// Write caller/callee to txCache.
 				txCache.UpdateAccount(caller)
 				txCache.UpdateAccount(callee)
-				vmach := evm.NewVM(txCache, evm.DefaultDynamicMemoryProvider, params, caller.Address(),
-					tx.Hash(exe.chainID), logger)
+				vmach := evm.NewVM(txCache, params, caller.Address(), tx.Hash(exe.chainID), logger, exe.vmOptions...)
 				vmach.SetPublisher(exe.eventCache)
 				// NOTE: Call() transfers the value from caller to callee iff call succeeds.
 				ret, err = vmach.Call(caller, callee, code, tx.Data, value, &gas)
diff --git a/execution/options.go b/execution/options.go
new file mode 100644
index 0000000000000000000000000000000000000000..8b6e458b890a5ce9dd1e07e24b0806634541b77f
--- /dev/null
+++ b/execution/options.go
@@ -0,0 +1,11 @@
+package execution
+
+import "github.com/hyperledger/burrow/execution/evm"
+
+type ExecutionOption func(*executor)
+
+func VMOptions(vmOptions ...func(*evm.VM)) func(*executor) {
+	return func(exe *executor) {
+		exe.vmOptions = vmOptions
+	}
+}
diff --git a/execution/transactor.go b/execution/transactor.go
index 31e1971cf45896d13fa9d9a80b4f3bfe87af2e3e..f3d06582f108e383b8ca7b11a7ca098d938adbdd 100644
--- a/execution/transactor.go
+++ b/execution/transactor.go
@@ -102,8 +102,7 @@ func (trans *transactor) Call(fromAddress, toAddress acm.Address, data []byte) (
 	txCache := acm.NewStateCache(trans.state)
 	params := vmParams(trans.blockchain)
 
-	vmach := evm.NewVM(txCache, evm.DefaultDynamicMemoryProvider, params, caller.Address(), nil,
-		trans.logger.WithScope("Call"))
+	vmach := evm.NewVM(txCache, params, caller.Address(), nil, trans.logger.WithScope("Call"))
 	vmach.SetPublisher(trans.eventEmitter)
 
 	gas := params.GasLimit
@@ -129,8 +128,7 @@ func (trans *transactor) CallCode(fromAddress acm.Address, code, data []byte) (*
 	txCache := acm.NewStateCache(trans.state)
 	params := vmParams(trans.blockchain)
 
-	vmach := evm.NewVM(txCache, evm.DefaultDynamicMemoryProvider, params, caller.Address(), nil,
-		trans.logger.WithScope("CallCode"))
+	vmach := evm.NewVM(txCache, params, caller.Address(), nil, trans.logger.WithScope("CallCode"))
 	gas := params.GasLimit
 	ret, err := vmach.Call(caller, callee, code, data, 0, &gas)
 	if err != nil {
diff --git a/logging/config/config.go b/logging/config/config.go
index 9eba4085bbb8a47a0cabd45f003e548690541a8d..dca01d2ed6049399c11a7f1d251c9a71afa874e8 100644
--- a/logging/config/config.go
+++ b/logging/config/config.go
@@ -9,10 +9,12 @@ import (
 	"encoding/json"
 
 	"github.com/BurntSushi/toml"
+	"github.com/hyperledger/burrow/logging/loggers"
 )
 
 type LoggingConfig struct {
-	RootSink *SinkConfig `toml:",omitempty"`
+	RootSink     *SinkConfig `toml:",omitempty"`
+	ExcludeTrace bool
 }
 
 // For encoding a top-level '[logging]' TOML table
@@ -22,7 +24,7 @@ type LoggingConfigWrapper struct {
 
 func DefaultNodeLoggingConfig() *LoggingConfig {
 	return &LoggingConfig{
-		RootSink: Sink().SetOutput(StderrOutput()),
+		RootSink: Sink().SetOutput(StderrOutput().SetFormat(loggers.JSONFormat)),
 	}
 }
 
@@ -53,28 +55,6 @@ func (lc *LoggingConfig) JSONString() string {
 	return JSONString(lc)
 }
 
-func LoggingConfigFromMap(loggingRootMap map[string]interface{}) (*LoggingConfig, error) {
-	lc := new(LoggingConfig)
-	buf := new(bytes.Buffer)
-	enc := toml.NewEncoder(buf)
-	// TODO: [Silas] consider using strongly typed config/struct mapping everywhere
-	// (!! unfortunately the way we are using viper
-	// to pass around a untyped bag of config means that we don't get keys mapped
-	// according to their metadata `toml:"Name"` tags. So we are re-encoding to toml
-	// and then decoding into the strongly type struct as a work-around)
-	// Encode the map back to TOML
-	err := enc.Encode(loggingRootMap)
-	if err != nil {
-		return nil, err
-	}
-	// Decode into struct into the LoggingConfig struct
-	_, err = toml.Decode(buf.String(), lc)
-	if err != nil {
-		return nil, err
-	}
-	return lc, nil
-}
-
 func TOMLString(v interface{}) string {
 	buf := new(bytes.Buffer)
 	encoder := toml.NewEncoder(buf)
diff --git a/logging/lifecycle/lifecycle.go b/logging/lifecycle/lifecycle.go
index 4a88f03413391e9fdca6ddc2fb5a96985d914592..d130904c2e5b9f2bf3d21aaadd1edda29409eadb 100644
--- a/logging/lifecycle/lifecycle.go
+++ b/logging/lifecycle/lifecycle.go
@@ -47,11 +47,14 @@ func NewLoggerFromLoggingConfig(loggingConfig *config.LoggingConfig) (*logging.L
 			return nil, err
 		}
 	} else {
-		outputLogger, err := infoTraceLoggerFromLoggingConfig(loggingConfig)
+		outputLogger, err := loggerFromLoggingConfig(loggingConfig)
 		if err != nil {
 			return nil, err
 		}
 		logger, errCh = NewLogger(outputLogger)
+		if loggingConfig.ExcludeTrace {
+			logger.Trace = kitlog.NewNopLogger()
+		}
 	}
 	go func() {
 		err := <-errCh.Out()
@@ -66,7 +69,7 @@ func NewLoggerFromLoggingConfig(loggingConfig *config.LoggingConfig) (*logging.L
 // Hot swap logging config by replacing output loggers of passed InfoTraceLogger
 // with those built from loggingConfig
 func SwapOutputLoggersFromLoggingConfig(logger *logging.Logger, loggingConfig *config.LoggingConfig) error {
-	outputLogger, err := infoTraceLoggerFromLoggingConfig(loggingConfig)
+	outputLogger, err := loggerFromLoggingConfig(loggingConfig)
 	if err != nil {
 		return err
 	}
@@ -105,7 +108,7 @@ func CaptureStdlibLogOutput(infoTraceLogger *logging.Logger) {
 }
 
 // Helpers
-func infoTraceLoggerFromLoggingConfig(loggingConfig *config.LoggingConfig) (kitlog.Logger, error) {
+func loggerFromLoggingConfig(loggingConfig *config.LoggingConfig) (kitlog.Logger, error) {
 	outputLogger, _, err := loggingConfig.RootSink.BuildLogger()
 	if err != nil {
 		return nil, err
diff --git a/logging/logger.go b/logging/logger.go
index 995c60f1dcbea261833a2d40522d711de5a779cd..51346c4f18d34ebd7c60603ee562afbf724c2509 100644
--- a/logging/logger.go
+++ b/logging/logger.go
@@ -144,10 +144,6 @@ func Msg(logger kitlog.Logger, message string, keyvals ...interface{}) error {
 // Wrap the output loggers with a a set of standard transforms, a non-blocking
 // ChannelLogger and an outer context
 func wrapOutputLogger(outputLogger kitlog.Logger) (kitlog.Logger, channels.Channel) {
-	//return outputLogger, channels.NewDeadChannel()
-	return loggers.NonBlockingLogger(loggers.BurrowFormatLogger(outputLogger))
-	//return NonBlockingLogger(VectorValuedLogger(SortLogger(BurrowFormatLogger(outputLogger),
-	//	structure.ChannelKey, structure.MessageKey, structure.TimeKey, structure.ComponentKey)))
-	//return VectorValuedLogger(SortLogger(BurrowFormatLogger(outputLogger),
-	//	structure.ChannelKey, structure.MessageKey, structure.TimeKey, structure.ComponentKey)), channels.NewDeadChannel()
+	//return loggers.NonBlockingLogger(loggers.BurrowFormatLogger(outputLogger))
+	return loggers.BurrowFormatLogger(outputLogger), channels.NewDeadChannel()
 }
diff --git a/process/process.go b/process/process.go
index 960f5b7ef3579ef2e13250cade835a234c220363..b0058d280388146feeda2b251cc3c2ea2bde3e43 100644
--- a/process/process.go
+++ b/process/process.go
@@ -18,8 +18,9 @@ func (sf ShutdownFunc) Shutdown(ctx context.Context) error {
 }
 
 type Launcher struct {
-	Name   string
-	Launch func() (Process, error)
+	Name     string
+	Disabled bool
+	Launch   func() (Process, error)
 }
 
 type listenersServer struct {
diff --git a/rpc/config.go b/rpc/config.go
index 0b35c840b6be1d3f7191272f9cab469126c769cd..89936dec7e18fd410ef853d82da6226a2e24b174 100644
--- a/rpc/config.go
+++ b/rpc/config.go
@@ -3,22 +3,31 @@ package rpc
 import "github.com/hyperledger/burrow/rpc/v0/server"
 
 type RPCConfig struct {
-	V0 *V0Config `json:",omitempty" toml:",omitempty"`
-	TM *TMConfig `json:",omitempty" toml:",omitempty"`
+	V0       *V0Config       `json:",omitempty" toml:",omitempty"`
+	TM       *TMConfig       `json:",omitempty" toml:",omitempty"`
+	Profiler *ProfilerConfig `json:",omitempty" toml:",omitempty"`
 }
 
 type TMConfig struct {
+	Disabled      bool
 	ListenAddress string
 }
 
 type V0Config struct {
-	Server *server.ServerConfig
+	Disabled bool
+	Server   *server.ServerConfig
+}
+
+type ProfilerConfig struct {
+	Disabled      bool
+	ListenAddress string
 }
 
 func DefaultRPCConfig() *RPCConfig {
 	return &RPCConfig{
-		TM: DefaultTMConfig(),
-		V0: DefaultV0Config(),
+		TM:       DefaultTMConfig(),
+		V0:       DefaultV0Config(),
+		Profiler: DefaultProfilerConfig(),
 	}
 }
 func DefaultV0Config() *V0Config {
@@ -32,3 +41,10 @@ func DefaultTMConfig() *TMConfig {
 		ListenAddress: ":46657",
 	}
 }
+
+func DefaultProfilerConfig() *ProfilerConfig {
+	return &ProfilerConfig{
+		Disabled:      true,
+		ListenAddress: ":6060",
+	}
+}
diff --git a/rpc/tm/integration/shared.go b/rpc/tm/integration/shared.go
index a84ed02d27ceecdf6ea693a068c89dd5be7508a8..2849634c4418dd5e1219ca256fe8c7ac93bbc037 100644
--- a/rpc/tm/integration/shared.go
+++ b/rpc/tm/integration/shared.go
@@ -107,7 +107,8 @@ func TestWrapper(runner func() int) int {
 
 	privValidator := validator.NewPrivValidatorMemory(privateAccounts[0], privateAccounts[0])
 	genesisDoc = testGenesisDoc()
-	kernel, err := core.NewKernel(context.Background(), privValidator, genesisDoc, tmConf, rpc.DefaultRPCConfig(), logger)
+	kernel, err := core.NewKernel(context.Background(), privValidator, genesisDoc, tmConf, rpc.DefaultRPCConfig(),
+		nil, logger)
 	if err != nil {
 		panic(err)
 	}