github.com/gnolang/gno@v0.0.0-20240520182011-228e9d0192ce/tm2/pkg/amino/cmd/aminoscan/aminoscan.go (about) 1 package main 2 3 import ( 4 "encoding/binary" 5 "encoding/hex" 6 "errors" 7 "flag" 8 "fmt" 9 "os" 10 "strconv" 11 "strings" 12 13 amino "github.com/gnolang/gno/tm2/pkg/amino" 14 ) 15 16 func main() { 17 // Print help. 18 if len(os.Args) == 1 { 19 fmt.Println(`Usage: aminoscan <STRUCT HEXBYTES> or --help`) 20 return 21 } 22 23 // Parse flags... 24 var colorize bool 25 flgs := flag.NewFlagSet(os.Args[0], flag.ExitOnError) 26 flgs.BoolVar(&colorize, "color", false, "Just print the colored bytes and exit.") 27 err := flgs.Parse(os.Args[1:]) 28 if errors.Is(err, flag.ErrHelp) { 29 fmt.Println(`Usage: aminoscan <STRUCT HEXBYTES> or --help 30 31 You can also use aminoscan to print "colored" bytes. This view will 32 try to display bytes in ascii in a different color if it happens to be 33 a printable character. 34 35 > aminoscan --color <HEXBYTES>`) 36 return 37 } else if err != nil { 38 fmt.Println(err) 39 return 40 } 41 42 // If we just want to show colored bytes... 43 if colorize { 44 if flgs.Arg(0) == "" { 45 fmt.Println(`Usage: aminoscan --color <HEXBYTES>`) 46 return 47 } 48 bz := hexDecode(flgs.Arg(0)) 49 fmt.Println(ColoredBytes(bz, Green, Blue)) 50 return 51 } 52 53 // Parse struct Amino bytes. 54 bz := hexDecode(os.Args[1]) // Read input hex bytes. 55 fmt.Println(Yellow("## Root Struct (assumed)")) 56 s, n, err := scanStruct(bz, "", true) // Assume that it's struct. 57 s += Red(fmt.Sprintf("%X", bz[n:])) // Bytes remaining are red. 58 fmt.Println(Yellow("## Root Struct END")) 59 fmt.Println(s, n, err) // Print color-encoded bytes s. 60 } 61 62 func scanAny(typ amino.Typ3, bz []byte, indent string) (s string, n int, err error) { 63 switch typ { 64 case amino.Typ3Varint: 65 s, n, err = scanVarint(bz, indent) 66 case amino.Typ38Byte: 67 s, n, err = scan8Byte(bz, indent) 68 case amino.Typ3ByteLength: 69 s, n, err = scanByteLength(bz, indent) 70 case amino.Typ34Byte: 71 s, n, err = scan4Byte(bz, indent) 72 default: 73 panic("should not happen") 74 } 75 return 76 } 77 78 func scanVarint(bz []byte, indent string) (s string, n int, err error) { 79 if len(bz) == 0 { 80 err = fmt.Errorf("EOF while reading (U)Varint") 81 } 82 // First try Varint. 83 okI64 := true 84 i64, n := binary.Varint(bz) 85 if n <= 0 { 86 n = 0 87 okI64 = false 88 } 89 // Then try Uvarint. 90 okU64 := true 91 u64, _n := binary.Uvarint(bz) 92 if n != _n { 93 n = 0 94 okU64 = false 95 } 96 // If neither work, return error. 97 if !okI64 && !okU64 { 98 err = fmt.Errorf("invalid (u)varint") 99 return 100 } 101 // s is the same either way. 102 s = Cyan(fmt.Sprintf("%X", bz[:n])) 103 fmt.Printf("%s%s (", indent, s) 104 if okI64 { 105 fmt.Printf("i64:%v ", i64) 106 } 107 if okU64 { 108 fmt.Printf("u64:%v", u64) 109 } 110 fmt.Print(")\n") 111 return s, n, err 112 } 113 114 func scan8Byte(bz []byte, indent string) (s string, n int, err error) { 115 if len(bz) < 8 { 116 err = errors.New("while reading 8byte field, EOF was encountered") 117 return 118 } 119 n = 8 120 s = Blue(fmt.Sprintf("%X", bz[:8])) 121 fmt.Printf("%s%s\n", indent, s) 122 return 123 } 124 125 func scanByteLength(bz []byte, indent string) (s string, n int, err error) { 126 // Read the length. 127 l64, _n := binary.Uvarint(bz) 128 if n < 0 { 129 n = 0 130 err = errors.New("error decoding uvarint") 131 return 132 } 133 length := int(l64) 134 if length >= len(bz) { 135 err = errors.New("while reading 8byte field, EOF was encountered") 136 return 137 } 138 lengthStrLong := fmt.Sprintf("%X (%v bytes) ", bz[:_n], length) 139 lengthStrLongLen := len(lengthStrLong) // for indenting later 140 lengthStrShort := fmt.Sprintf("%X", bz[:_n]) 141 s = Cyan(lengthStrShort) 142 slide(&bz, &n, _n) 143 // Read the remaining bytes. 144 contents := bz[:length] 145 contentsStr := fmt.Sprintf("%X", contents) 146 s += Green(contentsStr) 147 slide(&bz, &n, length) 148 fmt.Printf("%s%s%s\n", indent, Cyan(lengthStrLong), Green(contentsStr)) 149 // If ascii string, also show the string in quotes. 150 if amino.IsASCIIText(string(contents)) { 151 fmt.Printf("%s%s\n", indent+strings.Repeat(" ", lengthStrLongLen), Green("("+strconv.Quote(string(contents))+" in ASCII)")) 152 } 153 return 154 } 155 156 func scanStruct(bz []byte, indent string, isRoot bool) (s string, n int, err error) { 157 var ( 158 _s string 159 _n int 160 typ amino.Typ3 161 ) 162 for { 163 if isRoot && len(bz) == 0 { 164 return 165 } 166 _s, typ, _n, err = scanFieldKey(bz, indent+" ") 167 if slide(&bz, &n, _n) && concat(&s, _s) && err != nil { 168 return 169 } 170 _s, _n, err = scanAny(typ, bz, indent+" ") 171 if slide(&bz, &n, _n) && concat(&s, _s) && err != nil { 172 return 173 } 174 } 175 } 176 177 func scanFieldKey(bz []byte, indent string) (s string, typ amino.Typ3, n int, err error) { 178 var u64 uint64 179 u64, n = binary.Uvarint(bz) 180 if n < 0 { 181 n = 0 182 err = errors.New("error decoding uvarint") 183 return 184 } 185 typ = amino.Typ3(u64 & 0x07) 186 number := uint32(u64 >> 3) 187 s = fmt.Sprintf("%X", bz[:n]) 188 fmt.Printf("%s%s @%v %v\n", indent, s, number, typ) 189 return 190 } 191 192 func scan4Byte(bz []byte, indent string) (s string, n int, err error) { 193 if len(bz) < 4 { 194 err = errors.New("while reading 8byte field, EOF was encountered") 195 return 196 } 197 n = 4 198 s = Blue(fmt.Sprintf("%X", bz[:4])) 199 fmt.Printf("%s%s\n", indent, s) 200 return 201 } 202 203 /* 204 func scanList(bz []byte, indent string) (s string, n int, err error) { 205 // Read element Typ4. 206 if len(bz) < 1 { 207 err = errors.New("EOF while reading list element typ4.") 208 return 209 } 210 var typ = amino.Typ4(bz[0]) 211 if typ&0xF0 > 0 { 212 err = errors.New("Invalid list element typ4 byte") 213 } 214 s = fmt.Sprintf("%X", bz[:1]) 215 if slide(&bz, &n, 1) && err != nil { 216 return 217 } 218 // Read number of elements. 219 var num, _n = uint64(0), int(0) 220 num, _n = binary.Uvarint(bz) 221 if _n < 0 { 222 _n = 0 223 err = errors.New("error decoding list length (uvarint)") 224 } 225 s += Cyan(fmt.Sprintf("%X", bz[:_n])) 226 if slide(&bz, &n, _n) && err != nil { 227 return 228 } 229 fmt.Printf("%s%s of %v with %v items\n", indent, s, typ, num) 230 // Read elements. 231 var _s string 232 for i := 0; i < int(num); i++ { 233 // Maybe read nil byte. 234 if typ&0x08 != 0 { 235 if len(bz) == 0 { 236 err = errors.New("EOF while reading list nil byte") 237 return 238 } 239 var nb = bz[0] 240 slide(&bz, &n, 1) 241 switch nb { 242 case 0x00: 243 s += "00" 244 fmt.Printf("%s00 (not nil)\n", indent) 245 case 0x01: 246 s += "01" // Is nil (NOTE: reverse logic) 247 fmt.Printf("%s01 (is nil)\n", indent) 248 continue 249 default: 250 err = fmt.Errorf("Unexpected nil pointer byte %X", nb) 251 return 252 } 253 } 254 // Read element. 255 _s, _n, err = scanAny(typ.Typ3(), bz, indent+" ") 256 if slide(&bz, &n, _n) && concat(&s, _s) && err != nil { 257 return 258 } 259 } 260 return 261 } 262 */ 263 264 /* 265 func scanInterface(bz []byte, indent string) (s string, n int, err error) { 266 db, hasDb, pb, typ, _, isNil, _n, err := amino.DecodeDisambPrefixBytes(bz) 267 if slide(&bz, &n, _n) && err != nil { 268 return 269 } 270 pb3 := pb 271 if isNil { 272 s = Magenta("0000") 273 } else if hasDb { 274 s = Magenta(fmt.Sprintf("%X%X", db.Bytes(), pb3.Bytes())) 275 } else { 276 s = Magenta(fmt.Sprintf("%X", pb3.Bytes())) 277 } 278 if isNil { 279 fmt.Printf("%s%s (nil interface)\n", indent, s) 280 } else if hasDb { 281 fmt.Printf("%s%s (disamb: %X, prefix: %X, typ: %v)\n", 282 indent, s, db.Bytes(), pb.Bytes(), typ) 283 } else { 284 fmt.Printf("%s%s (prefix: %X, typ: %v)\n", 285 indent, s, pb.Bytes(), typ) 286 } 287 _s, _n, err := scanAny(typ, bz, indent) 288 if slide(&bz, &n, _n) && concat(&s, _s) && err != nil { 289 return 290 } 291 return 292 } 293 */ 294 295 //---------------------------------------- 296 // Misc. 297 298 func slide(bzPtr *[]byte, n *int, _n int) bool { 299 if len(*bzPtr) < _n { 300 panic("eof") 301 } 302 *bzPtr = (*bzPtr)[_n:] 303 *n += _n 304 return true 305 } 306 307 func concat(sPtr *string, _s string) bool { 308 *sPtr += _s 309 return true 310 } 311 312 func hexDecode(s string) []byte { 313 bz, err := hex.DecodeString(s) 314 if err != nil { 315 panic(err) 316 } 317 return bz 318 }