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 }