From 5aa3eac22d80c754d70651a918bccc9b3d1d216f Mon Sep 17 00:00:00 2001 From: jtakalai Date: Thu, 16 Nov 2017 13:14:51 +0200 Subject: [PATCH 1/3] eth/downloader: minor comments cleanup (#15495) it's -> its pet peeve, and I like to imagine I'm not alone. --- eth/downloader/downloader.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/eth/downloader/downloader.go b/eth/downloader/downloader.go index cca4fe7a93..b338129e00 100644 --- a/eth/downloader/downloader.go +++ b/eth/downloader/downloader.go @@ -333,7 +333,7 @@ func (d *Downloader) Synchronise(id string, head common.Hash, td *big.Int, mode } // synchronise will select the peer and use it for synchronising. If an empty string is given -// it will use the best peer possible and synchronize if it's TD is higher than our own. If any of the +// it will use the best peer possible and synchronize if its TD is higher than our own. If any of the // checks fail an error will be returned. This method is synchronous func (d *Downloader) synchronise(id string, hash common.Hash, td *big.Int, mode SyncMode) error { // Mock out the synchronisation if testing @@ -1003,8 +1003,8 @@ func (d *Downloader) fetchParts(errCancel error, deliveryCh chan dataPack, deliv return errCancel case packet := <-deliveryCh: - // If the peer was previously banned and failed to deliver it's pack - // in a reasonable time frame, ignore it's message. + // If the peer was previously banned and failed to deliver its pack + // in a reasonable time frame, ignore its message. if peer := d.peers.Peer(packet.PeerId()); peer != nil { // Deliver the received chunk of data and check chain validity accepted, err := deliver(packet) @@ -1205,8 +1205,8 @@ func (d *Downloader) processHeaders(origin uint64, td *big.Int) error { case <-d.cancelCh: } } - // If no headers were retrieved at all, the peer violated it's TD promise that it had a - // better chain compared to ours. The only exception is if it's promised blocks were + // If no headers were retrieved at all, the peer violated its TD promise that it had a + // better chain compared to ours. The only exception is if its promised blocks were // already imported by other means (e.g. fecher): // // R , L : Both at block 10 From 4013e23312257d79caf4fb5030881d30a62cb618 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Thu, 16 Nov 2017 13:51:06 +0200 Subject: [PATCH 2/3] rpc: allow dumb empty requests for AWS health checks --- rpc/http.go | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/rpc/http.go b/rpc/http.go index 3f572b34c0..2ac9f6c371 100644 --- a/rpc/http.go +++ b/rpc/http.go @@ -146,13 +146,17 @@ func NewHTTPServer(cors []string, srv *Server) *http.Server { // ServeHTTP serves JSON-RPC requests over HTTP. func (srv *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { + // Permit dumb empty requests for remote health-checks (AWS) + if r.Method == "GET" && r.ContentLength == 0 && r.URL.RawQuery == "" { + return + } + // For meaningful requests, validate it's size and content type if r.ContentLength > maxHTTPRequestContentLength { http.Error(w, fmt.Sprintf("content length too large (%d>%d)", r.ContentLength, maxHTTPRequestContentLength), http.StatusRequestEntityTooLarge) return } - ct := r.Header.Get("content-type") mt, _, err := mime.ParseMediaType(ct) if err != nil || mt != "application/json" { @@ -161,14 +165,13 @@ func (srv *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { http.StatusUnsupportedMediaType) return } - - w.Header().Set("content-type", "application/json") - - // create a codec that reads direct from the request body until - // EOF and writes the response to w and order the server to process - // a single request. + // All checks passed, create a codec that reads direct from the request body + // untilEOF and writes the response to w and order the server to process a + // single request. codec := NewJSONCodec(&httpReadWriteNopCloser{r.Body, w}) defer codec.Close() + + w.Header().Set("content-type", "application/json") srv.ServeSingleRequest(codec, OptionMethodInvocation) } From b0190189a386d13eb2e8bbdb6d64d9ef8c0e572a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Thu, 16 Nov 2017 18:53:18 +0200 Subject: [PATCH 3/3] core/vm, internal/ethapi: tracer no full storage, nicer json output (#15499) * core/vm, internal/ethapi: tracer no full storage, nicer json output * core/vm, internal/ethapi: omit disabled trace fields --- core/vm/logger.go | 26 +++---------------- core/vm/logger_test.go | 24 ------------------ internal/ethapi/api.go | 57 ++++++++++++++++++++++++------------------ 3 files changed, 36 insertions(+), 71 deletions(-) diff --git a/core/vm/logger.go b/core/vm/logger.go index 623c0d5632..75309da921 100644 --- a/core/vm/logger.go +++ b/core/vm/logger.go @@ -45,7 +45,6 @@ type LogConfig struct { DisableMemory bool // disable memory capture DisableStack bool // disable stack capture DisableStorage bool // disable storage capture - FullStorage bool // show full storage (slow) Limit int // maximum length of output, but zero means unlimited } @@ -136,14 +135,13 @@ func (l *StructLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost ui ) l.changedValues[contract.Address()][address] = value } - // copy a snapstot of the current memory state to a new buffer + // Copy a snapstot of the current memory state to a new buffer var mem []byte if !l.cfg.DisableMemory { mem = make([]byte, len(memory.Data())) copy(mem, memory.Data()) } - - // copy a snapshot of the current stack state to a new buffer + // Copy a snapshot of the current stack state to a new buffer var stck []*big.Int if !l.cfg.DisableStack { stck = make([]*big.Int, len(stack.Data())) @@ -151,26 +149,10 @@ func (l *StructLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost ui stck[i] = new(big.Int).Set(item) } } - - // Copy the storage based on the settings specified in the log config. If full storage - // is disabled (default) we can use the simple Storage.Copy method, otherwise we use - // the state object to query for all values (slow process). + // Copy a snapshot of the current storage to a new container var storage Storage if !l.cfg.DisableStorage { - if l.cfg.FullStorage { - storage = make(Storage) - // Get the contract account and loop over each storage entry. This may involve looping over - // the trie and is a very expensive process. - - env.StateDB.ForEachStorage(contract.Address(), func(key, value common.Hash) bool { - storage[key] = value - // Return true, indicating we'd like to continue. - return true - }) - } else { - // copy a snapshot of the current storage to a new container. - storage = l.changedValues[contract.Address()].Copy() - } + storage = l.changedValues[contract.Address()].Copy() } // create a new snaptshot of the EVM. log := StructLog{pc, op, gas, cost, mem, memory.Len(), stck, storage, depth, err} diff --git a/core/vm/logger_test.go b/core/vm/logger_test.go index b6fa31132a..915f7177e7 100644 --- a/core/vm/logger_test.go +++ b/core/vm/logger_test.go @@ -63,32 +63,8 @@ func TestStoreCapture(t *testing.T) { if len(logger.changedValues[contract.Address()]) == 0 { t.Fatalf("expected exactly 1 changed value on address %x, got %d", contract.Address(), len(logger.changedValues[contract.Address()])) } - exp := common.BigToHash(big.NewInt(1)) if logger.changedValues[contract.Address()][index] != exp { t.Errorf("expected %x, got %x", exp, logger.changedValues[contract.Address()][index]) } } - -func TestStorageCapture(t *testing.T) { - t.Skip("implementing this function is difficult. it requires all sort of interfaces to be implemented which isn't trivial. The value (the actual test) isn't worth it") - var ( - ref = &dummyContractRef{} - contract = NewContract(ref, ref, new(big.Int), 0) - env = NewEVM(Context{}, dummyStateDB{ref: ref}, params.TestChainConfig, Config{EnableJit: false, ForceJit: false}) - logger = NewStructLogger(nil) - mem = NewMemory() - stack = newstack() - ) - - logger.CaptureState(env, 0, STOP, 0, 0, mem, stack, contract, 0, nil) - if ref.calledForEach { - t.Error("didn't expect for each to be called") - } - - logger = NewStructLogger(&LogConfig{FullStorage: true}) - logger.CaptureState(env, 0, STOP, 0, 0, mem, stack, contract, 0, nil) - if !ref.calledForEach { - t.Error("expected for each to be called") - } -} diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 59a29d7226..cf15d1c71e 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -710,45 +710,52 @@ type ExecutionResult struct { // StructLogRes stores a structured log emitted by the EVM while replaying a // transaction in debug mode type StructLogRes struct { - Pc uint64 `json:"pc"` - Op string `json:"op"` - Gas uint64 `json:"gas"` - GasCost uint64 `json:"gasCost"` - Depth int `json:"depth"` - Error error `json:"error"` - Stack []string `json:"stack"` - Memory []string `json:"memory"` - Storage map[string]string `json:"storage"` + Pc uint64 `json:"pc"` + Op string `json:"op"` + Gas uint64 `json:"gas"` + GasCost uint64 `json:"gasCost"` + Depth int `json:"depth"` + Error error `json:"error,omitempty"` + Stack *[]string `json:"stack,omitempty"` + Memory *[]string `json:"memory,omitempty"` + Storage *map[string]string `json:"storage,omitempty"` } // formatLogs formats EVM returned structured logs for json output -func FormatLogs(structLogs []vm.StructLog) []StructLogRes { - formattedStructLogs := make([]StructLogRes, len(structLogs)) - for index, trace := range structLogs { - formattedStructLogs[index] = StructLogRes{ +func FormatLogs(logs []vm.StructLog) []StructLogRes { + formatted := make([]StructLogRes, len(logs)) + for index, trace := range logs { + formatted[index] = StructLogRes{ Pc: trace.Pc, Op: trace.Op.String(), Gas: trace.Gas, GasCost: trace.GasCost, Depth: trace.Depth, Error: trace.Err, - Stack: make([]string, len(trace.Stack)), - Storage: make(map[string]string), } - - for i, stackValue := range trace.Stack { - formattedStructLogs[index].Stack[i] = fmt.Sprintf("%x", math.PaddedBigBytes(stackValue, 32)) + if trace.Stack != nil { + stack := make([]string, len(trace.Stack)) + for i, stackValue := range trace.Stack { + stack[i] = fmt.Sprintf("%x", math.PaddedBigBytes(stackValue, 32)) + } + formatted[index].Stack = &stack } - - for i := 0; i+32 <= len(trace.Memory); i += 32 { - formattedStructLogs[index].Memory = append(formattedStructLogs[index].Memory, fmt.Sprintf("%x", trace.Memory[i:i+32])) + if trace.Memory != nil { + memory := make([]string, 0, (len(trace.Memory)+31)/32) + for i := 0; i+32 <= len(trace.Memory); i += 32 { + memory = append(memory, fmt.Sprintf("%x", trace.Memory[i:i+32])) + } + formatted[index].Memory = &memory } - - for i, storageValue := range trace.Storage { - formattedStructLogs[index].Storage[fmt.Sprintf("%x", i)] = fmt.Sprintf("%x", storageValue) + if trace.Storage != nil { + storage := make(map[string]string) + for i, storageValue := range trace.Storage { + storage[fmt.Sprintf("%x", i)] = fmt.Sprintf("%x", storageValue) + } + formatted[index].Storage = &storage } } - return formattedStructLogs + return formatted } // rpcOutputBlock converts the given block to the RPC output which depends on fullTx. If inclTx is true transactions are