github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/libs/iavl/docs/tree/export_import.md (about) 1 # Export/Import 2 3 A single `ImmutableTree` (i.e. a single version) can be exported via `ImmutableTree.Export()`, returning an iterator over `ExportNode` items. These nodes can be imported into an empty `MutableTree` with `MutableTree.Import()` to recreate an identical tree. The structure of `ExportNode` is: 4 5 ```go 6 type ExportNode struct { 7 Key []byte 8 Value []byte 9 Version int64 10 Height int8 11 } 12 ``` 13 14 This is the minimum amount of data about nodes that can be exported, see the [node documentation](../node/node.md) for comparison. The other node attributes, such as `hash` and `size`, can be derived from this data. Both leaf nodes and inner nodes are exported, since `Version` is part of the hash and inner nodes have different versions than the leaf nodes with the same key. 15 16 The order of exported nodes is significant. Nodes are exported by depth-first post-order (LRN) tree traversal. Consider the following tree (with nodes in `key@version=value` format): 17 18 ``` 19 d@3 20 / \ 21 c@3 e@3 22 / \ / \ 23 b@3 c@3=3 d@2=4 e@3=5 24 / \ 25 a@1=1 b@3=2 26 27 ``` 28 29 This would produce the following export: 30 31 ```go 32 []*ExportNode{ 33 {Key: []byte("a"), Value: []byte{1}, Version: 1, Height: 0}, 34 {Key: []byte("b"), Value: []byte{2}, Version: 3, Height: 0}, 35 {Key: []byte("b"), Value: nil, Version: 3, Height: 1}, 36 {Key: []byte("c"), Value: []byte{3}, Version: 3, Height: 0}, 37 {Key: []byte("c"), Value: nil, Version: 3, Height: 2}, 38 {Key: []byte("d"), Value: []byte{4}, Version: 2, Height: 0}, 39 {Key: []byte("e"), Value: []byte{5}, Version: 3, Height: 0}, 40 {Key: []byte("e"), Value: nil, Version: 3, Height: 1}, 41 {Key: []byte("d"), Value: nil, Version: 3, Height: 3}, 42 } 43 ``` 44 45 When importing, the tree must be rebuilt in the same order, such that the missing attributes (e.g. `hash` and `size`) can be generated. This is possible because children are always given before their parents. We can therefore first generate the hash and size of the left and right leaf nodes, and then use these to recursively generate the hash and size of the parent. 46 47 One way to do this is to keep a stack of orphaned children, and then pop those children once we build their parent, which then becomes a new child on the stack. We know that we encounter a parent because its height is higher than the child or children on top of the stack. We need a stack because we may need to recursively build a right branch while holding an orphaned left child. For the above export this would look like the following (in `key:height=value` format): 48 49 ``` 50 | Stack | Import node | 51 |-----------------|-------------------------------------------------------------| 52 | | {Key: []byte("a"), Value: []byte{1}, Version: 1, Height: 0} | 53 | a:0=1 | {Key: []byte("b"), Value: []byte{2}, Version: 3, Height: 0} | 54 | a:0=1,b:0=2 | {Key: []byte("b"), Value: nil, Version: 3, Height: 1} | 55 | b:1 | {Key: []byte("c"), Value: []byte{3}, Version: 3, Height: 0} | 56 | b:1,c:0=3 | {Key: []byte("c"), Value: nil, Version: 3, Height: 2} | 57 | c:2 | {Key: []byte("d"), Value: []byte{4}, Version: 2, Height: 0} | 58 | c:2,d:0=4 | {Key: []byte("e"), Value: []byte{5}, Version: 3, Height: 0} | 59 | c:2,d:0=4,e:0=5 | {Key: []byte("e"), Value: nil, Version: 3, Height: 1} | 60 | c:2,e:1 | {Key: []byte("d"), Value: nil, Version: 3, Height: 3} | 61 | d:3 | | 62 ``` 63 64 At the end, there will be a single node left on the stack, which is the root node of the tree.