github.com/ethersphere/bee/v2@v2.2.0/pkg/file/utils.go (about)

     1  // Copyright 2023 The Swarm Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package file
     6  
     7  import (
     8  	"bytes"
     9  	"errors"
    10  
    11  	"github.com/ethersphere/bee/v2/pkg/file/redundancy"
    12  	"github.com/ethersphere/bee/v2/pkg/swarm"
    13  )
    14  
    15  var (
    16  	zeroAddress = [32]byte{}
    17  )
    18  
    19  // ChunkPayloadSize returns the effective byte length of an intermediate chunk
    20  // assumes data is always chunk size (without span)
    21  func ChunkPayloadSize(data []byte) (int, error) {
    22  	l := len(data)
    23  	for l >= swarm.HashSize {
    24  		if !bytes.Equal(data[l-swarm.HashSize:l], zeroAddress[:]) {
    25  			return l, nil
    26  		}
    27  
    28  		l -= swarm.HashSize
    29  	}
    30  
    31  	return 0, errors.New("redundancy getter: intermediate chunk does not have at least a child")
    32  }
    33  
    34  // ChunkAddresses returns data shards and parities of the intermediate chunk
    35  // assumes data is truncated by ChunkPayloadSize
    36  func ChunkAddresses(data []byte, parities, reflen int) (addrs []swarm.Address, shardCnt int) {
    37  	shardCnt = (len(data) - parities*swarm.HashSize) / reflen
    38  	for offset := 0; offset < len(data); offset += reflen {
    39  		addrs = append(addrs, swarm.NewAddress(data[offset:offset+swarm.HashSize]))
    40  		if len(addrs) == shardCnt && reflen != swarm.HashSize {
    41  			reflen = swarm.HashSize
    42  			offset += reflen
    43  		}
    44  	}
    45  	return addrs, shardCnt
    46  }
    47  
    48  // ReferenceCount brute-forces the data shard count from which identify the parity count as well in a substree
    49  // assumes span > swarm.chunkSize
    50  // returns data and parity shard number
    51  func ReferenceCount(span uint64, level redundancy.Level, encrytedChunk bool) (int, int) {
    52  	// assume we have a trie of size `span` then we can assume that all of
    53  	// the forks except for the last one on the right are of equal size
    54  	// this is due to how the splitter wraps levels.
    55  	// first the algorithm will search for a BMT level where span can be included
    56  	// then identify how large data one reference can hold on that level
    57  	// then count how many references can satisfy span
    58  	// and finally how many parity shards should be on that level
    59  	maxShards := level.GetMaxShards()
    60  	if encrytedChunk {
    61  		maxShards = level.GetMaxEncShards()
    62  	}
    63  	var (
    64  		branching  = uint64(maxShards) // branching factor is how many data shard references can fit into one intermediate chunk
    65  		branchSize = uint64(swarm.ChunkSize)
    66  	)
    67  	// search for branch level big enough to include span
    68  	branchLevel := 1
    69  	for {
    70  		if branchSize >= span {
    71  			break
    72  		}
    73  		branchSize *= branching
    74  		branchLevel++
    75  	}
    76  	// span in one full reference
    77  	referenceSize := uint64(swarm.ChunkSize)
    78  	// referenceSize = branching ** (branchLevel - 1)
    79  	for i := 1; i < branchLevel-1; i++ {
    80  		referenceSize *= branching
    81  	}
    82  
    83  	dataShardAddresses := 1
    84  	spanOffset := referenceSize
    85  	for spanOffset < span {
    86  		spanOffset += referenceSize
    87  		dataShardAddresses++
    88  	}
    89  
    90  	parityAddresses := level.GetParities(dataShardAddresses)
    91  	if encrytedChunk {
    92  		parityAddresses = level.GetEncParities(dataShardAddresses)
    93  	}
    94  
    95  	return dataShardAddresses, parityAddresses
    96  }