github.com/ethersphere/bee/v2@v2.2.0/pkg/replicas/replicas.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 replicas implements a scheme to replicate chunks 6 // in such a way that 7 // - the replicas are optimally dispersed to aid cross-neighbourhood redundancy 8 // - the replicas addresses can be deduced by retrievers only knowing the address 9 // of the original content addressed chunk 10 // - no new chunk validation rules are introduced 11 package replicas 12 13 import ( 14 "time" 15 16 "github.com/ethersphere/bee/v2/pkg/crypto" 17 "github.com/ethersphere/bee/v2/pkg/file/redundancy" 18 "github.com/ethersphere/bee/v2/pkg/swarm" 19 ) 20 21 var ( 22 // RetryInterval is the duration between successive additional requests 23 RetryInterval = 300 * time.Millisecond 24 privKey, _ = crypto.DecodeSecp256k1PrivateKey(append([]byte{1}, make([]byte, 31)...)) 25 signer = crypto.NewDefaultSigner(privKey) 26 ) 27 28 // replicator running the find for replicas 29 type replicator struct { 30 addr []byte // chunk address 31 queue [16]*replica // to sort addresses according to di 32 exist [30]bool // maps the 16 distinct nibbles on all levels 33 sizes [5]int // number of distinct neighnourhoods redcorded for each depth 34 c chan *replica 35 rLevel redundancy.Level 36 } 37 38 // newReplicator replicator constructor 39 func newReplicator(addr swarm.Address, rLevel redundancy.Level) *replicator { 40 rr := &replicator{ 41 addr: addr.Bytes(), 42 sizes: redundancy.GetReplicaCounts(), 43 c: make(chan *replica, 16), 44 rLevel: rLevel, 45 } 46 go rr.replicas() 47 return rr 48 } 49 50 // replica of the mined SOC chunk (address) that serve as replicas 51 type replica struct { 52 addr, id []byte // byte slice of SOC address and SOC ID 53 } 54 55 // replicate returns a replica params structure seeded with a byte of entropy as argument 56 func (rr *replicator) replicate(i uint8) (sp *replica) { 57 // change the last byte of the address to create SOC ID 58 id := make([]byte, 32) 59 copy(id, rr.addr) 60 id[0] = i 61 // calculate SOC address for potential replica 62 h := swarm.NewHasher() 63 _, _ = h.Write(id) 64 _, _ = h.Write(swarm.ReplicasOwner) 65 return &replica{h.Sum(nil), id} 66 } 67 68 // replicas enumerates replica parameters (SOC ID) pushing it in a channel given as argument 69 // the order of replicas is so that addresses are always maximally dispersed 70 // in successive sets of addresses. 71 // I.e., the binary tree representing the new addresses prefix bits up to depth is balanced 72 func (rr *replicator) replicas() { 73 defer close(rr.c) 74 n := 0 75 for i := uint8(0); n < rr.rLevel.GetReplicaCount() && i < 255; i++ { 76 // create soc replica (ID and address using constant owner) 77 // the soc is added to neighbourhoods of depths in the closed interval [from...to] 78 r := rr.replicate(i) 79 d, m := rr.add(r, rr.rLevel) 80 if d == 0 { 81 continue 82 } 83 for m, r = range rr.queue[n:] { 84 if r == nil { 85 break 86 } 87 rr.c <- r 88 } 89 n += m 90 } 91 } 92 93 // add inserts the soc replica into a replicator so that addresses are balanced 94 func (rr *replicator) add(r *replica, rLevel redundancy.Level) (depth int, rank int) { 95 if rLevel == redundancy.NONE { 96 return 0, 0 97 } 98 nh := nh(rLevel, r.addr) 99 if rr.exist[nh] { 100 return 0, 0 101 } 102 rr.exist[nh] = true 103 l, o := rr.add(r, rLevel.Decrement()) 104 d := uint8(rLevel) - 1 105 if l == 0 { 106 o = rr.sizes[d] 107 rr.sizes[d]++ 108 rr.queue[o] = r 109 l = rLevel.GetReplicaCount() 110 } 111 return l, o 112 } 113 114 // UTILS 115 116 // index bases needed to keep track how many addresses were mined for a level. 117 var replicaIndexBases = [5]int{0, 2, 6, 14} 118 119 // nh returns the lookup key based on the redundancy level 120 // to be used as index to the replicators exist array 121 func nh(rLevel redundancy.Level, addr []byte) int { 122 d := uint8(rLevel) 123 return replicaIndexBases[d-1] + int(addr[0]>>(8-d)) 124 }