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