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