github.com/celestiaorg/celestia-node@v0.15.0-beta.1/share/getters/store.go (about) 1 package getters 2 3 import ( 4 "context" 5 "errors" 6 "fmt" 7 8 "go.opentelemetry.io/otel/attribute" 9 "go.opentelemetry.io/otel/trace" 10 11 "github.com/celestiaorg/rsmt2d" 12 13 "github.com/celestiaorg/celestia-node/header" 14 "github.com/celestiaorg/celestia-node/libs/utils" 15 "github.com/celestiaorg/celestia-node/share" 16 "github.com/celestiaorg/celestia-node/share/eds" 17 "github.com/celestiaorg/celestia-node/share/ipld" 18 ) 19 20 var _ share.Getter = (*StoreGetter)(nil) 21 22 // StoreGetter is a share.Getter that retrieves shares from an eds.Store. No results are saved to 23 // the eds.Store after retrieval. 24 type StoreGetter struct { 25 store *eds.Store 26 } 27 28 // NewStoreGetter creates a new share.Getter that retrieves shares from an eds.Store. 29 func NewStoreGetter(store *eds.Store) *StoreGetter { 30 return &StoreGetter{ 31 store: store, 32 } 33 } 34 35 // GetShare gets a single share at the given EDS coordinates from the eds.Store through the 36 // corresponding CAR-level blockstore. 37 func (sg *StoreGetter) GetShare(ctx context.Context, header *header.ExtendedHeader, row, col int) (share.Share, error) { 38 dah := header.DAH 39 var err error 40 ctx, span := tracer.Start(ctx, "store/get-share", trace.WithAttributes( 41 attribute.Int("row", row), 42 attribute.Int("col", col), 43 )) 44 defer func() { 45 utils.SetStatusAndEnd(span, err) 46 }() 47 48 upperBound := len(dah.RowRoots) 49 if row >= upperBound || col >= upperBound { 50 err := share.ErrOutOfBounds 51 span.RecordError(err) 52 return nil, err 53 } 54 root, leaf := ipld.Translate(dah, row, col) 55 bs, err := sg.store.CARBlockstore(ctx, dah.Hash()) 56 if errors.Is(err, eds.ErrNotFound) { 57 // convert error to satisfy getter interface contract 58 err = share.ErrNotFound 59 } 60 if err != nil { 61 return nil, fmt.Errorf("getter/store: failed to retrieve blockstore: %w", err) 62 } 63 defer func() { 64 if err := bs.Close(); err != nil { 65 log.Warnw("closing blockstore", "err", err) 66 } 67 }() 68 69 // wrap the read-only CAR blockstore in a getter 70 blockGetter := eds.NewBlockGetter(bs) 71 s, err := ipld.GetShare(ctx, blockGetter, root, leaf, len(dah.RowRoots)) 72 if errors.Is(err, ipld.ErrNodeNotFound) { 73 // convert error to satisfy getter interface contract 74 err = share.ErrNotFound 75 } 76 if err != nil { 77 return nil, fmt.Errorf("getter/store: failed to retrieve share: %w", err) 78 } 79 80 return s, nil 81 } 82 83 // GetEDS gets the EDS identified by the given root from the EDS store. 84 func (sg *StoreGetter) GetEDS( 85 ctx context.Context, header *header.ExtendedHeader, 86 ) (data *rsmt2d.ExtendedDataSquare, err error) { 87 ctx, span := tracer.Start(ctx, "store/get-eds") 88 defer func() { 89 utils.SetStatusAndEnd(span, err) 90 }() 91 92 data, err = sg.store.Get(ctx, header.DAH.Hash()) 93 if errors.Is(err, eds.ErrNotFound) { 94 // convert error to satisfy getter interface contract 95 err = share.ErrNotFound 96 } 97 if err != nil { 98 return nil, fmt.Errorf("getter/store: failed to retrieve eds: %w", err) 99 } 100 return data, nil 101 } 102 103 // GetSharesByNamespace gets all EDS shares in the given namespace from the EDS store through the 104 // corresponding CAR-level blockstore. 105 func (sg *StoreGetter) GetSharesByNamespace( 106 ctx context.Context, 107 header *header.ExtendedHeader, 108 namespace share.Namespace, 109 ) (shares share.NamespacedShares, err error) { 110 ctx, span := tracer.Start(ctx, "store/get-shares-by-namespace", trace.WithAttributes( 111 attribute.String("namespace", namespace.String()), 112 )) 113 defer func() { 114 utils.SetStatusAndEnd(span, err) 115 }() 116 117 ns, err := eds.RetrieveNamespaceFromStore(ctx, sg.store, header.DAH, namespace) 118 if err != nil { 119 return nil, fmt.Errorf("getter/store: %w", err) 120 } 121 return ns, nil 122 }