trie: fix for range proof (#21107)
* trie: fix for range proof * trie: fix typo
This commit is contained in:
		
							parent
							
								
									81e9caed7d
								
							
						
					
					
						commit
						070a5e1252
					
				| @ -219,54 +219,69 @@ func unsetInternal(n node, left []byte, right []byte) error { | |||||||
| 	if len(left) != len(right) { | 	if len(left) != len(right) { | ||||||
| 		return errors.New("inconsistent edge path") | 		return errors.New("inconsistent edge path") | ||||||
| 	} | 	} | ||||||
| 	// Step down to the fork point
 | 	// Step down to the fork point. There are two scenarios can happen:
 | ||||||
| 	prefix, pos := prefixLen(left, right), 0 | 	// - the fork point is a shortnode: the left proof MUST point to a
 | ||||||
| 	var parent node | 	//   non-existent key and the key doesn't match with the shortnode
 | ||||||
|  | 	// - the fork point is a fullnode: the left proof can point to an
 | ||||||
|  | 	//   existent key or not.
 | ||||||
|  | 	var ( | ||||||
|  | 		pos    = 0 | ||||||
|  | 		parent node | ||||||
|  | 	) | ||||||
|  | findFork: | ||||||
| 	for { | 	for { | ||||||
| 		if pos >= prefix { |  | ||||||
| 			break |  | ||||||
| 		} |  | ||||||
| 		switch rn := (n).(type) { | 		switch rn := (n).(type) { | ||||||
| 		case *shortNode: | 		case *shortNode: | ||||||
|  | 			// The right proof must point to an existent key.
 | ||||||
| 			if len(right)-pos < len(rn.Key) || !bytes.Equal(rn.Key, right[pos:pos+len(rn.Key)]) { | 			if len(right)-pos < len(rn.Key) || !bytes.Equal(rn.Key, right[pos:pos+len(rn.Key)]) { | ||||||
| 				return errors.New("invalid edge path") | 				return errors.New("invalid edge path") | ||||||
| 			} | 			} | ||||||
|  | 			rn.flags = nodeFlag{dirty: true} | ||||||
| 			// Special case, the non-existent proof points to the same path
 | 			// Special case, the non-existent proof points to the same path
 | ||||||
| 			// as the existent proof, but the path of existent proof is longer.
 | 			// as the existent proof, but the path of existent proof is longer.
 | ||||||
| 			// In this case, truncate the extra path(it should be recovered
 | 			// In this case, the fork point is this shortnode.
 | ||||||
| 			// by node insertion).
 |  | ||||||
| 			if len(left)-pos < len(rn.Key) || !bytes.Equal(rn.Key, left[pos:pos+len(rn.Key)]) { | 			if len(left)-pos < len(rn.Key) || !bytes.Equal(rn.Key, left[pos:pos+len(rn.Key)]) { | ||||||
| 				fn := parent.(*fullNode) | 				break findFork | ||||||
| 				fn.Children[left[pos-1]] = nil |  | ||||||
| 				return nil |  | ||||||
| 			} | 			} | ||||||
| 			rn.flags = nodeFlag{dirty: true} |  | ||||||
| 			parent = n | 			parent = n | ||||||
| 			n, pos = rn.Val, pos+len(rn.Key) | 			n, pos = rn.Val, pos+len(rn.Key) | ||||||
| 		case *fullNode: | 		case *fullNode: | ||||||
|  | 			leftnode, rightnode := rn.Children[left[pos]], rn.Children[right[pos]] | ||||||
|  | 			// The right proof must point to an existent key.
 | ||||||
|  | 			if rightnode == nil { | ||||||
|  | 				return errors.New("invalid edge path") | ||||||
|  | 			} | ||||||
| 			rn.flags = nodeFlag{dirty: true} | 			rn.flags = nodeFlag{dirty: true} | ||||||
|  | 			if leftnode != rightnode { | ||||||
|  | 				break findFork | ||||||
|  | 			} | ||||||
| 			parent = n | 			parent = n | ||||||
| 			n, pos = rn.Children[right[pos]], pos+1 | 			n, pos = rn.Children[left[pos]], pos+1 | ||||||
| 		default: | 		default: | ||||||
| 			panic(fmt.Sprintf("%T: invalid node: %v", n, n)) | 			panic(fmt.Sprintf("%T: invalid node: %v", n, n)) | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	fn, ok := n.(*fullNode) | 	switch rn := n.(type) { | ||||||
| 	if !ok { | 	case *shortNode: | ||||||
| 		return errors.New("the fork point must be a fullnode") | 		if _, ok := rn.Val.(valueNode); ok { | ||||||
|  | 			parent.(*fullNode).Children[right[pos-1]] = nil | ||||||
|  | 			return nil | ||||||
| 		} | 		} | ||||||
| 	// Find the fork point! Unset all intermediate references
 | 		return unset(rn, rn.Val, right[pos:], len(rn.Key), true) | ||||||
| 	for i := left[prefix] + 1; i < right[prefix]; i++ { | 	case *fullNode: | ||||||
| 		fn.Children[i] = nil | 		for i := left[pos] + 1; i < right[pos]; i++ { | ||||||
|  | 			rn.Children[i] = nil | ||||||
| 		} | 		} | ||||||
| 	fn.flags = nodeFlag{dirty: true} | 		if err := unset(rn, rn.Children[left[pos]], left[pos:], 1, false); err != nil { | ||||||
| 	if err := unset(fn, fn.Children[left[prefix]], left[prefix:], 1, false); err != nil { |  | ||||||
| 			return err | 			return err | ||||||
| 		} | 		} | ||||||
| 	if err := unset(fn, fn.Children[right[prefix]], right[prefix:], 1, true); err != nil { | 		if err := unset(rn, rn.Children[right[pos]], right[pos:], 1, true); err != nil { | ||||||
| 			return err | 			return err | ||||||
| 		} | 		} | ||||||
| 		return nil | 		return nil | ||||||
|  | 	default: | ||||||
|  | 		panic(fmt.Sprintf("%T: invalid node: %v", n, n)) | ||||||
|  | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // unset removes all internal node references either the left most or right most.
 | // unset removes all internal node references either the left most or right most.
 | ||||||
| @ -314,8 +329,8 @@ func unset(parent node, child node, key []byte, pos int, removeLeft bool) error | |||||||
| 				// The key of fork shortnode is less than the
 | 				// The key of fork shortnode is less than the
 | ||||||
| 				// path(it doesn't belong to the range), keep
 | 				// path(it doesn't belong to the range), keep
 | ||||||
| 				// it with the cached hash available.
 | 				// it with the cached hash available.
 | ||||||
| 				return nil |  | ||||||
| 			} | 			} | ||||||
|  | 			return nil | ||||||
| 		} | 		} | ||||||
| 		if _, ok := cld.Val.(valueNode); ok { | 		if _, ok := cld.Val.(valueNode); ok { | ||||||
| 			fn := parent.(*fullNode) | 			fn := parent.(*fullNode) | ||||||
|  | |||||||
| @ -397,6 +397,7 @@ func TestAllElementsProof(t *testing.T) { | |||||||
| 
 | 
 | ||||||
| // TestSingleSideRangeProof tests the range starts from zero.
 | // TestSingleSideRangeProof tests the range starts from zero.
 | ||||||
| func TestSingleSideRangeProof(t *testing.T) { | func TestSingleSideRangeProof(t *testing.T) { | ||||||
|  | 	for i := 0; i < 64; i++ { | ||||||
| 		trie := new(Trie) | 		trie := new(Trie) | ||||||
| 		var entries entrySlice | 		var entries entrySlice | ||||||
| 		for i := 0; i < 4096; i++ { | 		for i := 0; i < 4096; i++ { | ||||||
| @ -426,6 +427,7 @@ func TestSingleSideRangeProof(t *testing.T) { | |||||||
| 				t.Fatalf("Expected no error, got %v", err) | 				t.Fatalf("Expected no error, got %v", err) | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
|  | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // TestBadRangeProof tests a few cases which the proof is wrong.
 | // TestBadRangeProof tests a few cases which the proof is wrong.
 | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user