github.com/MetalBlockchain/subnet-evm@v0.4.9/trie/encoding.go (about) 1 // (c) 2020-2021, Ava Labs, Inc. 2 // 3 // This file is a derived work, based on the go-ethereum library whose original 4 // notices appear below. 5 // 6 // It is distributed under a license compatible with the licensing terms of the 7 // original code from which it is derived. 8 // 9 // Much love to the original authors for their work. 10 // ********** 11 // Copyright 2014 The go-ethereum Authors 12 // This file is part of the go-ethereum library. 13 // 14 // The go-ethereum library is free software: you can redistribute it and/or modify 15 // it under the terms of the GNU Lesser General Public License as published by 16 // the Free Software Foundation, either version 3 of the License, or 17 // (at your option) any later version. 18 // 19 // The go-ethereum library is distributed in the hope that it will be useful, 20 // but WITHOUT ANY WARRANTY; without even the implied warranty of 21 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 // GNU Lesser General Public License for more details. 23 // 24 // You should have received a copy of the GNU Lesser General Public License 25 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 26 27 package trie 28 29 // Trie keys are dealt with in three distinct encodings: 30 // 31 // KEYBYTES encoding contains the actual key and nothing else. This encoding is the 32 // input to most API functions. 33 // 34 // HEX encoding contains one byte for each nibble of the key and an optional trailing 35 // 'terminator' byte of value 0x10 which indicates whether or not the node at the key 36 // contains a value. Hex key encoding is used for nodes loaded in memory because it's 37 // convenient to access. 38 // 39 // COMPACT encoding is defined by the Ethereum Yellow Paper (it's called "hex prefix 40 // encoding" there) and contains the bytes of the key and a flag. The high nibble of the 41 // first byte contains the flag; the lowest bit encoding the oddness of the length and 42 // the second-lowest encoding whether the node at the key is a value node. The low nibble 43 // of the first byte is zero in the case of an even number of nibbles and the first nibble 44 // in the case of an odd number. All remaining nibbles (now an even number) fit properly 45 // into the remaining bytes. Compact encoding is used for nodes stored on disk. 46 47 func hexToCompact(hex []byte) []byte { 48 terminator := byte(0) 49 if hasTerm(hex) { 50 terminator = 1 51 hex = hex[:len(hex)-1] 52 } 53 buf := make([]byte, len(hex)/2+1) 54 buf[0] = terminator << 5 // the flag byte 55 if len(hex)&1 == 1 { 56 buf[0] |= 1 << 4 // odd flag 57 buf[0] |= hex[0] // first nibble is contained in the first byte 58 hex = hex[1:] 59 } 60 decodeNibbles(hex, buf[1:]) 61 return buf 62 } 63 64 // hexToCompactInPlace places the compact key in input buffer, returning the length 65 // needed for the representation 66 func hexToCompactInPlace(hex []byte) int { 67 var ( 68 hexLen = len(hex) // length of the hex input 69 firstByte = byte(0) 70 ) 71 // Check if we have a terminator there 72 if hexLen > 0 && hex[hexLen-1] == 16 { 73 firstByte = 1 << 5 74 hexLen-- // last part was the terminator, ignore that 75 } 76 var ( 77 binLen = hexLen/2 + 1 78 ni = 0 // index in hex 79 bi = 1 // index in bin (compact) 80 ) 81 if hexLen&1 == 1 { 82 firstByte |= 1 << 4 // odd flag 83 firstByte |= hex[0] // first nibble is contained in the first byte 84 ni++ 85 } 86 for ; ni < hexLen; bi, ni = bi+1, ni+2 { 87 hex[bi] = hex[ni]<<4 | hex[ni+1] 88 } 89 hex[0] = firstByte 90 return binLen 91 } 92 93 func compactToHex(compact []byte) []byte { 94 if len(compact) == 0 { 95 return compact 96 } 97 base := keybytesToHex(compact) 98 // delete terminator flag 99 if base[0] < 2 { 100 base = base[:len(base)-1] 101 } 102 // apply odd flag 103 chop := 2 - base[0]&1 104 return base[chop:] 105 } 106 107 func keybytesToHex(str []byte) []byte { 108 l := len(str)*2 + 1 109 var nibbles = make([]byte, l) 110 for i, b := range str { 111 nibbles[i*2] = b / 16 112 nibbles[i*2+1] = b % 16 113 } 114 nibbles[l-1] = 16 115 return nibbles 116 } 117 118 // hexToKeybytes turns hex nibbles into key bytes. 119 // This can only be used for keys of even length. 120 func hexToKeybytes(hex []byte) []byte { 121 if hasTerm(hex) { 122 hex = hex[:len(hex)-1] 123 } 124 if len(hex)&1 != 0 { 125 panic("can't convert hex key of odd length") 126 } 127 key := make([]byte, len(hex)/2) 128 decodeNibbles(hex, key) 129 return key 130 } 131 132 func decodeNibbles(nibbles []byte, bytes []byte) { 133 for bi, ni := 0, 0; ni < len(nibbles); bi, ni = bi+1, ni+2 { 134 bytes[bi] = nibbles[ni]<<4 | nibbles[ni+1] 135 } 136 } 137 138 // prefixLen returns the length of the common prefix of a and b. 139 func prefixLen(a, b []byte) int { 140 var i, length = 0, len(a) 141 if len(b) < length { 142 length = len(b) 143 } 144 for ; i < length; i++ { 145 if a[i] != b[i] { 146 break 147 } 148 } 149 return i 150 } 151 152 // hasTerm returns whether a hex key has the terminator flag. 153 func hasTerm(s []byte) bool { 154 return len(s) > 0 && s[len(s)-1] == 16 155 }