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