| 
									
										
										
										
											2015-07-07 02:54:22 +02:00
										 |  |  | // Copyright 2014 The go-ethereum Authors | 
					
						
							| 
									
										
										
										
											2015-07-22 18:48:40 +02:00
										 |  |  | // This file is part of the go-ethereum library. | 
					
						
							| 
									
										
										
										
											2015-07-07 02:54:22 +02:00
										 |  |  | // | 
					
						
							| 
									
										
										
										
											2015-07-23 18:35:11 +02:00
										 |  |  | // The go-ethereum library is free software: you can redistribute it and/or modify | 
					
						
							| 
									
										
										
										
											2015-07-07 02:54:22 +02:00
										 |  |  | // it under the terms of the GNU Lesser General Public License as published by | 
					
						
							|  |  |  | // the Free Software Foundation, either version 3 of the License, or | 
					
						
							|  |  |  | // (at your option) any later version. | 
					
						
							|  |  |  | // | 
					
						
							| 
									
										
										
										
											2015-07-22 18:48:40 +02:00
										 |  |  | // The go-ethereum library is distributed in the hope that it will be useful, | 
					
						
							| 
									
										
										
										
											2015-07-07 02:54:22 +02:00
										 |  |  | // but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							| 
									
										
										
										
											2015-07-22 18:48:40 +02:00
										 |  |  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 
					
						
							| 
									
										
										
										
											2015-07-07 02:54:22 +02:00
										 |  |  | // GNU Lesser General Public License for more details. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // You should have received a copy of the GNU Lesser General Public License | 
					
						
							| 
									
										
										
										
											2015-07-22 18:48:40 +02:00
										 |  |  | // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. | 
					
						
							| 
									
										
										
										
											2015-07-07 02:54:22 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-31 14:45:03 +01:00
										 |  |  | package trie | 
					
						
							| 
									
										
										
										
											2014-02-14 23:56:09 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-06 01:19:48 +02:00
										 |  |  | func compactEncode(hexSlice []byte) []byte { | 
					
						
							|  |  |  | 	terminator := byte(0) | 
					
						
							| 
									
										
										
										
											2014-02-14 23:56:09 +01:00
										 |  |  | 	if hexSlice[len(hexSlice)-1] == 16 { | 
					
						
							|  |  |  | 		terminator = 1 | 
					
						
							|  |  |  | 		hexSlice = hexSlice[:len(hexSlice)-1] | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-07-06 01:19:48 +02:00
										 |  |  | 	var ( | 
					
						
							|  |  |  | 		odd    = byte(len(hexSlice) % 2) | 
					
						
							|  |  |  | 		buflen = len(hexSlice)/2 + 1 | 
					
						
							|  |  |  | 		bi, hi = 0, 0    // indices | 
					
						
							|  |  |  | 		hs     = byte(0) // shift: flips between 0 and 4 | 
					
						
							|  |  |  | 	) | 
					
						
							|  |  |  | 	if odd == 0 { | 
					
						
							|  |  |  | 		bi = 1 | 
					
						
							|  |  |  | 		hs = 4 | 
					
						
							| 
									
										
										
										
											2014-02-14 23:56:09 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-07-06 01:19:48 +02:00
										 |  |  | 	buf := make([]byte, buflen) | 
					
						
							|  |  |  | 	buf[0] = terminator<<5 | byte(odd)<<4 | 
					
						
							|  |  |  | 	for bi < len(buf) && hi < len(hexSlice) { | 
					
						
							|  |  |  | 		buf[bi] |= hexSlice[hi] << hs | 
					
						
							|  |  |  | 		if hs == 0 { | 
					
						
							|  |  |  | 			bi++ | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		hi, hs = hi+1, hs^(1<<2) | 
					
						
							| 
									
										
										
										
											2014-02-14 23:56:09 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-08-06 12:39:07 -04:00
										 |  |  | 	return buf | 
					
						
							| 
									
										
										
										
											2014-02-14 23:56:09 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-06 01:19:48 +02:00
										 |  |  | func compactDecode(str []byte) []byte { | 
					
						
							|  |  |  | 	base := compactHexDecode(str) | 
					
						
							| 
									
										
										
										
											2014-02-14 23:56:09 +01:00
										 |  |  | 	base = base[:len(base)-1] | 
					
						
							| 
									
										
										
										
											2014-02-18 01:34:06 +01:00
										 |  |  | 	if base[0] >= 2 { | 
					
						
							| 
									
										
										
										
											2014-02-14 23:56:09 +01:00
										 |  |  | 		base = append(base, 16) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if base[0]%2 == 1 { | 
					
						
							|  |  |  | 		base = base[1:] | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		base = base[2:] | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return base | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-06 01:19:48 +02:00
										 |  |  | func compactHexDecode(str []byte) []byte { | 
					
						
							| 
									
										
										
										
											2015-08-06 12:39:07 -04:00
										 |  |  | 	l := len(str)*2 + 1 | 
					
						
							|  |  |  | 	var nibbles = make([]byte, l) | 
					
						
							|  |  |  | 	for i, b := range str { | 
					
						
							|  |  |  | 		nibbles[i*2] = b / 16 | 
					
						
							|  |  |  | 		nibbles[i*2+1] = b % 16 | 
					
						
							| 
									
										
										
										
											2014-02-14 23:56:09 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-08-06 12:39:07 -04:00
										 |  |  | 	nibbles[l-1] = 16 | 
					
						
							| 
									
										
										
										
											2015-08-06 03:11:10 -04:00
										 |  |  | 	return nibbles | 
					
						
							| 
									
										
										
										
											2014-02-14 23:56:09 +01:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2014-05-27 01:08:51 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-30 13:34:19 +01:00
										 |  |  | // compactHexEncode encodes a series of nibbles into a byte array | 
					
						
							|  |  |  | func compactHexEncode(nibbles []byte) []byte { | 
					
						
							|  |  |  | 	nl := len(nibbles) | 
					
						
							|  |  |  | 	if nl == 0 { | 
					
						
							|  |  |  | 		return nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if nibbles[nl-1] == 16 { | 
					
						
							|  |  |  | 		nl-- | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	l := (nl + 1) / 2 | 
					
						
							|  |  |  | 	var str = make([]byte, l) | 
					
						
							| 
									
										
										
										
											2017-01-06 15:52:03 +01:00
										 |  |  | 	for i := range str { | 
					
						
							| 
									
										
										
										
											2015-11-30 13:34:19 +01:00
										 |  |  | 		b := nibbles[i*2] * 16 | 
					
						
							|  |  |  | 		if nl > i*2 { | 
					
						
							|  |  |  | 			b += nibbles[i*2+1] | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		str[i] = b | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return str | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-06 01:19:48 +02:00
										 |  |  | func decodeCompact(key []byte) []byte { | 
					
						
							| 
									
										
										
										
											2015-08-06 12:39:07 -04:00
										 |  |  | 	l := len(key) / 2 | 
					
						
							|  |  |  | 	var res = make([]byte, l) | 
					
						
							|  |  |  | 	for i := 0; i < l; i++ { | 
					
						
							|  |  |  | 		v1, v0 := key[2*i], key[2*i+1] | 
					
						
							|  |  |  | 		res[i] = v1*16 + v0 | 
					
						
							| 
									
										
										
										
											2014-05-27 01:08:51 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-08-06 03:11:10 -04:00
										 |  |  | 	return res | 
					
						
							| 
									
										
										
										
											2014-05-27 01:08:51 +02:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2015-07-06 01:19:48 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | // prefixLen returns the length of the common prefix of a and b. | 
					
						
							|  |  |  | func prefixLen(a, b []byte) int { | 
					
						
							|  |  |  | 	var i, length = 0, len(a) | 
					
						
							|  |  |  | 	if len(b) < length { | 
					
						
							|  |  |  | 		length = len(b) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	for ; i < length; i++ { | 
					
						
							|  |  |  | 		if a[i] != b[i] { | 
					
						
							|  |  |  | 			break | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return i | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func hasTerm(s []byte) bool { | 
					
						
							|  |  |  | 	return s[len(s)-1] == 16 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func remTerm(s []byte) []byte { | 
					
						
							|  |  |  | 	if hasTerm(s) { | 
					
						
							|  |  |  | 		b := make([]byte, len(s)-1) | 
					
						
							|  |  |  | 		copy(b, s) | 
					
						
							|  |  |  | 		return b | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return s | 
					
						
							|  |  |  | } |