|
17 | 17 | package trie |
18 | 18 |
|
19 | 19 | import ( |
| 20 | + "bytes" |
20 | 21 | "fmt" |
21 | 22 | "io" |
22 | 23 | "strings" |
@@ -242,6 +243,74 @@ func decodeRef(buf []byte) (node, []byte, error) { |
242 | 243 | } |
243 | 244 | } |
244 | 245 |
|
| 246 | +// decodeNodeElements parses the RLP encoding of a trie node and returns all the |
| 247 | +// elements in raw byte format. |
| 248 | +// |
| 249 | +// For full node, it returns a slice of 17 elements; |
| 250 | +// For short node, it returns a slice of 2 elements; |
| 251 | +func decodeNodeElements(buf []byte) ([][]byte, error) { |
| 252 | + if len(buf) == 0 { |
| 253 | + return nil, io.ErrUnexpectedEOF |
| 254 | + } |
| 255 | + return rlp.SplitListValues(buf) |
| 256 | +} |
| 257 | + |
| 258 | +// encodeNodeElements encodes the provided node elements into a rlp list. |
| 259 | +func encodeNodeElements(elements [][]byte) ([]byte, error) { |
| 260 | + if len(elements) != 2 && len(elements) != 17 { |
| 261 | + return nil, fmt.Errorf("invalid number of elements: %d", len(elements)) |
| 262 | + } |
| 263 | + return rlp.MergeListValues(elements) |
| 264 | +} |
| 265 | + |
| 266 | +// NodeDifference accepts two RLP-encoding nodes and figures out the difference |
| 267 | +// between them. |
| 268 | +// |
| 269 | +// An error is returned if any of the provided blob is nil, or the type of nodes |
| 270 | +// are different. |
| 271 | +func NodeDifference(oldvalue []byte, newvalue []byte) (int, []int, [][]byte, error) { |
| 272 | + oldElems, err := decodeNodeElements(oldvalue) |
| 273 | + if err != nil { |
| 274 | + return 0, nil, nil, err |
| 275 | + } |
| 276 | + newElems, err := decodeNodeElements(newvalue) |
| 277 | + if err != nil { |
| 278 | + return 0, nil, nil, err |
| 279 | + } |
| 280 | + if len(oldElems) != len(newElems) { |
| 281 | + return 0, nil, nil, fmt.Errorf("different node type, old elements: %d, new elements: %d", len(oldElems), len(newElems)) |
| 282 | + } |
| 283 | + var ( |
| 284 | + indices = make([]int, 0, len(oldElems)) |
| 285 | + diff = make([][]byte, 0, len(oldElems)) |
| 286 | + ) |
| 287 | + for i := 0; i < len(oldElems); i++ { |
| 288 | + if !bytes.Equal(oldElems[i], newElems[i]) { |
| 289 | + indices = append(indices, i) |
| 290 | + diff = append(diff, oldElems[i]) |
| 291 | + } |
| 292 | + } |
| 293 | + return len(oldElems), indices, diff, nil |
| 294 | +} |
| 295 | + |
| 296 | +// ReassembleNode accepts a RLP-encoding node along with a set of mutations, |
| 297 | +// applying the modification diffs according to the indices and re-assemble. |
| 298 | +func ReassembleNode(blob []byte, mutations [][][]byte, indices [][]int) ([]byte, error) { |
| 299 | + if len(mutations) == 0 && len(indices) == 0 { |
| 300 | + return blob, nil |
| 301 | + } |
| 302 | + elements, err := decodeNodeElements(blob) |
| 303 | + if err != nil { |
| 304 | + return nil, err |
| 305 | + } |
| 306 | + for i := 0; i < len(mutations); i++ { |
| 307 | + for j, pos := range indices[i] { |
| 308 | + elements[pos] = mutations[i][j] |
| 309 | + } |
| 310 | + } |
| 311 | + return encodeNodeElements(elements) |
| 312 | +} |
| 313 | + |
245 | 314 | // wraps a decoding error with information about the path to the |
246 | 315 | // invalid child node (for debugging encoding issues). |
247 | 316 | type decodeError struct { |
|
0 commit comments