github.com/celestiaorg/celestia-node@v0.15.0-beta.1/share/eds/retriever_quadrant.go (about)

     1  package eds
     2  
     3  import (
     4  	"math/rand"
     5  	"time"
     6  
     7  	"github.com/ipfs/go-cid"
     8  
     9  	"github.com/celestiaorg/celestia-app/pkg/da"
    10  	"github.com/celestiaorg/rsmt2d"
    11  
    12  	"github.com/celestiaorg/celestia-node/share/ipld"
    13  )
    14  
    15  const (
    16  	// there are always 4 quadrants
    17  	numQuadrants = 4
    18  	// blockTime equals to the time with which new blocks are produced in the network.
    19  	// TODO(@Wondertan): Here we assume that the block time is a minute, but
    20  	//  block time is a network wide variable/param that has to be taken from
    21  	//  a proper place
    22  	blockTime = time.Minute
    23  )
    24  
    25  // RetrieveQuadrantTimeout defines how much time Retriever waits before
    26  // starting to retrieve another quadrant.
    27  //
    28  // NOTE:
    29  // - The whole data square must be retrieved in less than block time.
    30  // - We have 4 quadrants from two sources(rows, cols) which equals to 8 in total.
    31  var RetrieveQuadrantTimeout = blockTime / numQuadrants * 2
    32  
    33  type quadrant struct {
    34  	// slice of roots to get shares from
    35  	roots []cid.Cid
    36  	// Example coordinates(x;y) of each quadrant when fetching from column roots
    37  	// ------  -------
    38  	// |  Q0 | | Q1  |
    39  	// |(0;0)| |(1;0)|
    40  	// ------  -------
    41  	// |  Q2 | | Q3  |
    42  	// |(0;1)| |(1;1)|
    43  	// ------  -------
    44  	x, y int
    45  	// source defines the axis(Row or Col) to fetch the quadrant from
    46  	source rsmt2d.Axis
    47  }
    48  
    49  // newQuadrants constructs a slice of quadrants from DAHeader.
    50  // There are always 4 quadrants per each source (row and col), so 8 in total.
    51  // The ordering of quadrants is random.
    52  func newQuadrants(dah *da.DataAvailabilityHeader) []*quadrant {
    53  	// combine all the roots into one slice, so they can be easily accessible by index
    54  	daRoots := [][][]byte{
    55  		dah.RowRoots,
    56  		dah.ColumnRoots,
    57  	}
    58  	// create a quadrant slice for each source(row;col)
    59  	sources := [][]*quadrant{
    60  		make([]*quadrant, numQuadrants),
    61  		make([]*quadrant, numQuadrants),
    62  	}
    63  	for source, quadrants := range sources {
    64  		size, qsize := len(daRoots[source]), len(daRoots[source])/2
    65  		roots := make([]cid.Cid, size)
    66  		for i, root := range daRoots[source] {
    67  			roots[i] = ipld.MustCidFromNamespacedSha256(root)
    68  		}
    69  
    70  		for i := range quadrants {
    71  			// convert quadrant 1D into into 2D coordinates
    72  			x, y := i%2, i/2
    73  			quadrants[i] = &quadrant{
    74  				roots:  roots[qsize*y : qsize*(y+1)],
    75  				x:      x,
    76  				y:      y,
    77  				source: rsmt2d.Axis(source),
    78  			}
    79  		}
    80  	}
    81  	quadrants := make([]*quadrant, 0, numQuadrants*2)
    82  	for _, qs := range sources {
    83  		quadrants = append(quadrants, qs...)
    84  	}
    85  	// shuffle quadrants to be fetched in random order
    86  	rand.Shuffle(len(quadrants), func(i, j int) { quadrants[i], quadrants[j] = quadrants[j], quadrants[i] })
    87  	return quadrants
    88  }
    89  
    90  // pos calculates position of a share in a data square.
    91  func (q *quadrant) pos(rootIdx, cellIdx int) (int, int) {
    92  	cellIdx += len(q.roots) * q.x
    93  	rootIdx += len(q.roots) * q.y
    94  	switch q.source {
    95  	case rsmt2d.Row:
    96  		return rootIdx, cellIdx
    97  	case rsmt2d.Col:
    98  		return cellIdx, rootIdx
    99  	default:
   100  		panic("unknown axis")
   101  	}
   102  }