github.com/koko1123/flow-go-1@v0.29.6/ledger/complete/mtrie/flattener/encoding_v4.go (about)

     1  package flattener
     2  
     3  import (
     4  	"encoding/binary"
     5  	"fmt"
     6  	"io"
     7  
     8  	"github.com/koko1123/flow-go-1/ledger"
     9  	"github.com/koko1123/flow-go-1/ledger/common/hash"
    10  	"github.com/koko1123/flow-go-1/ledger/complete/mtrie/node"
    11  	"github.com/koko1123/flow-go-1/ledger/complete/mtrie/trie"
    12  )
    13  
    14  // This file contains decoding functions for checkpoint v4 for backwards compatibility.
    15  
    16  const (
    17  	encNodeTypeSizeV4      = 1
    18  	encHeightSizeV4        = 2
    19  	encMaxDepthSizeV4      = 2
    20  	encRegCountSizeV4      = 8
    21  	encHashSizeV4          = hash.HashLen
    22  	encPathSizeV4          = ledger.PathLen
    23  	encNodeIndexSizeV4     = 8
    24  	encPayloadLengthSizeV4 = 4
    25  )
    26  
    27  // ReadNodeFromCheckpointV4 reconstructs a node from data read from reader.
    28  // Scratch buffer is used to avoid allocs. It should be used directly instead
    29  // of using append.  This function uses len(scratch) and ignores cap(scratch),
    30  // so any extra capacity will not be utilized.
    31  // If len(scratch) < 1024, then a new buffer will be allocated and used.
    32  // Leaf node is encoded in the following format:
    33  // - node type (1 byte)
    34  // - height (2 bytes)
    35  // - max depth (2 bytes)
    36  // - reg count (8 bytes)
    37  // - hash (32 bytes)
    38  // - path (32 bytes)
    39  // - payload (4 bytes + n bytes)
    40  func ReadNodeFromCheckpointV4(reader io.Reader, scratch []byte, getNode getNodeFunc) (*node.Node, uint64, uint64, error) {
    41  
    42  	// minBufSize should be large enough for interim node and leaf node with small payload.
    43  	// minBufSize is a failsafe and is only used when len(scratch) is much smaller
    44  	// than expected.  len(scratch) is 4096 by default, so minBufSize isn't likely to be used.
    45  	const minBufSize = 1024
    46  
    47  	if len(scratch) < minBufSize {
    48  		scratch = make([]byte, minBufSize)
    49  	}
    50  
    51  	// fixLengthSize is the size of shared data of leaf node and interim node
    52  	const fixLengthSize = encNodeTypeSizeV4 +
    53  		encHeightSizeV4 +
    54  		encMaxDepthSizeV4 +
    55  		encRegCountSizeV4 +
    56  		encHashSizeV4
    57  
    58  	_, err := io.ReadFull(reader, scratch[:fixLengthSize])
    59  	if err != nil {
    60  		return nil, 0, 0, fmt.Errorf("failed to read fixed-length part of serialized node: %w", err)
    61  	}
    62  
    63  	pos := 0
    64  
    65  	// Decode node type (1 byte)
    66  	nType := scratch[pos]
    67  	pos += encNodeTypeSizeV4
    68  
    69  	if nType != byte(leafNodeType) && nType != byte(interimNodeType) {
    70  		return nil, 0, 0, fmt.Errorf("failed to decode node type %d", nType)
    71  	}
    72  
    73  	// Decode height (2 bytes)
    74  	height := binary.BigEndian.Uint16(scratch[pos:])
    75  	pos += encHeightSizeV4
    76  
    77  	// Decode max depth (2 bytes)
    78  	maxDepth := binary.BigEndian.Uint16(scratch[pos:])
    79  	pos += encMaxDepthSizeV4
    80  
    81  	// Decode reg count (8 bytes)
    82  	regCount := binary.BigEndian.Uint64(scratch[pos:])
    83  	pos += encRegCountSizeV4
    84  
    85  	// Decode and create hash.Hash (32 bytes)
    86  	nodeHash, err := hash.ToHash(scratch[pos : pos+encHashSizeV4])
    87  	if err != nil {
    88  		return nil, 0, 0, fmt.Errorf("failed to decode hash of serialized node: %w", err)
    89  	}
    90  
    91  	// maxDepth and regCount are removed from Node.
    92  	_ = maxDepth
    93  	_ = regCount
    94  
    95  	if nType == byte(leafNodeType) {
    96  
    97  		// Read path (32 bytes)
    98  		encPath := scratch[:encPathSizeV4]
    99  		_, err := io.ReadFull(reader, encPath)
   100  		if err != nil {
   101  			return nil, 0, 0, fmt.Errorf("failed to read path of serialized node: %w", err)
   102  		}
   103  
   104  		// Decode and create ledger.Path.
   105  		path, err := ledger.ToPath(encPath)
   106  		if err != nil {
   107  			return nil, 0, 0, fmt.Errorf("failed to decode path of serialized node: %w", err)
   108  		}
   109  
   110  		// Read encoded payload data and create ledger.Payload.
   111  		payload, err := readPayloadV0FromReader(reader, scratch)
   112  		if err != nil {
   113  			return nil, 0, 0, fmt.Errorf("failed to read and decode payload of serialized node: %w", err)
   114  		}
   115  
   116  		n := node.NewNode(int(height), nil, nil, path, payload, nodeHash)
   117  
   118  		// Leaf node has 1 register and register size is payload size.
   119  		return n, 1, uint64(payload.Size()), nil
   120  	}
   121  
   122  	// Read interim node
   123  
   124  	// Read left and right child index (16 bytes)
   125  	_, err = io.ReadFull(reader, scratch[:encNodeIndexSizeV4*2])
   126  	if err != nil {
   127  		return nil, 0, 0, fmt.Errorf("failed to read child index of serialized node: %w", err)
   128  	}
   129  
   130  	pos = 0
   131  
   132  	// Decode left child index (8 bytes)
   133  	lchildIndex := binary.BigEndian.Uint64(scratch[pos:])
   134  	pos += encNodeIndexSizeV4
   135  
   136  	// Decode right child index (8 bytes)
   137  	rchildIndex := binary.BigEndian.Uint64(scratch[pos:])
   138  
   139  	// Get left child node by node index
   140  	lchild, lchildRegCount, lchildRegSize, err := getNode(lchildIndex)
   141  	if err != nil {
   142  		return nil, 0, 0, fmt.Errorf("failed to find left child node of serialized node: %w", err)
   143  	}
   144  
   145  	// Get right child node by node index
   146  	rchild, rchildRegCount, rchildRegSize, err := getNode(rchildIndex)
   147  	if err != nil {
   148  		return nil, 0, 0, fmt.Errorf("failed to find right child node of serialized node: %w", err)
   149  	}
   150  
   151  	n := node.NewNode(int(height), lchild, rchild, ledger.DummyPath, nil, nodeHash)
   152  	return n, lchildRegCount + rchildRegCount, lchildRegSize + rchildRegSize, nil
   153  }
   154  
   155  // ReadTrieFromCheckpointV4 reconstructs a trie from data read from reader.
   156  func ReadTrieFromCheckpointV4(reader io.Reader, scratch []byte, getNode getNodeFunc) (*trie.MTrie, error) {
   157  
   158  	// encodedTrieSize is a failsafe and is only used when len(scratch) is much smaller
   159  	// than expected (4096 by default).
   160  	const encodedTrieSize = encNodeIndexSizeV4 + encHashSizeV4
   161  
   162  	if len(scratch) < encodedTrieSize {
   163  		scratch = make([]byte, encodedTrieSize)
   164  	}
   165  
   166  	// Read encoded trie (8 + 32 bytes)
   167  	_, err := io.ReadFull(reader, scratch[:encodedTrieSize])
   168  	if err != nil {
   169  		return nil, fmt.Errorf("failed to read serialized trie: %w", err)
   170  	}
   171  
   172  	pos := 0
   173  
   174  	// Decode root node index
   175  	rootIndex := binary.BigEndian.Uint64(scratch)
   176  	pos += encNodeIndexSizeV4
   177  
   178  	// Decode root node hash
   179  	readRootHash, err := hash.ToHash(scratch[pos : pos+encHashSizeV4])
   180  	if err != nil {
   181  		return nil, fmt.Errorf("failed to decode hash of serialized trie: %w", err)
   182  	}
   183  
   184  	rootNode, regCount, regSize, err := getNode(rootIndex)
   185  	if err != nil {
   186  		return nil, fmt.Errorf("failed to find root node of serialized trie: %w", err)
   187  	}
   188  
   189  	mtrie, err := trie.NewMTrie(rootNode, regCount, regSize)
   190  	if err != nil {
   191  		return nil, fmt.Errorf("failed to restore serialized trie: %w", err)
   192  	}
   193  
   194  	rootHash := mtrie.RootHash()
   195  	if !rootHash.Equals(ledger.RootHash(readRootHash)) {
   196  		return nil, fmt.Errorf("failed to restore serialized trie: roothash doesn't match")
   197  	}
   198  
   199  	return mtrie, nil
   200  }
   201  
   202  // readPayloadV0FromReader reads and decodes payload from reader.
   203  // Returned payload is a copy.
   204  func readPayloadV0FromReader(reader io.Reader, scratch []byte) (*ledger.Payload, error) {
   205  
   206  	if len(scratch) < encPayloadLengthSizeV4 {
   207  		scratch = make([]byte, encPayloadLengthSizeV4)
   208  	}
   209  
   210  	// Read payload size
   211  	_, err := io.ReadFull(reader, scratch[:encPayloadLengthSizeV4])
   212  	if err != nil {
   213  		return nil, fmt.Errorf("cannot read payload length: %w", err)
   214  	}
   215  
   216  	// Decode payload size
   217  	size := binary.BigEndian.Uint32(scratch)
   218  
   219  	if len(scratch) < int(size) {
   220  		scratch = make([]byte, size)
   221  	} else {
   222  		scratch = scratch[:size]
   223  	}
   224  
   225  	_, err = io.ReadFull(reader, scratch)
   226  	if err != nil {
   227  		return nil, fmt.Errorf("cannot read payload: %w", err)
   228  	}
   229  
   230  	// Decode and copy payload
   231  	payload, err := ledger.DecodePayloadWithoutPrefix(scratch, false, 0)
   232  	if err != nil {
   233  		return nil, fmt.Errorf("failed to decode payload: %w", err)
   234  	}
   235  
   236  	return payload, nil
   237  }