| 
									
										
										
										
											2015-07-07 02:54:22 +02:00
										 |  |  | // Copyright 2015 The go-ethereum Authors | 
					
						
							|  |  |  | // This file is part of go-ethereum. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // go-ethereum is free software: you can redistribute it and/or modify | 
					
						
							|  |  |  | // it under the terms of the GNU General Public License as published by | 
					
						
							|  |  |  | // the Free Software Foundation, either version 3 of the License, or | 
					
						
							|  |  |  | // (at your option) any later version. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // go-ethereum is distributed in the hope that it will be useful, | 
					
						
							|  |  |  | // but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							| 
									
										
										
										
											2015-07-22 18:48:40 +02:00
										 |  |  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 
					
						
							| 
									
										
										
										
											2015-07-07 02:54:22 +02:00
										 |  |  | // GNU General Public License for more details. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // You should have received a copy of the GNU General Public License | 
					
						
							| 
									
										
										
										
											2015-07-22 18:48:40 +02:00
										 |  |  | // along with go-ethereum. If not, see <http://www.gnu.org/licenses/>. | 
					
						
							| 
									
										
										
										
											2015-01-05 17:38:39 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | // rlpdump is a pretty-printer for RLP data. | 
					
						
							| 
									
										
										
										
											2015-01-05 13:30:58 +01:00
										 |  |  | package main | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							| 
									
										
										
										
											2021-10-18 13:38:00 +02:00
										 |  |  | 	"bufio" | 
					
						
							| 
									
										
										
										
											2015-01-05 13:30:58 +01:00
										 |  |  | 	"bytes" | 
					
						
							| 
									
										
										
										
											2021-10-18 13:38:00 +02:00
										 |  |  | 	"container/list" | 
					
						
							| 
									
										
										
										
											2015-01-05 13:30:58 +01:00
										 |  |  | 	"encoding/hex" | 
					
						
							|  |  |  | 	"flag" | 
					
						
							|  |  |  | 	"fmt" | 
					
						
							|  |  |  | 	"io" | 
					
						
							|  |  |  | 	"os" | 
					
						
							|  |  |  | 	"strings" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-18 13:38:00 +02:00
										 |  |  | 	"github.com/ethereum/go-ethereum/common" | 
					
						
							| 
									
										
										
										
											2015-01-05 13:30:58 +01:00
										 |  |  | 	"github.com/ethereum/go-ethereum/rlp" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var ( | 
					
						
							| 
									
										
										
										
											2021-10-18 13:38:00 +02:00
										 |  |  | 	hexMode     = flag.String("hex", "", "dump given hex data") | 
					
						
							|  |  |  | 	reverseMode = flag.Bool("reverse", false, "convert ASCII to rlp") | 
					
						
							|  |  |  | 	noASCII     = flag.Bool("noascii", false, "don't print ASCII strings readably") | 
					
						
							|  |  |  | 	single      = flag.Bool("single", false, "print only the first element, discard the rest") | 
					
						
							| 
									
										
										
										
											2015-01-05 13:30:58 +01:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func init() { | 
					
						
							|  |  |  | 	flag.Usage = func() { | 
					
						
							| 
									
										
										
										
											2021-10-18 13:38:00 +02:00
										 |  |  | 		fmt.Fprintln(os.Stderr, "Usage:", os.Args[0], "[-noascii] [-hex <data>][-reverse] [filename]") | 
					
						
							| 
									
										
										
										
											2015-01-05 13:30:58 +01:00
										 |  |  | 		flag.PrintDefaults() | 
					
						
							|  |  |  | 		fmt.Fprintln(os.Stderr, ` | 
					
						
							|  |  |  | Dumps RLP data from the given file in readable form. | 
					
						
							|  |  |  | If the filename is omitted, data is read from stdin.`) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func main() { | 
					
						
							|  |  |  | 	flag.Parse() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var r io.Reader | 
					
						
							|  |  |  | 	switch { | 
					
						
							|  |  |  | 	case *hexMode != "": | 
					
						
							| 
									
										
										
										
											2017-10-27 09:40:52 +01:00
										 |  |  | 		data, err := hex.DecodeString(strings.TrimPrefix(*hexMode, "0x")) | 
					
						
							| 
									
										
										
										
											2015-01-05 13:30:58 +01:00
										 |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			die(err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		r = bytes.NewReader(data) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	case flag.NArg() == 0: | 
					
						
							|  |  |  | 		r = os.Stdin | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	case flag.NArg() == 1: | 
					
						
							|  |  |  | 		fd, err := os.Open(flag.Arg(0)) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			die(err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		defer fd.Close() | 
					
						
							| 
									
										
										
										
											2015-01-05 17:42:20 +01:00
										 |  |  | 		r = fd | 
					
						
							| 
									
										
										
										
											2015-01-05 13:30:58 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	default: | 
					
						
							|  |  |  | 		fmt.Fprintln(os.Stderr, "Error: too many arguments") | 
					
						
							|  |  |  | 		flag.Usage() | 
					
						
							|  |  |  | 		os.Exit(2) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-10-18 13:38:00 +02:00
										 |  |  | 	out := os.Stdout | 
					
						
							|  |  |  | 	if *reverseMode { | 
					
						
							|  |  |  | 		data, err := textToRlp(r) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			die(err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		fmt.Printf("0x%x\n", data) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		err := rlpToText(r, out) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			die(err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2015-01-05 13:30:58 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-18 13:38:00 +02:00
										 |  |  | func rlpToText(r io.Reader, out io.Writer) error { | 
					
						
							| 
									
										
										
										
											2015-03-23 15:08:29 +01:00
										 |  |  | 	s := rlp.NewStream(r, 0) | 
					
						
							| 
									
										
										
										
											2015-01-05 13:30:58 +01:00
										 |  |  | 	for { | 
					
						
							| 
									
										
										
										
											2021-10-18 13:38:00 +02:00
										 |  |  | 		if err := dump(s, 0, out); err != nil { | 
					
						
							| 
									
										
										
										
											2015-01-05 13:30:58 +01:00
										 |  |  | 			if err != io.EOF { | 
					
						
							| 
									
										
										
										
											2021-10-18 13:38:00 +02:00
										 |  |  | 				return err | 
					
						
							| 
									
										
										
										
											2015-01-05 13:30:58 +01:00
										 |  |  | 			} | 
					
						
							|  |  |  | 			break | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2021-10-18 13:38:00 +02:00
										 |  |  | 		fmt.Fprintln(out) | 
					
						
							| 
									
										
										
										
											2017-04-12 14:27:34 +03:00
										 |  |  | 		if *single { | 
					
						
							|  |  |  | 			break | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-01-05 13:30:58 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-10-18 13:38:00 +02:00
										 |  |  | 	return nil | 
					
						
							| 
									
										
										
										
											2015-01-05 13:30:58 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-18 13:38:00 +02:00
										 |  |  | func dump(s *rlp.Stream, depth int, out io.Writer) error { | 
					
						
							| 
									
										
										
										
											2015-01-05 13:30:58 +01:00
										 |  |  | 	kind, size, err := s.Kind() | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	switch kind { | 
					
						
							|  |  |  | 	case rlp.Byte, rlp.String: | 
					
						
							|  |  |  | 		str, err := s.Bytes() | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if len(str) == 0 || !*noASCII && isASCII(str) { | 
					
						
							| 
									
										
										
										
											2021-10-18 13:38:00 +02:00
										 |  |  | 			fmt.Fprintf(out, "%s%q", ws(depth), str) | 
					
						
							| 
									
										
										
										
											2015-01-05 13:30:58 +01:00
										 |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2021-10-18 13:38:00 +02:00
										 |  |  | 			fmt.Fprintf(out, "%s%x", ws(depth), str) | 
					
						
							| 
									
										
										
										
											2015-01-05 13:30:58 +01:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	case rlp.List: | 
					
						
							|  |  |  | 		s.List() | 
					
						
							|  |  |  | 		defer s.ListEnd() | 
					
						
							|  |  |  | 		if size == 0 { | 
					
						
							| 
									
										
										
										
											2021-10-18 13:38:00 +02:00
										 |  |  | 			fmt.Fprintf(out, ws(depth)+"[]") | 
					
						
							| 
									
										
										
										
											2015-01-05 13:30:58 +01:00
										 |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2021-10-18 13:38:00 +02:00
										 |  |  | 			fmt.Fprintln(out, ws(depth)+"[") | 
					
						
							| 
									
										
										
										
											2015-01-05 13:30:58 +01:00
										 |  |  | 			for i := 0; ; i++ { | 
					
						
							|  |  |  | 				if i > 0 { | 
					
						
							| 
									
										
										
										
											2021-10-18 13:38:00 +02:00
										 |  |  | 					fmt.Fprint(out, ",\n") | 
					
						
							| 
									
										
										
										
											2015-01-05 13:30:58 +01:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2021-10-18 13:38:00 +02:00
										 |  |  | 				if err := dump(s, depth+1, out); err == rlp.EOL { | 
					
						
							| 
									
										
										
										
											2015-01-05 13:30:58 +01:00
										 |  |  | 					break | 
					
						
							|  |  |  | 				} else if err != nil { | 
					
						
							|  |  |  | 					return err | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2021-10-18 13:38:00 +02:00
										 |  |  | 			fmt.Fprint(out, ws(depth)+"]") | 
					
						
							| 
									
										
										
										
											2015-01-05 13:30:58 +01:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func isASCII(b []byte) bool { | 
					
						
							|  |  |  | 	for _, c := range b { | 
					
						
							|  |  |  | 		if c < 32 || c > 126 { | 
					
						
							|  |  |  | 			return false | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return true | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func ws(n int) string { | 
					
						
							|  |  |  | 	return strings.Repeat("  ", n) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func die(args ...interface{}) { | 
					
						
							|  |  |  | 	fmt.Fprintln(os.Stderr, args...) | 
					
						
							|  |  |  | 	os.Exit(1) | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2021-10-18 13:38:00 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | // textToRlp converts text into RLP (best effort). | 
					
						
							|  |  |  | func textToRlp(r io.Reader) ([]byte, error) { | 
					
						
							|  |  |  | 	// We're expecting the input to be well-formed, meaning that | 
					
						
							|  |  |  | 	// - each element is on a separate line | 
					
						
							|  |  |  | 	// - each line is either an (element OR a list start/end) + comma | 
					
						
							|  |  |  | 	// - an element is either hex-encoded bytes OR a quoted string | 
					
						
							|  |  |  | 	var ( | 
					
						
							|  |  |  | 		scanner = bufio.NewScanner(r) | 
					
						
							|  |  |  | 		obj     []interface{} | 
					
						
							|  |  |  | 		stack   = list.New() | 
					
						
							|  |  |  | 	) | 
					
						
							|  |  |  | 	for scanner.Scan() { | 
					
						
							|  |  |  | 		t := strings.TrimSpace(scanner.Text()) | 
					
						
							|  |  |  | 		if len(t) == 0 { | 
					
						
							|  |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		switch t { | 
					
						
							|  |  |  | 		case "[": // list start | 
					
						
							|  |  |  | 			stack.PushFront(obj) | 
					
						
							|  |  |  | 			obj = make([]interface{}, 0) | 
					
						
							|  |  |  | 		case "]", "],": // list end | 
					
						
							|  |  |  | 			parent := stack.Remove(stack.Front()).([]interface{}) | 
					
						
							|  |  |  | 			obj = append(parent, obj) | 
					
						
							|  |  |  | 		case "[],": // empty list | 
					
						
							|  |  |  | 			obj = append(obj, make([]interface{}, 0)) | 
					
						
							|  |  |  | 		default: // element | 
					
						
							|  |  |  | 			data := []byte(t)[:len(t)-1] // cut off comma | 
					
						
							|  |  |  | 			if data[0] == '"' {          // ascii string | 
					
						
							|  |  |  | 				data = []byte(t)[1 : len(data)-1] | 
					
						
							|  |  |  | 			} else { // hex data | 
					
						
							|  |  |  | 				data = common.FromHex(string(data)) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			obj = append(obj, data) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if err := scanner.Err(); err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	data, err := rlp.EncodeToBytes(obj[0]) | 
					
						
							|  |  |  | 	return data, err | 
					
						
							|  |  |  | } |