github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/trie/encoding.go (about)

     1  
     2  //<developer>
     3  //    <name>linapex 曹一峰</name>
     4  //    <email>linapex@163.com</email>
     5  //    <wx>superexc</wx>
     6  //    <qqgroup>128148617</qqgroup>
     7  //    <url>https://jsq.ink</url>
     8  //    <role>pku engineer</role>
     9  //    <date>2019-03-16 19:16:45</date>
    10  //</624450122779987968>
    11  
    12  
    13  package trie
    14  
    15  //trie键有三种不同的编码:
    16  //
    17  //keybytes编码包含实际的密钥,而不包含其他任何内容。此编码是
    18  //大多数API函数的输入。
    19  //
    20  //十六进制编码包含键的每个半字节和可选尾随字节。
    21  //值为0x10的“终止符”字节,指示键处的节点是否
    22  //包含一个值。十六进制键编码用于内存中加载的节点,因为它
    23  //方便进入。
    24  //
    25  //紧凑型编码由以太坊黄纸(称为“十六进制前缀”)定义
    26  //并包含密钥的字节和标志。高尖的
    27  //第一个字节包含标志;编码长度的奇数和
    28  //第二个最低的编码键处的节点是否为值节点。低啃咬
    29  //对于偶数个半字节和第一个半字节,第一个字节的为零。
    30  //如果是奇数。所有剩余的笔尖(现在是偶数)都合适
    31  //到剩余的字节。压缩编码用于存储在磁盘上的节点。
    32  
    33  func hexToCompact(hex []byte) []byte {
    34  	terminator := byte(0)
    35  	if hasTerm(hex) {
    36  		terminator = 1
    37  		hex = hex[:len(hex)-1]
    38  	}
    39  	buf := make([]byte, len(hex)/2+1)
    40  buf[0] = terminator << 5 //标志字节
    41  	if len(hex)&1 == 1 {
    42  buf[0] |= 1 << 4 //奇数旗
    43  buf[0] |= hex[0] //第一个半字节包含在第一个字节中
    44  		hex = hex[1:]
    45  	}
    46  	decodeNibbles(hex, buf[1:])
    47  	return buf
    48  }
    49  
    50  func compactToHex(compact []byte) []byte {
    51  	base := keybytesToHex(compact)
    52  //删除终止符标志
    53  	if base[0] < 2 {
    54  		base = base[:len(base)-1]
    55  	}
    56  //应用奇数旗
    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  //十六进制字节将十六进制字节转换为键字节。
    73  //这只能用于长度均匀的键。
    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)/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返回A和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返回十六进制键是否具有终止符标志。
   107  func hasTerm(s []byte) bool {
   108  	return len(s) > 0 && s[len(s)-1] == 16
   109  }
   110