diff --git a/cmd/curio/tasks/tasks.go b/cmd/curio/tasks/tasks.go index 9d60a1a43..abfa0b1b2 100644 --- a/cmd/curio/tasks/tasks.go +++ b/cmd/curio/tasks/tasks.go @@ -287,6 +287,7 @@ func StartTasks(ctx context.Context, dependencies *deps.Deps, shutdownChan chan return nil, err } var sdeps cuhttp.ServiceDeps + idxMax := taskhelp.Max(cfg.Subsystems.IndexingMaxTasks) if cfg.Subsystems.EnablePDP { es := getSenderEth() @@ -299,11 +300,11 @@ func StartTasks(ctx context.Context, dependencies *deps.Deps, shutdownChan chan pdpNextProvingPeriodTask := pdp.NewNextProvingPeriodTask(db, must.One(dependencies.EthClient.Val()), dependencies.Chain, chainSched, es) pdpInitProvingPeriodTask := pdp.NewInitProvingPeriodTask(db, must.One(dependencies.EthClient.Val()), dependencies.Chain, chainSched, es) pdpNotifTask := pdp.NewPDPNotifyTask(db) - activeTasks = append(activeTasks, pdpNotifTask, pdpProveTask, pdpNextProvingPeriodTask, pdpInitProvingPeriodTask) + pdpIndexingTask := indexing.NewPDPIndexingTask(db, iStore, dependencies.CachedPieceReader, cfg, idxMax) + pdpIpniTask := indexing.NewPDPIPNITask(db, sc, dependencies.CachedPieceReader, cfg, idxMax) + activeTasks = append(activeTasks, pdpNotifTask, pdpProveTask, pdpNextProvingPeriodTask, pdpInitProvingPeriodTask, pdpIndexingTask, pdpIpniTask) } - idxMax := taskhelp.Max(cfg.Subsystems.IndexingMaxTasks) - indexingTask := indexing.NewIndexingTask(db, sc, iStore, pp, cfg, idxMax) ipniTask := indexing.NewIPNITask(db, sc, iStore, pp, cfg, idxMax) activeTasks = append(activeTasks, ipniTask, indexingTask) diff --git a/deps/config/types.go b/deps/config/types.go index f46d81a0a..58fdd2c64 100644 --- a/deps/config/types.go +++ b/deps/config/types.go @@ -114,7 +114,7 @@ func DefaultCurioConfig() *CurioConfig { }, IPNI: IPNIConfig{ ServiceURL: []string{"https://cid.contact"}, - DirectAnnounceURLs: []string{"https://cid.contact/ingest/announce"}, + DirectAnnounceURLs: []string{"https://cid.contact/ingest/announce", "https://filecoinpin.contact/announce"}, }, }, }, diff --git a/harmony/harmonydb/sql/20240823-ipni.sql b/harmony/harmonydb/sql/20240823-ipni.sql index b9b9117c2..11677cb58 100644 --- a/harmony/harmonydb/sql/20240823-ipni.sql +++ b/harmony/harmonydb/sql/20240823-ipni.sql @@ -8,7 +8,7 @@ CREATE TABLE ipni_peerid ( CREATE TABLE ipni ( order_number BIGSERIAL PRIMARY KEY, -- Unique increasing order number ad_cid TEXT NOT NULL, - context_id BYTEA NOT NULL, -- abi.PieceInfo in Curio + context_id BYTEA NOT NULL, -- abi.PieceInfo || PDPIPNIContext in Curio -- metadata column in not required as Curio only supports one type of metadata(HTTP) is_rm BOOLEAN NOT NULL, diff --git a/harmony/harmonydb/sql/20251004-pdp-indexing.sql b/harmony/harmonydb/sql/20251004-pdp-indexing.sql new file mode 100644 index 000000000..07a438aa0 --- /dev/null +++ b/harmony/harmonydb/sql/20251004-pdp-indexing.sql @@ -0,0 +1,5 @@ +-- fields tracking indexing and ipni jobs over pdp pieces +ALTER TABLE pdp_piecerefs ADD COLUMN indexing_task_id BIGINT DEFAULT NULL; +ALTER TABLE pdp_piecerefs ADD COLUMN needs_indexing BOOLEAN DEFAULT FALSE; +ALTER TABLE pdp_piecerefs ADD COLUMN ipni_task_id BIGINT DEFAULT NULL; +ALTER TABLE pdp_piecerefs ADD COLUMN needs_ipni BOOLEAN DEFAULT FALSE; \ No newline at end of file diff --git a/market/ipni/ipni-provider/ipni-provider.go b/market/ipni/ipni-provider/ipni-provider.go index 33478e266..686a20740 100644 --- a/market/ipni/ipni-provider/ipni-provider.go +++ b/market/ipni/ipni-provider/ipni-provider.go @@ -49,8 +49,8 @@ const IPNIRoutePath = "/ipni-provider/" const IPNIPath = "/ipni/v1/ad/" // publishInterval represents the time interval between each publishing operation. -// It is set to 10 minutes. -const publishInterval = 10 * time.Minute +// It is set to 30 seconds for the purposes of PDP index publishing +const publishInterval = 30 * time.Second const publishProviderSpacing = 10 * time.Second var ( @@ -73,6 +73,7 @@ type Provider struct { indexStore *indexstore.IndexStore sc *chunker.ServeChunker keys map[string]*peerInfo // map[peerID String]Private_Key + latest map[string]cid.Cid // map[peerID String]last published head, used to avoid duplicate announce // announceURLs enables sending direct announcements via HTTP. This is // the list of indexer URLs to send direct HTTP announce messages to. announceURLs []*url.URL @@ -193,6 +194,7 @@ func NewProvider(d *deps.Deps) (*Provider, error) { keys: keyMap, announceURLs: announceURLs, httpServerAddresses: httpServerAddresses, + latest: make(map[string]cid.Cid), }, nil } @@ -364,7 +366,7 @@ func (p *Provider) handleGet(w http.ResponseWriter, r *http.Request) { start := time.Now() defer func() { - log.Infow("Served IPNI request", "path", r.URL.Path, "cid", reqCid, "providerId", providerID, "took", time.Since(start)) + log.Infow("Served IPNI request", "path", r.URL.Path, "cid", reqCid, "providerId", providerID, "took", time.Since(start), "remote_addr", r.RemoteAddr) }() b, err := cid.Parse(reqCid) @@ -477,7 +479,6 @@ func RemoveCidContact(slice []*url.URL) []*url.URL { // StartPublishing starts a poller which publishes the head for each provider every 10 minutes. func (p *Provider) StartPublishing(ctx context.Context) { var ticker *time.Ticker - // A poller which publishes head for each provider // every 10 minutes for mainnet build if build.BuildType == build.BuildMainnet { @@ -489,12 +490,22 @@ func (p *Provider) StartPublishing(ctx context.Context) { return } log.Info("Starting IPNI provider publishing for testnet build") + ticker = time.NewTicker(publishInterval) if build.BuildType != build.BuildCalibnet { ticker = time.NewTicker(time.Second * 10) log.Info("Resetting IPNI provider publishing ticker to 10 seconds for devnet build") } } + // Populated latest head cid from the ipni_head table + for provider := range p.keys { + c, err := p.getHeadCID(ctx, provider) + if err != nil { + log.Errorw("failed to get head CID", "provider", provider, "error", err) + continue + } + p.latest[provider] = c + } go func(ticker *time.Ticker) { for { select { @@ -544,10 +555,17 @@ func (p *Provider) publishHead(ctx context.Context) { log.Errorw("failed to get head CID", "provider", provider, "error", err) continue } + if _, ok := p.latest[provider]; ok && p.latest[provider] == c { + log.Debugw("Skipping duplicate announce for provider", "provider", provider, "cid", c.String()) + continue + } + log.Infow("Publishing head for provider", "provider", provider, "cid", c.String()) err = p.publishhttp(ctx, c, provider) if err != nil { log.Errorw("failed to publish head for provide", "provider", provider, "error", err) + } else { + p.latest[provider] = c } i++ @@ -567,6 +585,7 @@ func (p *Provider) publishProviderSpacingWait() { // It obtains the HTTP addresses for the peer and sends the announce message to those addresses. func (p *Provider) publishhttp(ctx context.Context, adCid cid.Cid, peer string) error { // Create the http announce sender. + log.Infow("Creating http announce sender", "urls", p.announceURLs) httpSender, err := httpsender.New(p.announceURLs, p.keys[peer].ID) if err != nil { return fmt.Errorf("cannot create http announce sender: %w", err) @@ -577,7 +596,6 @@ func (p *Provider) publishhttp(ctx context.Context, adCid cid.Cid, peer string) return fmt.Errorf("cannot create provider http addresses: %w", err) } - log.Infow("Announcing advertisements over HTTP", "urls", p.announceURLs) return announce.Send(ctx, adCid, addrs, httpSender) } diff --git a/market/ipni/ipni-provider/spark.go b/market/ipni/ipni-provider/spark.go index eb661a292..9276aebbd 100644 --- a/market/ipni/ipni-provider/spark.go +++ b/market/ipni/ipni-provider/spark.go @@ -26,7 +26,10 @@ import ( func (p *Provider) updateSparkContract(ctx context.Context) error { for _, pInfo := range p.keys { - pInfo := pInfo + if pInfo.SPID <= 0 { + log.Debugf("spark does not yet support pdp data") + continue + } mInfo, err := p.full.StateMinerInfo(ctx, pInfo.Miner, types.EmptyTSK) if err != nil { return err diff --git a/pdp/contract/FilecoinWarmStorageServiceStateView.abi b/pdp/contract/FilecoinWarmStorageServiceStateView.abi new file mode 100644 index 000000000..3b0359706 --- /dev/null +++ b/pdp/contract/FilecoinWarmStorageServiceStateView.abi @@ -0,0 +1,593 @@ +[ + { + "type": "constructor", + "inputs": [ + { + "name": "_service", + "type": "address", + "internalType": "contract FilecoinWarmStorageService" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "challengeWindow", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "clientDataSetIDs", + "inputs": [ + { + "name": "payer", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "clientDataSets", + "inputs": [ + { + "name": "payer", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "dataSetIds", + "type": "uint256[]", + "internalType": "uint256[]" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "filCDNControllerAddress", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getAllDataSetMetadata", + "inputs": [ + { + "name": "dataSetId", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "keys", + "type": "string[]", + "internalType": "string[]" + }, + { + "name": "values", + "type": "string[]", + "internalType": "string[]" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getAllPieceMetadata", + "inputs": [ + { + "name": "dataSetId", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "pieceId", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "keys", + "type": "string[]", + "internalType": "string[]" + }, + { + "name": "values", + "type": "string[]", + "internalType": "string[]" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getApprovedProviders", + "inputs": [], + "outputs": [ + { + "name": "providerIds", + "type": "uint256[]", + "internalType": "uint256[]" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getChallengesPerProof", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint64", + "internalType": "uint64" + } + ], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "getClientDataSets", + "inputs": [ + { + "name": "client", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "infos", + "type": "tuple[]", + "internalType": "struct FilecoinWarmStorageService.DataSetInfo[]", + "components": [ + { + "name": "pdpRailId", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "cacheMissRailId", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "cdnRailId", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "payer", + "type": "address", + "internalType": "address" + }, + { + "name": "payee", + "type": "address", + "internalType": "address" + }, + { + "name": "serviceProvider", + "type": "address", + "internalType": "address" + }, + { + "name": "commissionBps", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "clientDataSetId", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "pdpEndEpoch", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "providerId", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "cdnEndEpoch", + "type": "uint256", + "internalType": "uint256" + } + ] + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getDataSet", + "inputs": [ + { + "name": "dataSetId", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "info", + "type": "tuple", + "internalType": "struct FilecoinWarmStorageService.DataSetInfo", + "components": [ + { + "name": "pdpRailId", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "cacheMissRailId", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "cdnRailId", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "payer", + "type": "address", + "internalType": "address" + }, + { + "name": "payee", + "type": "address", + "internalType": "address" + }, + { + "name": "serviceProvider", + "type": "address", + "internalType": "address" + }, + { + "name": "commissionBps", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "clientDataSetId", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "pdpEndEpoch", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "providerId", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "cdnEndEpoch", + "type": "uint256", + "internalType": "uint256" + } + ] + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getDataSetMetadata", + "inputs": [ + { + "name": "dataSetId", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "key", + "type": "string", + "internalType": "string" + } + ], + "outputs": [ + { + "name": "exists", + "type": "bool", + "internalType": "bool" + }, + { + "name": "value", + "type": "string", + "internalType": "string" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getDataSetSizeInBytes", + "inputs": [ + { + "name": "leafCount", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "getMaxProvingPeriod", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint64", + "internalType": "uint64" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getPDPConfig", + "inputs": [], + "outputs": [ + { + "name": "maxProvingPeriod", + "type": "uint64", + "internalType": "uint64" + }, + { + "name": "challengeWindowSize", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "challengesPerProof", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "initChallengeWindowStart", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getPieceMetadata", + "inputs": [ + { + "name": "dataSetId", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "pieceId", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "key", + "type": "string", + "internalType": "string" + } + ], + "outputs": [ + { + "name": "exists", + "type": "bool", + "internalType": "bool" + }, + { + "name": "value", + "type": "string", + "internalType": "string" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "isProviderApproved", + "inputs": [ + { + "name": "providerId", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "nextPDPChallengeWindowStart", + "inputs": [ + { + "name": "setId", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "provenPeriods", + "inputs": [ + { + "name": "dataSetId", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "periodId", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "provenThisPeriod", + "inputs": [ + { + "name": "dataSetId", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "provingActivationEpoch", + "inputs": [ + { + "name": "dataSetId", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "provingDeadline", + "inputs": [ + { + "name": "setId", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "railToDataSet", + "inputs": [ + { + "name": "railId", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "service", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "contract FilecoinWarmStorageService" + } + ], + "stateMutability": "view" + }, + { + "type": "error", + "name": "ProvingPeriodNotInitialized", + "inputs": [ + { + "name": "dataSetId", + "type": "uint256", + "internalType": "uint256" + } + ] + } +] diff --git a/pdp/contract/FilecoinWarmStorageServiceStateView.go b/pdp/contract/FilecoinWarmStorageServiceStateView.go new file mode 100644 index 000000000..62efd0654 --- /dev/null +++ b/pdp/contract/FilecoinWarmStorageServiceStateView.go @@ -0,0 +1,989 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package contract + +import ( + "errors" + "math/big" + "strings" + + ethereum "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/event" +) + +// Reference imports to suppress errors if they are not otherwise used. +var ( + _ = errors.New + _ = big.NewInt + _ = strings.NewReader + _ = ethereum.NotFound + _ = bind.Bind + _ = common.Big1 + _ = types.BloomLookup + _ = event.NewSubscription + _ = abi.ConvertType +) + +// FilecoinWarmStorageServiceDataSetInfo is an auto generated low-level Go binding around an user-defined struct. +type FilecoinWarmStorageServiceDataSetInfo struct { + PdpRailId *big.Int + CacheMissRailId *big.Int + CdnRailId *big.Int + Payer common.Address + Payee common.Address + ServiceProvider common.Address + CommissionBps *big.Int + ClientDataSetId *big.Int + PdpEndEpoch *big.Int + ProviderId *big.Int + CdnEndEpoch *big.Int +} + +// FilecoinWarmStorageServiceStateViewMetaData contains all meta data concerning the FilecoinWarmStorageServiceStateView contract. +var FilecoinWarmStorageServiceStateViewMetaData = &bind.MetaData{ + ABI: "[{\"type\":\"constructor\",\"inputs\":[{\"name\":\"_service\",\"type\":\"address\",\"internalType\":\"contractFilecoinWarmStorageService\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"challengeWindow\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"clientDataSetIDs\",\"inputs\":[{\"name\":\"payer\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"clientDataSets\",\"inputs\":[{\"name\":\"payer\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"dataSetIds\",\"type\":\"uint256[]\",\"internalType\":\"uint256[]\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"filCDNControllerAddress\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getAllDataSetMetadata\",\"inputs\":[{\"name\":\"dataSetId\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"keys\",\"type\":\"string[]\",\"internalType\":\"string[]\"},{\"name\":\"values\",\"type\":\"string[]\",\"internalType\":\"string[]\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getAllPieceMetadata\",\"inputs\":[{\"name\":\"dataSetId\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"pieceId\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"keys\",\"type\":\"string[]\",\"internalType\":\"string[]\"},{\"name\":\"values\",\"type\":\"string[]\",\"internalType\":\"string[]\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getApprovedProviders\",\"inputs\":[],\"outputs\":[{\"name\":\"providerIds\",\"type\":\"uint256[]\",\"internalType\":\"uint256[]\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getChallengesPerProof\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint64\",\"internalType\":\"uint64\"}],\"stateMutability\":\"pure\"},{\"type\":\"function\",\"name\":\"getClientDataSets\",\"inputs\":[{\"name\":\"client\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"infos\",\"type\":\"tuple[]\",\"internalType\":\"structFilecoinWarmStorageService.DataSetInfo[]\",\"components\":[{\"name\":\"pdpRailId\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"cacheMissRailId\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"cdnRailId\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"payer\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"payee\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"serviceProvider\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"commissionBps\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"clientDataSetId\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"pdpEndEpoch\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"providerId\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"cdnEndEpoch\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getDataSet\",\"inputs\":[{\"name\":\"dataSetId\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"info\",\"type\":\"tuple\",\"internalType\":\"structFilecoinWarmStorageService.DataSetInfo\",\"components\":[{\"name\":\"pdpRailId\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"cacheMissRailId\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"cdnRailId\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"payer\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"payee\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"serviceProvider\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"commissionBps\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"clientDataSetId\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"pdpEndEpoch\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"providerId\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"cdnEndEpoch\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getDataSetMetadata\",\"inputs\":[{\"name\":\"dataSetId\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"key\",\"type\":\"string\",\"internalType\":\"string\"}],\"outputs\":[{\"name\":\"exists\",\"type\":\"bool\",\"internalType\":\"bool\"},{\"name\":\"value\",\"type\":\"string\",\"internalType\":\"string\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getDataSetSizeInBytes\",\"inputs\":[{\"name\":\"leafCount\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"pure\"},{\"type\":\"function\",\"name\":\"getMaxProvingPeriod\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint64\",\"internalType\":\"uint64\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getPDPConfig\",\"inputs\":[],\"outputs\":[{\"name\":\"maxProvingPeriod\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"challengeWindowSize\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"challengesPerProof\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"initChallengeWindowStart\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getPieceMetadata\",\"inputs\":[{\"name\":\"dataSetId\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"pieceId\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"key\",\"type\":\"string\",\"internalType\":\"string\"}],\"outputs\":[{\"name\":\"exists\",\"type\":\"bool\",\"internalType\":\"bool\"},{\"name\":\"value\",\"type\":\"string\",\"internalType\":\"string\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"isProviderApproved\",\"inputs\":[{\"name\":\"providerId\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"nextPDPChallengeWindowStart\",\"inputs\":[{\"name\":\"setId\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"provenPeriods\",\"inputs\":[{\"name\":\"dataSetId\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"periodId\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"provenThisPeriod\",\"inputs\":[{\"name\":\"dataSetId\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"provingActivationEpoch\",\"inputs\":[{\"name\":\"dataSetId\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"provingDeadline\",\"inputs\":[{\"name\":\"setId\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"railToDataSet\",\"inputs\":[{\"name\":\"railId\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"service\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractFilecoinWarmStorageService\"}],\"stateMutability\":\"view\"},{\"type\":\"error\",\"name\":\"ProvingPeriodNotInitialized\",\"inputs\":[{\"name\":\"dataSetId\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]}]", +} + +// FilecoinWarmStorageServiceStateViewABI is the input ABI used to generate the binding from. +// Deprecated: Use FilecoinWarmStorageServiceStateViewMetaData.ABI instead. +var FilecoinWarmStorageServiceStateViewABI = FilecoinWarmStorageServiceStateViewMetaData.ABI + +// FilecoinWarmStorageServiceStateView is an auto generated Go binding around an Ethereum contract. +type FilecoinWarmStorageServiceStateView struct { + FilecoinWarmStorageServiceStateViewCaller // Read-only binding to the contract + FilecoinWarmStorageServiceStateViewTransactor // Write-only binding to the contract + FilecoinWarmStorageServiceStateViewFilterer // Log filterer for contract events +} + +// FilecoinWarmStorageServiceStateViewCaller is an auto generated read-only Go binding around an Ethereum contract. +type FilecoinWarmStorageServiceStateViewCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// FilecoinWarmStorageServiceStateViewTransactor is an auto generated write-only Go binding around an Ethereum contract. +type FilecoinWarmStorageServiceStateViewTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// FilecoinWarmStorageServiceStateViewFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type FilecoinWarmStorageServiceStateViewFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// FilecoinWarmStorageServiceStateViewSession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type FilecoinWarmStorageServiceStateViewSession struct { + Contract *FilecoinWarmStorageServiceStateView // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// FilecoinWarmStorageServiceStateViewCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type FilecoinWarmStorageServiceStateViewCallerSession struct { + Contract *FilecoinWarmStorageServiceStateViewCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// FilecoinWarmStorageServiceStateViewTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type FilecoinWarmStorageServiceStateViewTransactorSession struct { + Contract *FilecoinWarmStorageServiceStateViewTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// FilecoinWarmStorageServiceStateViewRaw is an auto generated low-level Go binding around an Ethereum contract. +type FilecoinWarmStorageServiceStateViewRaw struct { + Contract *FilecoinWarmStorageServiceStateView // Generic contract binding to access the raw methods on +} + +// FilecoinWarmStorageServiceStateViewCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type FilecoinWarmStorageServiceStateViewCallerRaw struct { + Contract *FilecoinWarmStorageServiceStateViewCaller // Generic read-only contract binding to access the raw methods on +} + +// FilecoinWarmStorageServiceStateViewTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type FilecoinWarmStorageServiceStateViewTransactorRaw struct { + Contract *FilecoinWarmStorageServiceStateViewTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewFilecoinWarmStorageServiceStateView creates a new instance of FilecoinWarmStorageServiceStateView, bound to a specific deployed contract. +func NewFilecoinWarmStorageServiceStateView(address common.Address, backend bind.ContractBackend) (*FilecoinWarmStorageServiceStateView, error) { + contract, err := bindFilecoinWarmStorageServiceStateView(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &FilecoinWarmStorageServiceStateView{FilecoinWarmStorageServiceStateViewCaller: FilecoinWarmStorageServiceStateViewCaller{contract: contract}, FilecoinWarmStorageServiceStateViewTransactor: FilecoinWarmStorageServiceStateViewTransactor{contract: contract}, FilecoinWarmStorageServiceStateViewFilterer: FilecoinWarmStorageServiceStateViewFilterer{contract: contract}}, nil +} + +// NewFilecoinWarmStorageServiceStateViewCaller creates a new read-only instance of FilecoinWarmStorageServiceStateView, bound to a specific deployed contract. +func NewFilecoinWarmStorageServiceStateViewCaller(address common.Address, caller bind.ContractCaller) (*FilecoinWarmStorageServiceStateViewCaller, error) { + contract, err := bindFilecoinWarmStorageServiceStateView(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &FilecoinWarmStorageServiceStateViewCaller{contract: contract}, nil +} + +// NewFilecoinWarmStorageServiceStateViewTransactor creates a new write-only instance of FilecoinWarmStorageServiceStateView, bound to a specific deployed contract. +func NewFilecoinWarmStorageServiceStateViewTransactor(address common.Address, transactor bind.ContractTransactor) (*FilecoinWarmStorageServiceStateViewTransactor, error) { + contract, err := bindFilecoinWarmStorageServiceStateView(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &FilecoinWarmStorageServiceStateViewTransactor{contract: contract}, nil +} + +// NewFilecoinWarmStorageServiceStateViewFilterer creates a new log filterer instance of FilecoinWarmStorageServiceStateView, bound to a specific deployed contract. +func NewFilecoinWarmStorageServiceStateViewFilterer(address common.Address, filterer bind.ContractFilterer) (*FilecoinWarmStorageServiceStateViewFilterer, error) { + contract, err := bindFilecoinWarmStorageServiceStateView(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &FilecoinWarmStorageServiceStateViewFilterer{contract: contract}, nil +} + +// bindFilecoinWarmStorageServiceStateView binds a generic wrapper to an already deployed contract. +func bindFilecoinWarmStorageServiceStateView(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := FilecoinWarmStorageServiceStateViewMetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_FilecoinWarmStorageServiceStateView *FilecoinWarmStorageServiceStateViewRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _FilecoinWarmStorageServiceStateView.Contract.FilecoinWarmStorageServiceStateViewCaller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_FilecoinWarmStorageServiceStateView *FilecoinWarmStorageServiceStateViewRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _FilecoinWarmStorageServiceStateView.Contract.FilecoinWarmStorageServiceStateViewTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_FilecoinWarmStorageServiceStateView *FilecoinWarmStorageServiceStateViewRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _FilecoinWarmStorageServiceStateView.Contract.FilecoinWarmStorageServiceStateViewTransactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_FilecoinWarmStorageServiceStateView *FilecoinWarmStorageServiceStateViewCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _FilecoinWarmStorageServiceStateView.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_FilecoinWarmStorageServiceStateView *FilecoinWarmStorageServiceStateViewTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _FilecoinWarmStorageServiceStateView.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_FilecoinWarmStorageServiceStateView *FilecoinWarmStorageServiceStateViewTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _FilecoinWarmStorageServiceStateView.Contract.contract.Transact(opts, method, params...) +} + +// ChallengeWindow is a free data retrieval call binding the contract method 0x861a1412. +// +// Solidity: function challengeWindow() view returns(uint256) +func (_FilecoinWarmStorageServiceStateView *FilecoinWarmStorageServiceStateViewCaller) ChallengeWindow(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _FilecoinWarmStorageServiceStateView.contract.Call(opts, &out, "challengeWindow") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// ChallengeWindow is a free data retrieval call binding the contract method 0x861a1412. +// +// Solidity: function challengeWindow() view returns(uint256) +func (_FilecoinWarmStorageServiceStateView *FilecoinWarmStorageServiceStateViewSession) ChallengeWindow() (*big.Int, error) { + return _FilecoinWarmStorageServiceStateView.Contract.ChallengeWindow(&_FilecoinWarmStorageServiceStateView.CallOpts) +} + +// ChallengeWindow is a free data retrieval call binding the contract method 0x861a1412. +// +// Solidity: function challengeWindow() view returns(uint256) +func (_FilecoinWarmStorageServiceStateView *FilecoinWarmStorageServiceStateViewCallerSession) ChallengeWindow() (*big.Int, error) { + return _FilecoinWarmStorageServiceStateView.Contract.ChallengeWindow(&_FilecoinWarmStorageServiceStateView.CallOpts) +} + +// ClientDataSetIDs is a free data retrieval call binding the contract method 0x196ed89b. +// +// Solidity: function clientDataSetIDs(address payer) view returns(uint256) +func (_FilecoinWarmStorageServiceStateView *FilecoinWarmStorageServiceStateViewCaller) ClientDataSetIDs(opts *bind.CallOpts, payer common.Address) (*big.Int, error) { + var out []interface{} + err := _FilecoinWarmStorageServiceStateView.contract.Call(opts, &out, "clientDataSetIDs", payer) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// ClientDataSetIDs is a free data retrieval call binding the contract method 0x196ed89b. +// +// Solidity: function clientDataSetIDs(address payer) view returns(uint256) +func (_FilecoinWarmStorageServiceStateView *FilecoinWarmStorageServiceStateViewSession) ClientDataSetIDs(payer common.Address) (*big.Int, error) { + return _FilecoinWarmStorageServiceStateView.Contract.ClientDataSetIDs(&_FilecoinWarmStorageServiceStateView.CallOpts, payer) +} + +// ClientDataSetIDs is a free data retrieval call binding the contract method 0x196ed89b. +// +// Solidity: function clientDataSetIDs(address payer) view returns(uint256) +func (_FilecoinWarmStorageServiceStateView *FilecoinWarmStorageServiceStateViewCallerSession) ClientDataSetIDs(payer common.Address) (*big.Int, error) { + return _FilecoinWarmStorageServiceStateView.Contract.ClientDataSetIDs(&_FilecoinWarmStorageServiceStateView.CallOpts, payer) +} + +// ClientDataSets is a free data retrieval call binding the contract method 0x7dab7c40. +// +// Solidity: function clientDataSets(address payer) view returns(uint256[] dataSetIds) +func (_FilecoinWarmStorageServiceStateView *FilecoinWarmStorageServiceStateViewCaller) ClientDataSets(opts *bind.CallOpts, payer common.Address) ([]*big.Int, error) { + var out []interface{} + err := _FilecoinWarmStorageServiceStateView.contract.Call(opts, &out, "clientDataSets", payer) + + if err != nil { + return *new([]*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new([]*big.Int)).(*[]*big.Int) + + return out0, err + +} + +// ClientDataSets is a free data retrieval call binding the contract method 0x7dab7c40. +// +// Solidity: function clientDataSets(address payer) view returns(uint256[] dataSetIds) +func (_FilecoinWarmStorageServiceStateView *FilecoinWarmStorageServiceStateViewSession) ClientDataSets(payer common.Address) ([]*big.Int, error) { + return _FilecoinWarmStorageServiceStateView.Contract.ClientDataSets(&_FilecoinWarmStorageServiceStateView.CallOpts, payer) +} + +// ClientDataSets is a free data retrieval call binding the contract method 0x7dab7c40. +// +// Solidity: function clientDataSets(address payer) view returns(uint256[] dataSetIds) +func (_FilecoinWarmStorageServiceStateView *FilecoinWarmStorageServiceStateViewCallerSession) ClientDataSets(payer common.Address) ([]*big.Int, error) { + return _FilecoinWarmStorageServiceStateView.Contract.ClientDataSets(&_FilecoinWarmStorageServiceStateView.CallOpts, payer) +} + +// FilCDNControllerAddress is a free data retrieval call binding the contract method 0x1b5f2b8f. +// +// Solidity: function filCDNControllerAddress() view returns(address) +func (_FilecoinWarmStorageServiceStateView *FilecoinWarmStorageServiceStateViewCaller) FilCDNControllerAddress(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _FilecoinWarmStorageServiceStateView.contract.Call(opts, &out, "filCDNControllerAddress") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// FilCDNControllerAddress is a free data retrieval call binding the contract method 0x1b5f2b8f. +// +// Solidity: function filCDNControllerAddress() view returns(address) +func (_FilecoinWarmStorageServiceStateView *FilecoinWarmStorageServiceStateViewSession) FilCDNControllerAddress() (common.Address, error) { + return _FilecoinWarmStorageServiceStateView.Contract.FilCDNControllerAddress(&_FilecoinWarmStorageServiceStateView.CallOpts) +} + +// FilCDNControllerAddress is a free data retrieval call binding the contract method 0x1b5f2b8f. +// +// Solidity: function filCDNControllerAddress() view returns(address) +func (_FilecoinWarmStorageServiceStateView *FilecoinWarmStorageServiceStateViewCallerSession) FilCDNControllerAddress() (common.Address, error) { + return _FilecoinWarmStorageServiceStateView.Contract.FilCDNControllerAddress(&_FilecoinWarmStorageServiceStateView.CallOpts) +} + +// GetAllDataSetMetadata is a free data retrieval call binding the contract method 0xf417c13f. +// +// Solidity: function getAllDataSetMetadata(uint256 dataSetId) view returns(string[] keys, string[] values) +func (_FilecoinWarmStorageServiceStateView *FilecoinWarmStorageServiceStateViewCaller) GetAllDataSetMetadata(opts *bind.CallOpts, dataSetId *big.Int) (struct { + Keys []string + Values []string +}, error) { + var out []interface{} + err := _FilecoinWarmStorageServiceStateView.contract.Call(opts, &out, "getAllDataSetMetadata", dataSetId) + + outstruct := new(struct { + Keys []string + Values []string + }) + if err != nil { + return *outstruct, err + } + + outstruct.Keys = *abi.ConvertType(out[0], new([]string)).(*[]string) + outstruct.Values = *abi.ConvertType(out[1], new([]string)).(*[]string) + + return *outstruct, err + +} + +// GetAllDataSetMetadata is a free data retrieval call binding the contract method 0xf417c13f. +// +// Solidity: function getAllDataSetMetadata(uint256 dataSetId) view returns(string[] keys, string[] values) +func (_FilecoinWarmStorageServiceStateView *FilecoinWarmStorageServiceStateViewSession) GetAllDataSetMetadata(dataSetId *big.Int) (struct { + Keys []string + Values []string +}, error) { + return _FilecoinWarmStorageServiceStateView.Contract.GetAllDataSetMetadata(&_FilecoinWarmStorageServiceStateView.CallOpts, dataSetId) +} + +// GetAllDataSetMetadata is a free data retrieval call binding the contract method 0xf417c13f. +// +// Solidity: function getAllDataSetMetadata(uint256 dataSetId) view returns(string[] keys, string[] values) +func (_FilecoinWarmStorageServiceStateView *FilecoinWarmStorageServiceStateViewCallerSession) GetAllDataSetMetadata(dataSetId *big.Int) (struct { + Keys []string + Values []string +}, error) { + return _FilecoinWarmStorageServiceStateView.Contract.GetAllDataSetMetadata(&_FilecoinWarmStorageServiceStateView.CallOpts, dataSetId) +} + +// GetAllPieceMetadata is a free data retrieval call binding the contract method 0x3c0bd253. +// +// Solidity: function getAllPieceMetadata(uint256 dataSetId, uint256 pieceId) view returns(string[] keys, string[] values) +func (_FilecoinWarmStorageServiceStateView *FilecoinWarmStorageServiceStateViewCaller) GetAllPieceMetadata(opts *bind.CallOpts, dataSetId *big.Int, pieceId *big.Int) (struct { + Keys []string + Values []string +}, error) { + var out []interface{} + err := _FilecoinWarmStorageServiceStateView.contract.Call(opts, &out, "getAllPieceMetadata", dataSetId, pieceId) + + outstruct := new(struct { + Keys []string + Values []string + }) + if err != nil { + return *outstruct, err + } + + outstruct.Keys = *abi.ConvertType(out[0], new([]string)).(*[]string) + outstruct.Values = *abi.ConvertType(out[1], new([]string)).(*[]string) + + return *outstruct, err + +} + +// GetAllPieceMetadata is a free data retrieval call binding the contract method 0x3c0bd253. +// +// Solidity: function getAllPieceMetadata(uint256 dataSetId, uint256 pieceId) view returns(string[] keys, string[] values) +func (_FilecoinWarmStorageServiceStateView *FilecoinWarmStorageServiceStateViewSession) GetAllPieceMetadata(dataSetId *big.Int, pieceId *big.Int) (struct { + Keys []string + Values []string +}, error) { + return _FilecoinWarmStorageServiceStateView.Contract.GetAllPieceMetadata(&_FilecoinWarmStorageServiceStateView.CallOpts, dataSetId, pieceId) +} + +// GetAllPieceMetadata is a free data retrieval call binding the contract method 0x3c0bd253. +// +// Solidity: function getAllPieceMetadata(uint256 dataSetId, uint256 pieceId) view returns(string[] keys, string[] values) +func (_FilecoinWarmStorageServiceStateView *FilecoinWarmStorageServiceStateViewCallerSession) GetAllPieceMetadata(dataSetId *big.Int, pieceId *big.Int) (struct { + Keys []string + Values []string +}, error) { + return _FilecoinWarmStorageServiceStateView.Contract.GetAllPieceMetadata(&_FilecoinWarmStorageServiceStateView.CallOpts, dataSetId, pieceId) +} + +// GetApprovedProviders is a free data retrieval call binding the contract method 0x266afe1b. +// +// Solidity: function getApprovedProviders() view returns(uint256[] providerIds) +func (_FilecoinWarmStorageServiceStateView *FilecoinWarmStorageServiceStateViewCaller) GetApprovedProviders(opts *bind.CallOpts) ([]*big.Int, error) { + var out []interface{} + err := _FilecoinWarmStorageServiceStateView.contract.Call(opts, &out, "getApprovedProviders") + + if err != nil { + return *new([]*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new([]*big.Int)).(*[]*big.Int) + + return out0, err + +} + +// GetApprovedProviders is a free data retrieval call binding the contract method 0x266afe1b. +// +// Solidity: function getApprovedProviders() view returns(uint256[] providerIds) +func (_FilecoinWarmStorageServiceStateView *FilecoinWarmStorageServiceStateViewSession) GetApprovedProviders() ([]*big.Int, error) { + return _FilecoinWarmStorageServiceStateView.Contract.GetApprovedProviders(&_FilecoinWarmStorageServiceStateView.CallOpts) +} + +// GetApprovedProviders is a free data retrieval call binding the contract method 0x266afe1b. +// +// Solidity: function getApprovedProviders() view returns(uint256[] providerIds) +func (_FilecoinWarmStorageServiceStateView *FilecoinWarmStorageServiceStateViewCallerSession) GetApprovedProviders() ([]*big.Int, error) { + return _FilecoinWarmStorageServiceStateView.Contract.GetApprovedProviders(&_FilecoinWarmStorageServiceStateView.CallOpts) +} + +// GetChallengesPerProof is a free data retrieval call binding the contract method 0x47d3dfe7. +// +// Solidity: function getChallengesPerProof() pure returns(uint64) +func (_FilecoinWarmStorageServiceStateView *FilecoinWarmStorageServiceStateViewCaller) GetChallengesPerProof(opts *bind.CallOpts) (uint64, error) { + var out []interface{} + err := _FilecoinWarmStorageServiceStateView.contract.Call(opts, &out, "getChallengesPerProof") + + if err != nil { + return *new(uint64), err + } + + out0 := *abi.ConvertType(out[0], new(uint64)).(*uint64) + + return out0, err + +} + +// GetChallengesPerProof is a free data retrieval call binding the contract method 0x47d3dfe7. +// +// Solidity: function getChallengesPerProof() pure returns(uint64) +func (_FilecoinWarmStorageServiceStateView *FilecoinWarmStorageServiceStateViewSession) GetChallengesPerProof() (uint64, error) { + return _FilecoinWarmStorageServiceStateView.Contract.GetChallengesPerProof(&_FilecoinWarmStorageServiceStateView.CallOpts) +} + +// GetChallengesPerProof is a free data retrieval call binding the contract method 0x47d3dfe7. +// +// Solidity: function getChallengesPerProof() pure returns(uint64) +func (_FilecoinWarmStorageServiceStateView *FilecoinWarmStorageServiceStateViewCallerSession) GetChallengesPerProof() (uint64, error) { + return _FilecoinWarmStorageServiceStateView.Contract.GetChallengesPerProof(&_FilecoinWarmStorageServiceStateView.CallOpts) +} + +// GetClientDataSets is a free data retrieval call binding the contract method 0x967c6f21. +// +// Solidity: function getClientDataSets(address client) view returns((uint256,uint256,uint256,address,address,address,uint256,uint256,uint256,uint256,uint256)[] infos) +func (_FilecoinWarmStorageServiceStateView *FilecoinWarmStorageServiceStateViewCaller) GetClientDataSets(opts *bind.CallOpts, client common.Address) ([]FilecoinWarmStorageServiceDataSetInfo, error) { + var out []interface{} + err := _FilecoinWarmStorageServiceStateView.contract.Call(opts, &out, "getClientDataSets", client) + + if err != nil { + return *new([]FilecoinWarmStorageServiceDataSetInfo), err + } + + out0 := *abi.ConvertType(out[0], new([]FilecoinWarmStorageServiceDataSetInfo)).(*[]FilecoinWarmStorageServiceDataSetInfo) + + return out0, err + +} + +// GetClientDataSets is a free data retrieval call binding the contract method 0x967c6f21. +// +// Solidity: function getClientDataSets(address client) view returns((uint256,uint256,uint256,address,address,address,uint256,uint256,uint256,uint256,uint256)[] infos) +func (_FilecoinWarmStorageServiceStateView *FilecoinWarmStorageServiceStateViewSession) GetClientDataSets(client common.Address) ([]FilecoinWarmStorageServiceDataSetInfo, error) { + return _FilecoinWarmStorageServiceStateView.Contract.GetClientDataSets(&_FilecoinWarmStorageServiceStateView.CallOpts, client) +} + +// GetClientDataSets is a free data retrieval call binding the contract method 0x967c6f21. +// +// Solidity: function getClientDataSets(address client) view returns((uint256,uint256,uint256,address,address,address,uint256,uint256,uint256,uint256,uint256)[] infos) +func (_FilecoinWarmStorageServiceStateView *FilecoinWarmStorageServiceStateViewCallerSession) GetClientDataSets(client common.Address) ([]FilecoinWarmStorageServiceDataSetInfo, error) { + return _FilecoinWarmStorageServiceStateView.Contract.GetClientDataSets(&_FilecoinWarmStorageServiceStateView.CallOpts, client) +} + +// GetDataSet is a free data retrieval call binding the contract method 0xbdaac056. +// +// Solidity: function getDataSet(uint256 dataSetId) view returns((uint256,uint256,uint256,address,address,address,uint256,uint256,uint256,uint256,uint256) info) +func (_FilecoinWarmStorageServiceStateView *FilecoinWarmStorageServiceStateViewCaller) GetDataSet(opts *bind.CallOpts, dataSetId *big.Int) (FilecoinWarmStorageServiceDataSetInfo, error) { + var out []interface{} + err := _FilecoinWarmStorageServiceStateView.contract.Call(opts, &out, "getDataSet", dataSetId) + + if err != nil { + return *new(FilecoinWarmStorageServiceDataSetInfo), err + } + + out0 := *abi.ConvertType(out[0], new(FilecoinWarmStorageServiceDataSetInfo)).(*FilecoinWarmStorageServiceDataSetInfo) + + return out0, err + +} + +// GetDataSet is a free data retrieval call binding the contract method 0xbdaac056. +// +// Solidity: function getDataSet(uint256 dataSetId) view returns((uint256,uint256,uint256,address,address,address,uint256,uint256,uint256,uint256,uint256) info) +func (_FilecoinWarmStorageServiceStateView *FilecoinWarmStorageServiceStateViewSession) GetDataSet(dataSetId *big.Int) (FilecoinWarmStorageServiceDataSetInfo, error) { + return _FilecoinWarmStorageServiceStateView.Contract.GetDataSet(&_FilecoinWarmStorageServiceStateView.CallOpts, dataSetId) +} + +// GetDataSet is a free data retrieval call binding the contract method 0xbdaac056. +// +// Solidity: function getDataSet(uint256 dataSetId) view returns((uint256,uint256,uint256,address,address,address,uint256,uint256,uint256,uint256,uint256) info) +func (_FilecoinWarmStorageServiceStateView *FilecoinWarmStorageServiceStateViewCallerSession) GetDataSet(dataSetId *big.Int) (FilecoinWarmStorageServiceDataSetInfo, error) { + return _FilecoinWarmStorageServiceStateView.Contract.GetDataSet(&_FilecoinWarmStorageServiceStateView.CallOpts, dataSetId) +} + +// GetDataSetMetadata is a free data retrieval call binding the contract method 0x4dc17df1. +// +// Solidity: function getDataSetMetadata(uint256 dataSetId, string key) view returns(bool exists, string value) +func (_FilecoinWarmStorageServiceStateView *FilecoinWarmStorageServiceStateViewCaller) GetDataSetMetadata(opts *bind.CallOpts, dataSetId *big.Int, key string) (struct { + Exists bool + Value string +}, error) { + var out []interface{} + err := _FilecoinWarmStorageServiceStateView.contract.Call(opts, &out, "getDataSetMetadata", dataSetId, key) + + outstruct := new(struct { + Exists bool + Value string + }) + if err != nil { + return *outstruct, err + } + + outstruct.Exists = *abi.ConvertType(out[0], new(bool)).(*bool) + outstruct.Value = *abi.ConvertType(out[1], new(string)).(*string) + + return *outstruct, err + +} + +// GetDataSetMetadata is a free data retrieval call binding the contract method 0x4dc17df1. +// +// Solidity: function getDataSetMetadata(uint256 dataSetId, string key) view returns(bool exists, string value) +func (_FilecoinWarmStorageServiceStateView *FilecoinWarmStorageServiceStateViewSession) GetDataSetMetadata(dataSetId *big.Int, key string) (struct { + Exists bool + Value string +}, error) { + return _FilecoinWarmStorageServiceStateView.Contract.GetDataSetMetadata(&_FilecoinWarmStorageServiceStateView.CallOpts, dataSetId, key) +} + +// GetDataSetMetadata is a free data retrieval call binding the contract method 0x4dc17df1. +// +// Solidity: function getDataSetMetadata(uint256 dataSetId, string key) view returns(bool exists, string value) +func (_FilecoinWarmStorageServiceStateView *FilecoinWarmStorageServiceStateViewCallerSession) GetDataSetMetadata(dataSetId *big.Int, key string) (struct { + Exists bool + Value string +}, error) { + return _FilecoinWarmStorageServiceStateView.Contract.GetDataSetMetadata(&_FilecoinWarmStorageServiceStateView.CallOpts, dataSetId, key) +} + +// GetDataSetSizeInBytes is a free data retrieval call binding the contract method 0xfe295953. +// +// Solidity: function getDataSetSizeInBytes(uint256 leafCount) pure returns(uint256) +func (_FilecoinWarmStorageServiceStateView *FilecoinWarmStorageServiceStateViewCaller) GetDataSetSizeInBytes(opts *bind.CallOpts, leafCount *big.Int) (*big.Int, error) { + var out []interface{} + err := _FilecoinWarmStorageServiceStateView.contract.Call(opts, &out, "getDataSetSizeInBytes", leafCount) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// GetDataSetSizeInBytes is a free data retrieval call binding the contract method 0xfe295953. +// +// Solidity: function getDataSetSizeInBytes(uint256 leafCount) pure returns(uint256) +func (_FilecoinWarmStorageServiceStateView *FilecoinWarmStorageServiceStateViewSession) GetDataSetSizeInBytes(leafCount *big.Int) (*big.Int, error) { + return _FilecoinWarmStorageServiceStateView.Contract.GetDataSetSizeInBytes(&_FilecoinWarmStorageServiceStateView.CallOpts, leafCount) +} + +// GetDataSetSizeInBytes is a free data retrieval call binding the contract method 0xfe295953. +// +// Solidity: function getDataSetSizeInBytes(uint256 leafCount) pure returns(uint256) +func (_FilecoinWarmStorageServiceStateView *FilecoinWarmStorageServiceStateViewCallerSession) GetDataSetSizeInBytes(leafCount *big.Int) (*big.Int, error) { + return _FilecoinWarmStorageServiceStateView.Contract.GetDataSetSizeInBytes(&_FilecoinWarmStorageServiceStateView.CallOpts, leafCount) +} + +// GetMaxProvingPeriod is a free data retrieval call binding the contract method 0xf2f12333. +// +// Solidity: function getMaxProvingPeriod() view returns(uint64) +func (_FilecoinWarmStorageServiceStateView *FilecoinWarmStorageServiceStateViewCaller) GetMaxProvingPeriod(opts *bind.CallOpts) (uint64, error) { + var out []interface{} + err := _FilecoinWarmStorageServiceStateView.contract.Call(opts, &out, "getMaxProvingPeriod") + + if err != nil { + return *new(uint64), err + } + + out0 := *abi.ConvertType(out[0], new(uint64)).(*uint64) + + return out0, err + +} + +// GetMaxProvingPeriod is a free data retrieval call binding the contract method 0xf2f12333. +// +// Solidity: function getMaxProvingPeriod() view returns(uint64) +func (_FilecoinWarmStorageServiceStateView *FilecoinWarmStorageServiceStateViewSession) GetMaxProvingPeriod() (uint64, error) { + return _FilecoinWarmStorageServiceStateView.Contract.GetMaxProvingPeriod(&_FilecoinWarmStorageServiceStateView.CallOpts) +} + +// GetMaxProvingPeriod is a free data retrieval call binding the contract method 0xf2f12333. +// +// Solidity: function getMaxProvingPeriod() view returns(uint64) +func (_FilecoinWarmStorageServiceStateView *FilecoinWarmStorageServiceStateViewCallerSession) GetMaxProvingPeriod() (uint64, error) { + return _FilecoinWarmStorageServiceStateView.Contract.GetMaxProvingPeriod(&_FilecoinWarmStorageServiceStateView.CallOpts) +} + +// GetPDPConfig is a free data retrieval call binding the contract method 0xea0f9354. +// +// Solidity: function getPDPConfig() view returns(uint64 maxProvingPeriod, uint256 challengeWindowSize, uint256 challengesPerProof, uint256 initChallengeWindowStart) +func (_FilecoinWarmStorageServiceStateView *FilecoinWarmStorageServiceStateViewCaller) GetPDPConfig(opts *bind.CallOpts) (struct { + MaxProvingPeriod uint64 + ChallengeWindowSize *big.Int + ChallengesPerProof *big.Int + InitChallengeWindowStart *big.Int +}, error) { + var out []interface{} + err := _FilecoinWarmStorageServiceStateView.contract.Call(opts, &out, "getPDPConfig") + + outstruct := new(struct { + MaxProvingPeriod uint64 + ChallengeWindowSize *big.Int + ChallengesPerProof *big.Int + InitChallengeWindowStart *big.Int + }) + if err != nil { + return *outstruct, err + } + + outstruct.MaxProvingPeriod = *abi.ConvertType(out[0], new(uint64)).(*uint64) + outstruct.ChallengeWindowSize = *abi.ConvertType(out[1], new(*big.Int)).(**big.Int) + outstruct.ChallengesPerProof = *abi.ConvertType(out[2], new(*big.Int)).(**big.Int) + outstruct.InitChallengeWindowStart = *abi.ConvertType(out[3], new(*big.Int)).(**big.Int) + + return *outstruct, err + +} + +// GetPDPConfig is a free data retrieval call binding the contract method 0xea0f9354. +// +// Solidity: function getPDPConfig() view returns(uint64 maxProvingPeriod, uint256 challengeWindowSize, uint256 challengesPerProof, uint256 initChallengeWindowStart) +func (_FilecoinWarmStorageServiceStateView *FilecoinWarmStorageServiceStateViewSession) GetPDPConfig() (struct { + MaxProvingPeriod uint64 + ChallengeWindowSize *big.Int + ChallengesPerProof *big.Int + InitChallengeWindowStart *big.Int +}, error) { + return _FilecoinWarmStorageServiceStateView.Contract.GetPDPConfig(&_FilecoinWarmStorageServiceStateView.CallOpts) +} + +// GetPDPConfig is a free data retrieval call binding the contract method 0xea0f9354. +// +// Solidity: function getPDPConfig() view returns(uint64 maxProvingPeriod, uint256 challengeWindowSize, uint256 challengesPerProof, uint256 initChallengeWindowStart) +func (_FilecoinWarmStorageServiceStateView *FilecoinWarmStorageServiceStateViewCallerSession) GetPDPConfig() (struct { + MaxProvingPeriod uint64 + ChallengeWindowSize *big.Int + ChallengesPerProof *big.Int + InitChallengeWindowStart *big.Int +}, error) { + return _FilecoinWarmStorageServiceStateView.Contract.GetPDPConfig(&_FilecoinWarmStorageServiceStateView.CallOpts) +} + +// GetPieceMetadata is a free data retrieval call binding the contract method 0x837a7f49. +// +// Solidity: function getPieceMetadata(uint256 dataSetId, uint256 pieceId, string key) view returns(bool exists, string value) +func (_FilecoinWarmStorageServiceStateView *FilecoinWarmStorageServiceStateViewCaller) GetPieceMetadata(opts *bind.CallOpts, dataSetId *big.Int, pieceId *big.Int, key string) (struct { + Exists bool + Value string +}, error) { + var out []interface{} + err := _FilecoinWarmStorageServiceStateView.contract.Call(opts, &out, "getPieceMetadata", dataSetId, pieceId, key) + + outstruct := new(struct { + Exists bool + Value string + }) + if err != nil { + return *outstruct, err + } + + outstruct.Exists = *abi.ConvertType(out[0], new(bool)).(*bool) + outstruct.Value = *abi.ConvertType(out[1], new(string)).(*string) + + return *outstruct, err + +} + +// GetPieceMetadata is a free data retrieval call binding the contract method 0x837a7f49. +// +// Solidity: function getPieceMetadata(uint256 dataSetId, uint256 pieceId, string key) view returns(bool exists, string value) +func (_FilecoinWarmStorageServiceStateView *FilecoinWarmStorageServiceStateViewSession) GetPieceMetadata(dataSetId *big.Int, pieceId *big.Int, key string) (struct { + Exists bool + Value string +}, error) { + return _FilecoinWarmStorageServiceStateView.Contract.GetPieceMetadata(&_FilecoinWarmStorageServiceStateView.CallOpts, dataSetId, pieceId, key) +} + +// GetPieceMetadata is a free data retrieval call binding the contract method 0x837a7f49. +// +// Solidity: function getPieceMetadata(uint256 dataSetId, uint256 pieceId, string key) view returns(bool exists, string value) +func (_FilecoinWarmStorageServiceStateView *FilecoinWarmStorageServiceStateViewCallerSession) GetPieceMetadata(dataSetId *big.Int, pieceId *big.Int, key string) (struct { + Exists bool + Value string +}, error) { + return _FilecoinWarmStorageServiceStateView.Contract.GetPieceMetadata(&_FilecoinWarmStorageServiceStateView.CallOpts, dataSetId, pieceId, key) +} + +// IsProviderApproved is a free data retrieval call binding the contract method 0xb6133b7a. +// +// Solidity: function isProviderApproved(uint256 providerId) view returns(bool) +func (_FilecoinWarmStorageServiceStateView *FilecoinWarmStorageServiceStateViewCaller) IsProviderApproved(opts *bind.CallOpts, providerId *big.Int) (bool, error) { + var out []interface{} + err := _FilecoinWarmStorageServiceStateView.contract.Call(opts, &out, "isProviderApproved", providerId) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// IsProviderApproved is a free data retrieval call binding the contract method 0xb6133b7a. +// +// Solidity: function isProviderApproved(uint256 providerId) view returns(bool) +func (_FilecoinWarmStorageServiceStateView *FilecoinWarmStorageServiceStateViewSession) IsProviderApproved(providerId *big.Int) (bool, error) { + return _FilecoinWarmStorageServiceStateView.Contract.IsProviderApproved(&_FilecoinWarmStorageServiceStateView.CallOpts, providerId) +} + +// IsProviderApproved is a free data retrieval call binding the contract method 0xb6133b7a. +// +// Solidity: function isProviderApproved(uint256 providerId) view returns(bool) +func (_FilecoinWarmStorageServiceStateView *FilecoinWarmStorageServiceStateViewCallerSession) IsProviderApproved(providerId *big.Int) (bool, error) { + return _FilecoinWarmStorageServiceStateView.Contract.IsProviderApproved(&_FilecoinWarmStorageServiceStateView.CallOpts, providerId) +} + +// NextPDPChallengeWindowStart is a free data retrieval call binding the contract method 0x11d41294. +// +// Solidity: function nextPDPChallengeWindowStart(uint256 setId) view returns(uint256) +func (_FilecoinWarmStorageServiceStateView *FilecoinWarmStorageServiceStateViewCaller) NextPDPChallengeWindowStart(opts *bind.CallOpts, setId *big.Int) (*big.Int, error) { + var out []interface{} + err := _FilecoinWarmStorageServiceStateView.contract.Call(opts, &out, "nextPDPChallengeWindowStart", setId) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// NextPDPChallengeWindowStart is a free data retrieval call binding the contract method 0x11d41294. +// +// Solidity: function nextPDPChallengeWindowStart(uint256 setId) view returns(uint256) +func (_FilecoinWarmStorageServiceStateView *FilecoinWarmStorageServiceStateViewSession) NextPDPChallengeWindowStart(setId *big.Int) (*big.Int, error) { + return _FilecoinWarmStorageServiceStateView.Contract.NextPDPChallengeWindowStart(&_FilecoinWarmStorageServiceStateView.CallOpts, setId) +} + +// NextPDPChallengeWindowStart is a free data retrieval call binding the contract method 0x11d41294. +// +// Solidity: function nextPDPChallengeWindowStart(uint256 setId) view returns(uint256) +func (_FilecoinWarmStorageServiceStateView *FilecoinWarmStorageServiceStateViewCallerSession) NextPDPChallengeWindowStart(setId *big.Int) (*big.Int, error) { + return _FilecoinWarmStorageServiceStateView.Contract.NextPDPChallengeWindowStart(&_FilecoinWarmStorageServiceStateView.CallOpts, setId) +} + +// ProvenPeriods is a free data retrieval call binding the contract method 0x698762cb. +// +// Solidity: function provenPeriods(uint256 dataSetId, uint256 periodId) view returns(bool) +func (_FilecoinWarmStorageServiceStateView *FilecoinWarmStorageServiceStateViewCaller) ProvenPeriods(opts *bind.CallOpts, dataSetId *big.Int, periodId *big.Int) (bool, error) { + var out []interface{} + err := _FilecoinWarmStorageServiceStateView.contract.Call(opts, &out, "provenPeriods", dataSetId, periodId) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// ProvenPeriods is a free data retrieval call binding the contract method 0x698762cb. +// +// Solidity: function provenPeriods(uint256 dataSetId, uint256 periodId) view returns(bool) +func (_FilecoinWarmStorageServiceStateView *FilecoinWarmStorageServiceStateViewSession) ProvenPeriods(dataSetId *big.Int, periodId *big.Int) (bool, error) { + return _FilecoinWarmStorageServiceStateView.Contract.ProvenPeriods(&_FilecoinWarmStorageServiceStateView.CallOpts, dataSetId, periodId) +} + +// ProvenPeriods is a free data retrieval call binding the contract method 0x698762cb. +// +// Solidity: function provenPeriods(uint256 dataSetId, uint256 periodId) view returns(bool) +func (_FilecoinWarmStorageServiceStateView *FilecoinWarmStorageServiceStateViewCallerSession) ProvenPeriods(dataSetId *big.Int, periodId *big.Int) (bool, error) { + return _FilecoinWarmStorageServiceStateView.Contract.ProvenPeriods(&_FilecoinWarmStorageServiceStateView.CallOpts, dataSetId, periodId) +} + +// ProvenThisPeriod is a free data retrieval call binding the contract method 0x7598a1cd. +// +// Solidity: function provenThisPeriod(uint256 dataSetId) view returns(bool) +func (_FilecoinWarmStorageServiceStateView *FilecoinWarmStorageServiceStateViewCaller) ProvenThisPeriod(opts *bind.CallOpts, dataSetId *big.Int) (bool, error) { + var out []interface{} + err := _FilecoinWarmStorageServiceStateView.contract.Call(opts, &out, "provenThisPeriod", dataSetId) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// ProvenThisPeriod is a free data retrieval call binding the contract method 0x7598a1cd. +// +// Solidity: function provenThisPeriod(uint256 dataSetId) view returns(bool) +func (_FilecoinWarmStorageServiceStateView *FilecoinWarmStorageServiceStateViewSession) ProvenThisPeriod(dataSetId *big.Int) (bool, error) { + return _FilecoinWarmStorageServiceStateView.Contract.ProvenThisPeriod(&_FilecoinWarmStorageServiceStateView.CallOpts, dataSetId) +} + +// ProvenThisPeriod is a free data retrieval call binding the contract method 0x7598a1cd. +// +// Solidity: function provenThisPeriod(uint256 dataSetId) view returns(bool) +func (_FilecoinWarmStorageServiceStateView *FilecoinWarmStorageServiceStateViewCallerSession) ProvenThisPeriod(dataSetId *big.Int) (bool, error) { + return _FilecoinWarmStorageServiceStateView.Contract.ProvenThisPeriod(&_FilecoinWarmStorageServiceStateView.CallOpts, dataSetId) +} + +// ProvingActivationEpoch is a free data retrieval call binding the contract method 0x725e3216. +// +// Solidity: function provingActivationEpoch(uint256 dataSetId) view returns(uint256) +func (_FilecoinWarmStorageServiceStateView *FilecoinWarmStorageServiceStateViewCaller) ProvingActivationEpoch(opts *bind.CallOpts, dataSetId *big.Int) (*big.Int, error) { + var out []interface{} + err := _FilecoinWarmStorageServiceStateView.contract.Call(opts, &out, "provingActivationEpoch", dataSetId) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// ProvingActivationEpoch is a free data retrieval call binding the contract method 0x725e3216. +// +// Solidity: function provingActivationEpoch(uint256 dataSetId) view returns(uint256) +func (_FilecoinWarmStorageServiceStateView *FilecoinWarmStorageServiceStateViewSession) ProvingActivationEpoch(dataSetId *big.Int) (*big.Int, error) { + return _FilecoinWarmStorageServiceStateView.Contract.ProvingActivationEpoch(&_FilecoinWarmStorageServiceStateView.CallOpts, dataSetId) +} + +// ProvingActivationEpoch is a free data retrieval call binding the contract method 0x725e3216. +// +// Solidity: function provingActivationEpoch(uint256 dataSetId) view returns(uint256) +func (_FilecoinWarmStorageServiceStateView *FilecoinWarmStorageServiceStateViewCallerSession) ProvingActivationEpoch(dataSetId *big.Int) (*big.Int, error) { + return _FilecoinWarmStorageServiceStateView.Contract.ProvingActivationEpoch(&_FilecoinWarmStorageServiceStateView.CallOpts, dataSetId) +} + +// ProvingDeadline is a free data retrieval call binding the contract method 0x149ac5cc. +// +// Solidity: function provingDeadline(uint256 setId) view returns(uint256) +func (_FilecoinWarmStorageServiceStateView *FilecoinWarmStorageServiceStateViewCaller) ProvingDeadline(opts *bind.CallOpts, setId *big.Int) (*big.Int, error) { + var out []interface{} + err := _FilecoinWarmStorageServiceStateView.contract.Call(opts, &out, "provingDeadline", setId) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// ProvingDeadline is a free data retrieval call binding the contract method 0x149ac5cc. +// +// Solidity: function provingDeadline(uint256 setId) view returns(uint256) +func (_FilecoinWarmStorageServiceStateView *FilecoinWarmStorageServiceStateViewSession) ProvingDeadline(setId *big.Int) (*big.Int, error) { + return _FilecoinWarmStorageServiceStateView.Contract.ProvingDeadline(&_FilecoinWarmStorageServiceStateView.CallOpts, setId) +} + +// ProvingDeadline is a free data retrieval call binding the contract method 0x149ac5cc. +// +// Solidity: function provingDeadline(uint256 setId) view returns(uint256) +func (_FilecoinWarmStorageServiceStateView *FilecoinWarmStorageServiceStateViewCallerSession) ProvingDeadline(setId *big.Int) (*big.Int, error) { + return _FilecoinWarmStorageServiceStateView.Contract.ProvingDeadline(&_FilecoinWarmStorageServiceStateView.CallOpts, setId) +} + +// RailToDataSet is a free data retrieval call binding the contract method 0x2ad6e6b5. +// +// Solidity: function railToDataSet(uint256 railId) view returns(uint256) +func (_FilecoinWarmStorageServiceStateView *FilecoinWarmStorageServiceStateViewCaller) RailToDataSet(opts *bind.CallOpts, railId *big.Int) (*big.Int, error) { + var out []interface{} + err := _FilecoinWarmStorageServiceStateView.contract.Call(opts, &out, "railToDataSet", railId) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// RailToDataSet is a free data retrieval call binding the contract method 0x2ad6e6b5. +// +// Solidity: function railToDataSet(uint256 railId) view returns(uint256) +func (_FilecoinWarmStorageServiceStateView *FilecoinWarmStorageServiceStateViewSession) RailToDataSet(railId *big.Int) (*big.Int, error) { + return _FilecoinWarmStorageServiceStateView.Contract.RailToDataSet(&_FilecoinWarmStorageServiceStateView.CallOpts, railId) +} + +// RailToDataSet is a free data retrieval call binding the contract method 0x2ad6e6b5. +// +// Solidity: function railToDataSet(uint256 railId) view returns(uint256) +func (_FilecoinWarmStorageServiceStateView *FilecoinWarmStorageServiceStateViewCallerSession) RailToDataSet(railId *big.Int) (*big.Int, error) { + return _FilecoinWarmStorageServiceStateView.Contract.RailToDataSet(&_FilecoinWarmStorageServiceStateView.CallOpts, railId) +} + +// Service is a free data retrieval call binding the contract method 0xd598d4c9. +// +// Solidity: function service() view returns(address) +func (_FilecoinWarmStorageServiceStateView *FilecoinWarmStorageServiceStateViewCaller) Service(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _FilecoinWarmStorageServiceStateView.contract.Call(opts, &out, "service") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// Service is a free data retrieval call binding the contract method 0xd598d4c9. +// +// Solidity: function service() view returns(address) +func (_FilecoinWarmStorageServiceStateView *FilecoinWarmStorageServiceStateViewSession) Service() (common.Address, error) { + return _FilecoinWarmStorageServiceStateView.Contract.Service(&_FilecoinWarmStorageServiceStateView.CallOpts) +} + +// Service is a free data retrieval call binding the contract method 0xd598d4c9. +// +// Solidity: function service() view returns(address) +func (_FilecoinWarmStorageServiceStateView *FilecoinWarmStorageServiceStateViewCallerSession) Service() (common.Address, error) { + return _FilecoinWarmStorageServiceStateView.Contract.Service(&_FilecoinWarmStorageServiceStateView.CallOpts) +} diff --git a/pdp/contract/addresses.go b/pdp/contract/addresses.go index ca62ee653..c76820174 100644 --- a/pdp/contract/addresses.go +++ b/pdp/contract/addresses.go @@ -22,6 +22,7 @@ func ContractAddresses() PDPContracts { return PDPContracts{ PDPVerifier: common.HexToAddress("0x445238Eca6c6aB8Dff1Aa6087d9c05734D22f137"), AllowedPublicRecordKeepers: []common.Address{ + common.HexToAddress("0x92B51cefF7eBc721Ad0F1fB09505E75F67DCAac6"), // Simple common.HexToAddress("0x80617b65FD2EEa1D7fDe2B4F85977670690ed348"), // FilecoinWarmStorageService }, } diff --git a/pdp/contract/utils.go b/pdp/contract/utils.go index 72167f2bf..5b0f037f0 100644 --- a/pdp/contract/utils.go +++ b/pdp/contract/utils.go @@ -1,6 +1,8 @@ package contract import ( + "math/big" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/ethclient" "golang.org/x/xerrors" @@ -35,3 +37,24 @@ func GetProvingScheduleFromListener(listenerAddr common.Address, ethClient *ethc return provingSchedule, nil } + +func GetDataSetMetadataAtKey(listenerAddr common.Address, ethClient *ethclient.Client, dataSetId *big.Int, key string) (bool, string, error) { + metadataAddr := listenerAddr + + // Check if the listener supports the viewContractAddress method + listenerService, err := NewListenerServiceWithViewContract(listenerAddr, ethClient) + if err == nil { + viewAddr, err := listenerService.ViewContractAddress(nil) + if err == nil && viewAddr != (common.Address{}) { + metadataAddr = viewAddr + } + } + + // Create a warm storage service viewer. + warmStorageService, err := NewFilecoinWarmStorageServiceStateView(metadataAddr, ethClient) + if err != nil { + return false, "", xerrors.Errorf("failed to create warm storage service viewer: %w", err) + } + out, err := warmStorageService.GetDataSetMetadata(nil, dataSetId, key) + return out.Exists, out.Value, err +} diff --git a/pdp/handlers.go b/pdp/handlers.go index 1e60bc231..9a226182f 100644 --- a/pdp/handlers.go +++ b/pdp/handlers.go @@ -974,7 +974,30 @@ func (p *PDPService) handleAddPieceToDataSet(w http.ResponseWriter, r *http.Requ return } - // Step 9: Insert into message_waits_eth and pdp_data_set_pieces + // Step 9: check for indexing requirements on data set. + // Get listenerAddr from blockchain contract + pdpVerifier, err := contract.NewPDPVerifier(contract.ContractAddresses().PDPVerifier, p.ethClient) + if err != nil { + log.Errorw("Failed to instantiate PDPVerifier contract", "error", err, "dataSetId", dataSetId) + http.Error(w, "Internal server error", http.StatusInternalServerError) + return + } + listenerAddr, err := pdpVerifier.GetDataSetListener(nil, dataSetId) + if err != nil { + log.Errorw("Failed to get listener address for data set", "error", err, "dataSetId", dataSetId) + http.Error(w, "Internal server error", http.StatusInternalServerError) + return + } + mustIndex, _, err := contract.GetDataSetMetadataAtKey(listenerAddr, p.ethClient, dataSetId, "withIPFSIndexing") + if err != nil { + // Hard to differenctiate between unsupported listener type OR internal error + // So we log on debug and skip indexing attempt + mustIndex = false + log.Infow("Failed to get data set metadata, skipping indexing ", "error", err, "dataSetId", dataSetId) + } + + // Step 10: Insert into message_waits_eth and pdp_data_set_pieces + // If indexing required update pdp_piecerefs table with indexing requirement // Ensure consistent lowercase transaction hash txHashLower := strings.ToLower(txHash.Hex()) log.Infow("PDP AddPieces: Inserting transaction tracking", @@ -1007,7 +1030,6 @@ func (p *PDPService) handleAddPieceToDataSet(w http.ResponseWriter, r *http.Requ } // Insert into pdp_data_set_pieces - for addMessageIndex, addPieceReq := range payload.Pieces { for _, subPieceEntry := range addPieceReq.SubPieces { subPieceInfo := subPieceInfoMap[subPieceEntry.subPieceCIDv1] @@ -1041,6 +1063,22 @@ func (p *PDPService) handleAddPieceToDataSet(w http.ResponseWriter, r *http.Requ } } + if mustIndex { + log.Debugw("Data set metadata exists, marking all subpiecesas needing indexing", "dataSetId", dataSetId) + // Note: it's possible to update a duplicate piece that has already completed the indexing step + // but task_pdp_indexing handles pieces that have already been indexed smoothly + _, err := txdb.Exec(` + UPDATE pdp_piecerefs + SET needs_indexing = TRUE + WHERE service = $1 + AND piece_cid = ANY($2) + AND needs_indexing = FALSE + `, serviceLabel, subPieceCidList) + if err != nil { + return false, err + } + } + // Return true to commit the transaction return true, nil }, harmonydb.OptionRetry()) @@ -1050,7 +1088,7 @@ func (p *PDPService) handleAddPieceToDataSet(w http.ResponseWriter, r *http.Requ return } - // Step 10: Respond with 201 Created + // Step 11: Respond with 201 Created w.Header().Set("Location", path.Join("/pdp/data-sets", dataSetIdStr, "pieces/added", txHashLower)) w.WriteHeader(http.StatusCreated) } diff --git a/pdp/handlers_upload.go b/pdp/handlers_upload.go index 809137875..f6e38d712 100644 --- a/pdp/handlers_upload.go +++ b/pdp/handlers_upload.go @@ -53,7 +53,7 @@ func (p *PDPService) handlePiecePost(w http.ResponseWriter, r *http.Request) { } pieceCidV2, size, err := asPieceCIDv2(req.PieceCID, 0) if err != nil { - http.Error(w, "Invalid request body: invalid pieceCid", http.StatusBadRequest) + http.Error(w, "Invalid request body: invalid pieceCid: "+err.Error(), http.StatusBadRequest) return } if size > uint64(PieceSizeLimit) { diff --git a/tasks/indexing/task_pdp_indexing.go b/tasks/indexing/task_pdp_indexing.go new file mode 100644 index 000000000..868269bb9 --- /dev/null +++ b/tasks/indexing/task_pdp_indexing.go @@ -0,0 +1,270 @@ +package indexing + +import ( + "bufio" + "context" + "errors" + "fmt" + "io" + "time" + + "github.com/ipfs/go-cid" + carv2 "github.com/ipld/go-car/v2" + "golang.org/x/sync/errgroup" + "golang.org/x/xerrors" + + "github.com/filecoin-project/curio/deps/config" + "github.com/filecoin-project/curio/harmony/harmonydb" + "github.com/filecoin-project/curio/harmony/harmonytask" + "github.com/filecoin-project/curio/harmony/resources" + "github.com/filecoin-project/curio/harmony/taskhelp" + "github.com/filecoin-project/curio/lib/cachedreader" + "github.com/filecoin-project/curio/lib/passcall" + "github.com/filecoin-project/curio/market/indexstore" +) + +type PDPIndexingTask struct { + db *harmonydb.DB + indexStore *indexstore.IndexStore + cpr *cachedreader.CachedPieceReader + cfg *config.CurioConfig + insertConcurrency int + insertBatchSize int + max taskhelp.Limiter +} + +func NewPDPIndexingTask(db *harmonydb.DB, indexStore *indexstore.IndexStore, cpr *cachedreader.CachedPieceReader, cfg *config.CurioConfig, max taskhelp.Limiter) *PDPIndexingTask { + + return &PDPIndexingTask{ + db: db, + indexStore: indexStore, + cpr: cpr, + cfg: cfg, + insertConcurrency: cfg.Market.StorageMarketConfig.Indexing.InsertConcurrency, + insertBatchSize: cfg.Market.StorageMarketConfig.Indexing.InsertBatchSize, + max: max, + } +} + +func (P *PDPIndexingTask) Do(taskID harmonytask.TaskID, stillOwned func() bool) (done bool, err error) { + ctx := context.Background() + + var tasks []struct { + ID int64 `db:"id"` + PieceCID string `db:"piece_cid"` + PieceRef int64 `db:"piece_ref"` + } + + err = P.db.Select(ctx, &tasks, `SELECT id, piece_cid, piece_ref FROM pdp_piecerefs WHERE indexing_task_id = $1 AND needs_indexing = TRUE`, taskID) + if err != nil { + return false, xerrors.Errorf("getting PDP pending indexing tasks: %w", err) + } + + if len(tasks) != 1 { + return false, xerrors.Errorf("incorrect rows for pending indexing tasks: %d", len(tasks)) + } + task := tasks[0] + + pcid, err := cid.Parse(task.PieceCID) + if err != nil { + return false, xerrors.Errorf("parsing piece CID: %w", err) + } + + hasIndex, err := P.indexStore.CheckHasPiece(ctx, pcid) + if err != nil { + return false, xerrors.Errorf("checking if piece is already indexed: %w", err) + } + if hasIndex { + // Piece already indexed so earlier indexing should have completed IPNI + err = P.recordCompletion(ctx, taskID, task.ID, false) + if err != nil { + return false, err + } + return true, nil + } + + reader, _, err := P.cpr.GetSharedPieceReader(ctx, pcid) + if err != nil { + return false, xerrors.Errorf("getting piece reader: %w", err) + } + defer func() { + _ = reader.Close() + }() + + startTime := time.Now() + + // Note: These are not technically PDP config values, but we can share them with porep deal cfg + dealCfg := P.cfg.Market.StorageMarketConfig + chanSize := dealCfg.Indexing.InsertConcurrency * dealCfg.Indexing.InsertBatchSize + + recs := make(chan indexstore.Record, chanSize) + var blocks int64 + + var eg errgroup.Group + addFail := make(chan struct{}) + var interrupted bool + + eg.Go(func() error { + defer close(addFail) + return P.indexStore.AddIndex(ctx, pcid, recs) + }) + blocks, interrupted, err = IndexCAR(reader, 4<<20, recs, addFail) + if err != nil { + // Indexing itself failed, stop early + close(recs) // still safe to close, AddIndex will exit on channel close + // wait for AddIndex goroutine to finish cleanly + _ = eg.Wait() + return false, xerrors.Errorf("indexing failed: %w", err) + } + + // Close the channel + close(recs) + + // Wait till AddIndex is finished + err = eg.Wait() + if err != nil { + return false, xerrors.Errorf("adding index to DB (interrupted %t): %w", interrupted, err) + } + + log.Infof("Indexing piece %d took %0.3f seconds", task.ID, time.Since(startTime).Seconds()) + + err = P.recordCompletion(ctx, taskID, task.ID, true) + if err != nil { + return false, err + } + + blocksPerSecond := float64(blocks) / time.Since(startTime).Seconds() + log.Infow("Piece indexed", "piece_cid", task.PieceCID, "id", task.ID, "blocks", blocks, "blocks_per_second", blocksPerSecond) + + return true, nil +} + +func (P *PDPIndexingTask) recordCompletion(ctx context.Context, taskID harmonytask.TaskID, id int64, needsIPNI bool) error { + comm, err := P.db.BeginTransaction(ctx, func(tx *harmonydb.Tx) (commit bool, err error) { + + n, err := P.db.Exec(ctx, `UPDATE pdp_piecerefs SET needs_indexing = FALSE, needs_ipni = $3, indexing_task_id = NULL + WHERE id = $1 AND indexing_task_id = $2`, id, taskID, needsIPNI) + if err != nil { + return false, xerrors.Errorf("store indexing success: updating pipeline: %w", err) + } + if n != 1 { + return false, xerrors.Errorf("store indexing success: updated %d rows", n) + } + return true, nil + }, harmonydb.OptionRetry()) + if err != nil { + return xerrors.Errorf("committing transaction: %w", err) + } + if !comm { + return xerrors.Errorf("failed to commit transaction") + } + + return nil +} + +func (P *PDPIndexingTask) CanAccept(ids []harmonytask.TaskID, engine *harmonytask.TaskEngine) (*harmonytask.TaskID, error) { + // We just accept all tasks + // Note that this differs from markets v2 code which does a local storage check on the piece. + // + // If we are ever in an instance where the shared piece reader is expected to go to sector storage and will actually benefit from these local checks + // then we should be using markets v2 code because then we'll be in a shared datasource world. In the rare case where an SP is handling PDP and PoRep on + // a cluster and just so happens to have a collision then the network overhead of moving a piece around will be small. + id := ids[0] + return &id, nil +} + +func (P *PDPIndexingTask) TypeDetails() harmonytask.TaskTypeDetails { + return harmonytask.TaskTypeDetails{ + Name: "PDPIndexing", + Cost: resources.Resources{ + Cpu: 1, + Ram: uint64(P.insertBatchSize * P.insertConcurrency * 56 * 2), + }, + Max: P.max, + MaxFailures: 3, + IAmBored: passcall.Every(3*time.Second, func(taskFunc harmonytask.AddTaskFunc) error { + return P.schedule(context.Background(), taskFunc) + }), + } +} + +func (P *PDPIndexingTask) schedule(_ context.Context, taskFunc harmonytask.AddTaskFunc) error { + // schedule submits + var stop bool + for !stop { + taskFunc(func(id harmonytask.TaskID, tx *harmonydb.Tx) (shouldCommit bool, seriousError error) { + stop = true // assume we're done until we find a task to schedule + + var pendings []struct { + ID string `db:"id"` + } + + err := tx.Select(&pendings, `SELECT id FROM pdp_piecerefs + WHERE indexing_task_id IS NULL + AND needs_indexing = TRUE + ORDER BY created_at ASC LIMIT 1;`) + if err != nil { + return false, xerrors.Errorf("getting PDP pending indexing tasks: %w", err) + } + + if len(pendings) == 0 { + return false, nil + } + + pending := pendings[0] + _, err = tx.Exec(`UPDATE pdp_piecerefs SET indexing_task_id = $1 + WHERE indexing_task_id IS NULL AND id = $2`, id, pending.ID) + if err != nil { + return false, xerrors.Errorf("updating PDP indexing task id: %w", err) + } + + stop = false + return true, nil + }) + } + + return nil +} + +func (P *PDPIndexingTask) Adder(taskFunc harmonytask.AddTaskFunc) {} + +var _ harmonytask.TaskInterface = &PDPIndexingTask{} +var _ = harmonytask.Reg(&PDPIndexingTask{}) + +func IndexCAR(r io.Reader, buffSize int, recs chan<- indexstore.Record, addFail <-chan struct{}) (int64, bool, error) { + blockReader, err := carv2.NewBlockReader(bufio.NewReaderSize(r, buffSize), carv2.ZeroLengthSectionAsEOF(true)) + if err != nil { + return 0, false, fmt.Errorf("getting block reader over piece: %w", err) + } + + var blocks int64 + var interrupted bool + + for { + blockMetadata, err := blockReader.SkipNext() + if err != nil { + if errors.Is(err, io.EOF) { + break + } + return blocks, interrupted, fmt.Errorf("generating index for piece: %w", err) + } + + blocks++ + + select { + case recs <- indexstore.Record{ + Cid: blockMetadata.Cid, + Offset: blockMetadata.SourceOffset, + Size: blockMetadata.Size, + }: + case <-addFail: + interrupted = true + } + + if interrupted { + break + } + } + + return blocks, interrupted, nil +} diff --git a/tasks/indexing/task_pdp_ipni.go b/tasks/indexing/task_pdp_ipni.go new file mode 100644 index 000000000..be2f4b0e3 --- /dev/null +++ b/tasks/indexing/task_pdp_ipni.go @@ -0,0 +1,427 @@ +package indexing + +import ( + "bufio" + "context" + "crypto/rand" + "errors" + "fmt" + "io" + "net/url" + "strings" + "time" + + "github.com/ipfs/go-cid" + carv2 "github.com/ipld/go-car/v2" + cidlink "github.com/ipld/go-ipld-prime/linking/cid" + "github.com/ipni/go-libipni/ingest/schema" + "github.com/ipni/go-libipni/maurl" + "github.com/ipni/go-libipni/metadata" + "github.com/libp2p/go-libp2p/core/crypto" + "github.com/libp2p/go-libp2p/core/peer" + "github.com/yugabyte/pgx/v5" + "golang.org/x/xerrors" + + "github.com/filecoin-project/curio/build" + "github.com/filecoin-project/curio/deps/config" + "github.com/filecoin-project/curio/harmony/harmonydb" + "github.com/filecoin-project/curio/harmony/harmonytask" + "github.com/filecoin-project/curio/harmony/resources" + "github.com/filecoin-project/curio/harmony/taskhelp" + "github.com/filecoin-project/curio/lib/cachedreader" + "github.com/filecoin-project/curio/lib/ffi" + "github.com/filecoin-project/curio/lib/passcall" + "github.com/filecoin-project/curio/market/ipni/chunker" + "github.com/filecoin-project/curio/market/ipni/ipniculib" +) + +const ( + PDP_SP_ID = -2 // This is the SP ID for PDP in the IPNI table +) + +type PDPIPNITask struct { + db *harmonydb.DB + cpr *cachedreader.CachedPieceReader + cfg *config.CurioConfig + max taskhelp.Limiter +} + +func NewPDPIPNITask(db *harmonydb.DB, sc *ffi.SealCalls, cpr *cachedreader.CachedPieceReader, cfg *config.CurioConfig, max taskhelp.Limiter) *PDPIPNITask { + return &PDPIPNITask{ + db: db, + cpr: cpr, + cfg: cfg, + max: max, + } +} + +func (P *PDPIPNITask) Do(taskID harmonytask.TaskID, stillOwned func() bool) (done bool, err error) { + ctx := context.Background() + + var tasks []struct { + ID int64 `db:"id"` + PieceCID string `db:"piece_cid"` + Size int64 `db:"piece_padded_size"` + Prov string `db:"peer_id"` + } + + err = P.db.Select(ctx, &tasks, ` + SELECT + pr.id, + pr.piece_cid, + pp.piece_padded_size, + ipni_peer.peer_id + FROM + pdp_piecerefs pr + JOIN parked_piece_refs ppr ON pr.piece_ref = ppr.ref_id + JOIN parked_pieces pp ON ppr.piece_id = pp.id + CROSS JOIN ipni_peerid ipni_peer + WHERE + pr.ipni_task_id = $1 + AND ipni_peer.sp_id = $2 +`, taskID, PDP_SP_ID) + if err != nil { + return false, xerrors.Errorf("getting ipni task params: %w", err) + } + + if len(tasks) != 1 { + return false, xerrors.Errorf("expected 1 ipni task params, got %d", len(tasks)) + } + + task := tasks[0] + + pcid, err := cid.Parse(task.PieceCID) + if err != nil { + return false, xerrors.Errorf("parsing piece CID: %w", err) + } + + mds := metadata.IpfsGatewayHttp{} + md, err := mds.MarshalBinary() + if err != nil { + return false, xerrors.Errorf("marshaling metadata: %w", err) + } + + pi := &PdpIpniContext{ + PieceCID: pcid, + Payload: true, + } + + iContext, err := pi.Marshal() + if err != nil { + return false, xerrors.Errorf("marshaling piece info: %w", err) + } + + reader, _, err := P.cpr.GetSharedPieceReader(ctx, pcid) + if err != nil { + return false, xerrors.Errorf("getting piece reader: %w", err) + } + defer func() { + _ = reader.Close() + }() + + opts := []carv2.Option{carv2.ZeroLengthSectionAsEOF(true)} + blockReader, err := carv2.NewBlockReader(bufio.NewReaderSize(reader, 4<<20), opts...) + if err != nil { + return false, fmt.Errorf("getting block reader over piece: %w", err) + } + + chk := chunker.NewInitialChunker() + + blockMetadata, err := blockReader.SkipNext() + for err == nil { + if err := chk.Accept(blockMetadata.Hash(), int64(blockMetadata.SourceOffset), blockMetadata.Size+40); err != nil { + return false, xerrors.Errorf("accepting block: %w", err) + } + + blockMetadata, err = blockReader.SkipNext() + } + if !errors.Is(err, io.EOF) { + return false, xerrors.Errorf("reading block: %w", err) + } + + // make sure we still own the task before writing to the database + if !stillOwned() { + return false, nil + } + + lnk, err := chk.Finish(ctx, P.db, pcid) + if err != nil { + return false, xerrors.Errorf("chunking CAR multihash iterator: %w", err) + } + + // make sure we still own the task before writing ad chains + if !stillOwned() { + return false, nil + } + + _, err = P.db.BeginTransaction(ctx, func(tx *harmonydb.Tx) (commit bool, err error) { + var prev string + err = tx.QueryRow(`SELECT head FROM ipni_head WHERE provider = $1`, task.Prov).Scan(&prev) + if err != nil && err != pgx.ErrNoRows { + return false, xerrors.Errorf("querying previous head: %w", err) + } + + var privKey []byte + err = tx.QueryRow(`SELECT priv_key FROM ipni_peerid WHERE sp_id = 0`).Scan(&privKey) + if err != nil { + return false, xerrors.Errorf("failed to get private ipni-libp2p key: %w", err) + } + + pkey, err := crypto.UnmarshalPrivateKey(privKey) + if err != nil { + return false, xerrors.Errorf("unmarshaling private key: %w", err) + } + + adv := schema.Advertisement{ + Provider: task.Prov, + Entries: lnk, + ContextID: iContext, + Metadata: md, + IsRm: false, // No PDP IPNI IsRms (yet) + } + + { + u, err := url.Parse(fmt.Sprintf("https://%s", P.cfg.HTTP.DomainName)) + if err != nil { + return false, xerrors.Errorf("parsing announce address domain: %w", err) + } + if build.BuildType != build.BuildMainnet && build.BuildType != build.BuildCalibnet { + ls := strings.Split(P.cfg.HTTP.ListenAddress, ":") + u, err = url.Parse(fmt.Sprintf("http://%s:%s", P.cfg.HTTP.DomainName, ls[1])) + if err != nil { + return false, xerrors.Errorf("parsing announce address domain: %w", err) + } + } + + addr, err := maurl.FromURL(u) + if err != nil { + return false, xerrors.Errorf("converting URL to multiaddr: %w", err) + } + + adv.Addresses = append(adv.Addresses, addr.String()) + } + + if prev != "" { + prevCID, err := cid.Parse(prev) + if err != nil { + return false, xerrors.Errorf("parsing previous CID: %w", err) + } + + adv.PreviousID = cidlink.Link{Cid: prevCID} + } + + err = adv.Sign(pkey) + if err != nil { + return false, xerrors.Errorf("signing the advertisement: %w", err) + } + + err = adv.Validate() + if err != nil { + return false, xerrors.Errorf("validating the advertisement: %w", err) + } + + adNode, err := adv.ToNode() + if err != nil { + return false, xerrors.Errorf("converting advertisement to node: %w", err) + } + + ad, err := ipniculib.NodeToLink(adNode, schema.Linkproto) + if err != nil { + return false, xerrors.Errorf("converting advertisement to link: %w", err) + } + + _, err = tx.Exec(`SELECT insert_ad_and_update_head($1, $2, $3, $4, $5, $6, $7, $8, $9)`, + ad.(cidlink.Link).Cid.String(), adv.ContextID, task.PieceCID, task.Size, adv.IsRm, adv.Provider, strings.Join(adv.Addresses, "|"), + adv.Signature, adv.Entries.String()) + + if err != nil { + return false, xerrors.Errorf("adding advertisement to the database: %w", err) + } + + err = P.recordCompletion(ctx, taskID, task.ID) + if err != nil { + return false, xerrors.Errorf("recording IPNI task completion: %w", err) + } + + return true, nil + + }, harmonydb.OptionRetry()) + if err != nil { + return false, xerrors.Errorf("store IPNI success: %w", err) + } + + log.Infow("IPNI task complete", "task_id", taskID, "piece_cid", task.PieceCID) + + return true, nil +} + +func (P *PDPIPNITask) recordCompletion(ctx context.Context, taskID harmonytask.TaskID, id int64) error { + comm, err := P.db.BeginTransaction(ctx, func(tx *harmonydb.Tx) (commit bool, err error) { + + n, err := P.db.Exec(ctx, `UPDATE pdp_piecerefs SET needs_ipni = FALSE, ipni_task_id = NULL + WHERE id = $1 AND ipni_task_id = $2`, id, taskID) + if err != nil { + return false, xerrors.Errorf("store indexing success: updating pipeline: %w", err) + } + if n != 1 { + return false, xerrors.Errorf("store indexing success: updated %d rows", n) + } + return true, nil + }, harmonydb.OptionRetry()) + if err != nil { + return xerrors.Errorf("committing transaction: %w", err) + } + if !comm { + return xerrors.Errorf("failed to commit transaction") + } + + return nil +} + +func (P *PDPIPNITask) CanAccept(ids []harmonytask.TaskID, engine *harmonytask.TaskEngine) (*harmonytask.TaskID, error) { + return &ids[0], nil +} + +func (P *PDPIPNITask) TypeDetails() harmonytask.TaskTypeDetails { + return harmonytask.TaskTypeDetails{ + Name: "PDPIpni", + Cost: resources.Resources{ + Cpu: 1, + Ram: 1 << 30, + }, + MaxFailures: 3, + IAmBored: passcall.Every(30*time.Second, func(taskFunc harmonytask.AddTaskFunc) error { + return P.schedule(context.Background(), taskFunc) + }), + Max: P.max, + } +} + +func (P *PDPIPNITask) schedule(ctx context.Context, taskFunc harmonytask.AddTaskFunc) error { + // schedule submits + var stop bool + for !stop { + taskFunc(func(id harmonytask.TaskID, tx *harmonydb.Tx) (shouldCommit bool, seriousError error) { + stop = true // assume we're done until we find a task to schedule + + var pendings []struct { + ID string `db:"id"` + } + + err := tx.Select(&pendings, `SELECT id FROM pdp_piecerefs + WHERE ipni_task_id IS NULL + AND needs_ipni = TRUE + ORDER BY created_at ASC LIMIT 1;`) + if err != nil { + return false, xerrors.Errorf("getting PDP pending indexing tasks: %w", err) + } + + if len(pendings) == 0 { + return false, nil + } + + // Setup PDP IPNI private key if this is our first IPNI task + if err := P.initProvider(tx); err != nil { + return false, xerrors.Errorf("initializing PDP IPNI provider: %w", err) + } + + pending := pendings[0] + _, err = tx.Exec(`UPDATE pdp_piecerefs SET ipni_task_id = $1 + WHERE ipni_task_id IS NULL AND id = $2`, id, pending.ID) + if err != nil { + return false, xerrors.Errorf("updating PDP ipni task id: %w", err) + } + + stop = false + return true, nil + }) + } + + return nil +} + +func (P *PDPIPNITask) Adder(taskFunc harmonytask.AddTaskFunc) {} + +// The ipni provider key for pdp is at PDP_SP_ID +func (P *PDPIPNITask) initProvider(tx *harmonydb.Tx) error { + var privKey []byte + err := tx.QueryRow(`SELECT priv_key FROM ipni_peerid WHERE sp_id = $1`, PDP_SP_ID).Scan(&privKey) + if err != nil { + if err != pgx.ErrNoRows { + return xerrors.Errorf("failed to get private libp2p key: %w", err) + } + + // generate the ipni provider key + pk, _, err := crypto.GenerateEd25519Key(rand.Reader) + if err != nil { + return xerrors.Errorf("failed to generate a new key: %w", err) + } + + privKey, err = crypto.MarshalPrivateKey(pk) + if err != nil { + return xerrors.Errorf("failed to marshal the private key: %w", err) + } + + pid, err := peer.IDFromPublicKey(pk.GetPublic()) + if err != nil { + return xerrors.Errorf("getting peer ID: %w", err) + } + + n, err := tx.Exec(`INSERT INTO ipni_peerid (priv_key, peer_id, sp_id) VALUES ($1, $2, 0)`, privKey, pid.String()) + if err != nil { + return xerrors.Errorf("failed to to insert the key into DB: %w", err) + } + + if n == 0 { + return xerrors.Errorf("failed to insert the key into db") + } + } + return nil +} + +var _ harmonytask.TaskInterface = &PDPIPNITask{} +var _ = harmonytask.Reg(&PDPIPNITask{}) + +// PdpIpniContext is used to generate the context bytes for PDP IPNI ads +type PdpIpniContext struct { + // PieceCID is piece CID V2 + PieceCID cid.Cid + + // Payload determines if the IPNI ad is TransportFilecoinPieceHttp or TransportIpfsGatewayHttp + Payload bool +} + +// Marshal encodes the PdpIpniContext into a byte slice containing a single byte for Payload and the byte representation of PieceCID. +func (p *PdpIpniContext) Marshal() ([]byte, error) { + pBytes := p.PieceCID.Bytes() + if len(pBytes) > 63 { + return nil, xerrors.Errorf("piece CID byte length exceeds 63") + } + payloadByte := make([]byte, 1) + if p.Payload { + payloadByte[0] = 1 + } else { + payloadByte[0] = 0 + } + return append(payloadByte, pBytes...), nil +} + +// Unmarshal decodes the provided byte slice into the PdpIpniContext struct, validating its length and extracting the PieceCID and Payload values. +func (p *PdpIpniContext) Unmarshal(b []byte) error { + if len(b) > 64 { + return xerrors.Errorf("byte length exceeds 64") + } + if len(b) < 2 { + return xerrors.Errorf("byte length is less than 2") + } + payload := b[0] == 1 + pcid, err := cid.Cast(b[1:]) + if err != nil { + return err + } + + p.PieceCID = pcid + p.Payload = payload + + return nil +}