github.com/celestiaorg/celestia-node@v0.15.0-beta.1/share/availability/full/availability.go (about) 1 package full 2 3 import ( 4 "context" 5 "errors" 6 "fmt" 7 8 "github.com/filecoin-project/dagstore" 9 logging "github.com/ipfs/go-log/v2" 10 11 "github.com/celestiaorg/celestia-node/header" 12 "github.com/celestiaorg/celestia-node/share" 13 "github.com/celestiaorg/celestia-node/share/eds" 14 "github.com/celestiaorg/celestia-node/share/eds/byzantine" 15 "github.com/celestiaorg/celestia-node/share/ipld" 16 "github.com/celestiaorg/celestia-node/share/p2p/discovery" 17 ) 18 19 var log = logging.Logger("share/full") 20 21 // ShareAvailability implements share.Availability using the full data square 22 // recovery technique. It is considered "full" because it is required 23 // to download enough shares to fully reconstruct the data square. 24 type ShareAvailability struct { 25 store *eds.Store 26 getter share.Getter 27 disc *discovery.Discovery 28 29 cancel context.CancelFunc 30 } 31 32 // NewShareAvailability creates a new full ShareAvailability. 33 func NewShareAvailability( 34 store *eds.Store, 35 getter share.Getter, 36 disc *discovery.Discovery, 37 ) *ShareAvailability { 38 return &ShareAvailability{ 39 store: store, 40 getter: getter, 41 disc: disc, 42 } 43 } 44 45 func (fa *ShareAvailability) Start(context.Context) error { 46 ctx, cancel := context.WithCancel(context.Background()) 47 fa.cancel = cancel 48 49 go fa.disc.Advertise(ctx) 50 return nil 51 } 52 53 func (fa *ShareAvailability) Stop(context.Context) error { 54 fa.cancel() 55 return nil 56 } 57 58 // SharesAvailable reconstructs the data committed to the given Root by requesting 59 // enough Shares from the network. 60 func (fa *ShareAvailability) SharesAvailable(ctx context.Context, header *header.ExtendedHeader) error { 61 dah := header.DAH 62 // short-circuit if the given root is minimum DAH of an empty data square, to avoid datastore hit 63 if share.DataHash(dah.Hash()).IsEmptyRoot() { 64 return nil 65 } 66 67 // we assume the caller of this method has already performed basic validation on the 68 // given dah/root. If for some reason this has not happened, the node should panic. 69 if err := dah.ValidateBasic(); err != nil { 70 log.Errorw("Availability validation cannot be performed on a malformed DataAvailabilityHeader", 71 "err", err) 72 panic(err) 73 } 74 75 // a hack to avoid loading the whole EDS in mem if we store it already. 76 if ok, _ := fa.store.Has(ctx, dah.Hash()); ok { 77 return nil 78 } 79 80 adder := ipld.NewProofsAdder(len(dah.RowRoots)) 81 ctx = ipld.CtxWithProofsAdder(ctx, adder) 82 defer adder.Purge() 83 84 eds, err := fa.getter.GetEDS(ctx, header) 85 if err != nil { 86 if errors.Is(err, context.Canceled) { 87 return err 88 } 89 log.Errorw("availability validation failed", "root", dah.String(), "err", err.Error()) 90 var byzantineErr *byzantine.ErrByzantine 91 if errors.Is(err, share.ErrNotFound) || errors.Is(err, context.DeadlineExceeded) && !errors.As(err, &byzantineErr) { 92 return share.ErrNotAvailable 93 } 94 return err 95 } 96 97 err = fa.store.Put(ctx, dah.Hash(), eds) 98 if err != nil && !errors.Is(err, dagstore.ErrShardExists) { 99 return fmt.Errorf("full availability: failed to store eds: %w", err) 100 } 101 return nil 102 }