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) }