Skip to content

Commit 57c3fbe

Browse files
committed
feat: booster-http
1 parent 2f8d246 commit 57c3fbe

File tree

9 files changed

+652
-0
lines changed

9 files changed

+652
-0
lines changed

Makefile

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,12 @@ boost: $(BUILD_DEPS)
8989
.PHONY: boost
9090
BINS+=boost boostx boostd
9191

92+
booster-http: $(BUILD_DEPS)
93+
rm -f booster-http
94+
$(GOCC) build $(GOFLAGS) -o booster-http ./cmd/booster-http
95+
.PHONY: booster-http
96+
BINS+=booster-http
97+
9298
devnet: $(BUILD_DEPS)
9399
rm -f devnet
94100
$(GOCC) build $(GOFLAGS) -o devnet ./cmd/devnet

api/api.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ type Boost interface {
6666
PiecesListCidInfos(ctx context.Context) ([]cid.Cid, error) //perm:read
6767
PiecesGetPieceInfo(ctx context.Context, pieceCid cid.Cid) (*piecestore.PieceInfo, error) //perm:read
6868
PiecesGetCIDInfo(ctx context.Context, payloadCid cid.Cid) (*piecestore.CIDInfo, error) //perm:read
69+
PiecesGetMaxOffset(ctx context.Context, pieceCid cid.Cid) (uint64, error) //perm:read
6970

7071
// MethodGroup: Actor
7172
ActorSectorSize(context.Context, address.Address) (abi.SectorSize, error) //perm:read

api/proxy_gen.go

Lines changed: 13 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

cmd/boostd/run.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ var runCmd = &cli.Command{
2828
Name: "pprof",
2929
Usage: "run pprof web server on localhost:6060",
3030
},
31+
&cli.BoolFlag{
32+
Name: "nosync",
33+
Usage: "dont wait for the full node to sync with the chain",
34+
},
3135
},
3236
Action: func(cctx *cli.Context) error {
3337
if cctx.Bool("pprof") {

cmd/booster-http/main.go

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
package main
2+
3+
import (
4+
"os"
5+
6+
logging "github.com/ipfs/go-log/v2"
7+
"github.com/urfave/cli/v2"
8+
9+
"github.com/filecoin-project/boost/build"
10+
cliutil "github.com/filecoin-project/boost/cli/util"
11+
)
12+
13+
var log = logging.Logger("booster")
14+
15+
const (
16+
FlagBoostRepo = "boost-repo"
17+
)
18+
19+
func main() {
20+
app := &cli.App{
21+
Name: "booster-http",
22+
Usage: "HTTP endpoint for retrieval from Filecoin",
23+
EnableBashCompletion: true,
24+
Version: build.UserVersion(),
25+
Flags: []cli.Flag{
26+
&cli.StringFlag{
27+
Name: FlagBoostRepo,
28+
EnvVars: []string{"BOOST_PATH"},
29+
Usage: "boost repo path",
30+
Value: "~/.boost",
31+
},
32+
cliutil.FlagVeryVerbose,
33+
},
34+
Commands: []*cli.Command{
35+
runCmd,
36+
},
37+
}
38+
app.Setup()
39+
40+
if err := app.Run(os.Args); err != nil {
41+
os.Stderr.WriteString("Error: " + err.Error() + "\n")
42+
}
43+
}
44+
45+
func before(cctx *cli.Context) error {
46+
_ = logging.SetLogLevel("booster", "INFO")
47+
48+
if cliutil.IsVeryVerbose {
49+
_ = logging.SetLogLevel("booster", "DEBUG")
50+
}
51+
52+
return nil
53+
}

cmd/booster-http/run.go

Lines changed: 263 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,263 @@
1+
package main
2+
3+
import (
4+
"context"
5+
"errors"
6+
"fmt"
7+
"github.com/filecoin-project/boost/api"
8+
bclient "github.com/filecoin-project/boost/api/client"
9+
cliutil "github.com/filecoin-project/boost/cli/util"
10+
"github.com/filecoin-project/dagstore/mount"
11+
"github.com/filecoin-project/go-address"
12+
"github.com/filecoin-project/go-fil-markets/piecestore"
13+
"github.com/filecoin-project/go-jsonrpc"
14+
"github.com/filecoin-project/go-state-types/abi"
15+
lapi "github.com/filecoin-project/lotus/api"
16+
"github.com/filecoin-project/lotus/api/client"
17+
"github.com/filecoin-project/lotus/api/v0api"
18+
"github.com/filecoin-project/lotus/api/v1api"
19+
lcli "github.com/filecoin-project/lotus/cli"
20+
sectorstorage "github.com/filecoin-project/lotus/extern/sector-storage"
21+
"github.com/filecoin-project/lotus/extern/sector-storage/stores"
22+
"github.com/filecoin-project/lotus/markets/dagstore"
23+
"github.com/filecoin-project/lotus/markets/sectoraccessor"
24+
lotus_modules "github.com/filecoin-project/lotus/node/modules"
25+
"github.com/filecoin-project/lotus/node/modules/dtypes"
26+
"github.com/filecoin-project/lotus/node/repo"
27+
"github.com/ipfs/go-cid"
28+
"github.com/urfave/cli/v2"
29+
"net/http"
30+
_ "net/http/pprof"
31+
"strings"
32+
)
33+
34+
var runCmd = &cli.Command{
35+
Name: "run",
36+
Usage: "Start a booster-http process",
37+
Before: before,
38+
Flags: []cli.Flag{
39+
&cli.BoolFlag{
40+
Name: "pprof",
41+
Usage: "run pprof web server on localhost:6070",
42+
},
43+
&cli.StringFlag{
44+
Name: "base-path",
45+
Usage: "the base path at which to run the web server",
46+
Value: "",
47+
},
48+
&cli.UintFlag{
49+
Name: "port",
50+
Usage: "the port the web server listens on",
51+
Value: 7777,
52+
},
53+
&cli.StringFlag{
54+
Name: "api-boost",
55+
Usage: "the endpoint for the boost API",
56+
Required: true,
57+
},
58+
&cli.StringFlag{
59+
Name: "api-fullnode",
60+
Usage: "the endpoint for the full node API",
61+
Required: true,
62+
},
63+
&cli.StringFlag{
64+
Name: "api-sealer",
65+
Usage: "the endpoint for the sealer API",
66+
Required: true,
67+
},
68+
&cli.StringFlag{
69+
Name: "miner",
70+
Usage: "the miner's address",
71+
Required: true,
72+
},
73+
},
74+
Action: func(cctx *cli.Context) error {
75+
if cctx.Bool("pprof") {
76+
go func() {
77+
err := http.ListenAndServe("localhost:6070", nil)
78+
if err != nil {
79+
log.Error(err)
80+
}
81+
}()
82+
}
83+
84+
maddr, err := address.NewFromString(cctx.String("miner"))
85+
if err != nil {
86+
return fmt.Errorf("parsing miner address %s: %w", cctx.String("miner"), err)
87+
}
88+
89+
// Connect to the Boost API
90+
ctx := lcli.ReqContext(cctx)
91+
boostApiInfo := cctx.String("api-boost")
92+
bapi, bcloser, err := getBoostApi(ctx, boostApiInfo)
93+
if err != nil {
94+
return fmt.Errorf("getting boost API: %w", err)
95+
}
96+
defer bcloser()
97+
98+
// Connect to the full node API
99+
fnApiInfo := cctx.String("api-fullnode")
100+
fullnodeApi, ncloser, err := getFullNodeApi(ctx, fnApiInfo)
101+
defer ncloser()
102+
103+
// Connect to the sealing API
104+
sealingApiInfo := cctx.String("api-sealer")
105+
sauth, err := storageAuthWithURL(sealingApiInfo)
106+
if err != nil {
107+
return fmt.Errorf("parsing sealing API endpoint: %w", err)
108+
}
109+
sealingService, sealerCloser, err := getMinerApi(ctx, sealingApiInfo)
110+
defer sealerCloser()
111+
112+
// Use an in-memory repo because we don't need any functions
113+
// of a real repo, we just need to supply something that satisfies
114+
// the LocalStorage interface to the store
115+
memRepo := repo.NewMemory(nil)
116+
lr, err := memRepo.Lock(repo.StorageMiner)
117+
if err != nil {
118+
return fmt.Errorf("locking mem repo: %w", err)
119+
}
120+
defer lr.Close()
121+
122+
// Create the store interface
123+
var urls []string
124+
lstor, err := stores.NewLocal(ctx, lr, sealingService, urls)
125+
if err != nil {
126+
return fmt.Errorf("creating new local store: %w", err)
127+
}
128+
storage := lotus_modules.RemoteStorage(lstor, sealingService, sauth, sectorstorage.Config{
129+
// TODO: Not sure if I need this, or any of the other fields in this struct
130+
ParallelFetchLimit: 1,
131+
})
132+
// Create the piece provider and sector accessors
133+
pp := sectorstorage.NewPieceProvider(storage, sealingService, sealingService)
134+
sa := sectoraccessor.NewSectorAccessor(dtypes.MinerAddress(maddr), sealingService, pp, fullnodeApi)
135+
// Create the server API
136+
sapi := serverApi{ctx: ctx, bapi: bapi, sa: sa}
137+
server := NewHttpServer(cctx.String("base-path"), cctx.Int("port"), sapi)
138+
139+
// Start the server
140+
log.Infof("Starting booster-http node on port %d with base path '%s'",
141+
cctx.Int("port"), cctx.String("base-path"))
142+
server.Start(ctx)
143+
144+
// Monitor for shutdown.
145+
<-ctx.Done()
146+
147+
log.Info("Shutting down...")
148+
149+
err = server.Stop()
150+
if err != nil {
151+
return err
152+
}
153+
log.Info("Graceful shutdown successful")
154+
155+
// Sync all loggers.
156+
_ = log.Sync() //nolint:errcheck
157+
158+
return nil
159+
},
160+
}
161+
162+
func storageAuthWithURL(apiInfo string) (sectorstorage.StorageAuth, error) {
163+
s := strings.Split(apiInfo, ":")
164+
if len(s) != 2 {
165+
return nil, errors.New("unexpected format of `apiInfo`")
166+
}
167+
headers := http.Header{}
168+
headers.Add("Authorization", "Bearer "+s[0])
169+
return sectorstorage.StorageAuth(headers), nil
170+
}
171+
172+
type serverApi struct {
173+
ctx context.Context
174+
bapi api.Boost
175+
sa dagstore.SectorAccessor
176+
}
177+
178+
var _ HttpServerApi = (*serverApi)(nil)
179+
180+
func (s serverApi) GetMaxPieceOffset(pieceCid cid.Cid) (uint64, error) {
181+
return s.bapi.PiecesGetMaxOffset(s.ctx, pieceCid)
182+
}
183+
184+
func (s serverApi) GetPieceInfo(pieceCID cid.Cid) (*piecestore.PieceInfo, error) {
185+
return s.bapi.PiecesGetPieceInfo(s.ctx, pieceCID)
186+
}
187+
188+
func (s serverApi) IsUnsealed(ctx context.Context, sectorID abi.SectorNumber, offset abi.UnpaddedPieceSize, length abi.UnpaddedPieceSize) (bool, error) {
189+
return s.sa.IsUnsealed(ctx, sectorID, offset, length)
190+
}
191+
192+
func (s serverApi) UnsealSectorAt(ctx context.Context, sectorID abi.SectorNumber, offset abi.UnpaddedPieceSize, length abi.UnpaddedPieceSize) (mount.Reader, error) {
193+
return s.sa.UnsealSectorAt(ctx, sectorID, offset, length)
194+
}
195+
196+
func getBoostApi(ctx context.Context, ai string) (api.Boost, jsonrpc.ClientCloser, error) {
197+
ai = strings.TrimPrefix(strings.TrimSpace(ai), "BOOST_API_INFO=")
198+
info := cliutil.ParseApiInfo(ai)
199+
addr, err := info.DialArgs("v0")
200+
if err != nil {
201+
return nil, nil, fmt.Errorf("could not get DialArgs: %w", err)
202+
}
203+
204+
log.Infof("Using boost API at %s", addr)
205+
api, closer, err := bclient.NewBoostRPCV0(ctx, addr, info.AuthHeader())
206+
if err != nil {
207+
return nil, nil, fmt.Errorf("creating full node service API: %w", err)
208+
}
209+
210+
return api, closer, nil
211+
}
212+
213+
func getFullNodeApi(ctx context.Context, ai string) (v1api.FullNode, jsonrpc.ClientCloser, error) {
214+
ai = strings.TrimPrefix(strings.TrimSpace(ai), "FULLNODE_API_INFO=")
215+
info := cliutil.ParseApiInfo(ai)
216+
addr, err := info.DialArgs("v1")
217+
if err != nil {
218+
return nil, nil, fmt.Errorf("could not get DialArgs: %w", err)
219+
}
220+
221+
log.Infof("Using full node API at %s", addr)
222+
api, closer, err := client.NewFullNodeRPCV1(ctx, addr, info.AuthHeader())
223+
if err != nil {
224+
return nil, nil, fmt.Errorf("creating full node service API: %w", err)
225+
}
226+
227+
v, err := api.Version(ctx)
228+
if err != nil {
229+
return nil, nil, fmt.Errorf("checking full node service API version: %w", err)
230+
}
231+
232+
if !v.APIVersion.EqMajorMinor(lapi.FullAPIVersion1) {
233+
return nil, nil, fmt.Errorf("full node service API version didn't match (expected %s, remote %s)", lapi.FullAPIVersion1, v.APIVersion)
234+
}
235+
236+
return api, closer, nil
237+
}
238+
239+
func getMinerApi(ctx context.Context, ai string) (v0api.StorageMiner, jsonrpc.ClientCloser, error) {
240+
ai = strings.TrimPrefix(strings.TrimSpace(ai), "MINER_API_INFO=")
241+
info := cliutil.ParseApiInfo(ai)
242+
addr, err := info.DialArgs("v0")
243+
if err != nil {
244+
return nil, nil, fmt.Errorf("could not get DialArgs: %w", err)
245+
}
246+
247+
log.Infof("Using sealing API at %s", addr)
248+
api, closer, err := client.NewStorageMinerRPCV0(ctx, addr, info.AuthHeader())
249+
if err != nil {
250+
return nil, nil, fmt.Errorf("creating miner service API: %w", err)
251+
}
252+
253+
v, err := api.Version(ctx)
254+
if err != nil {
255+
return nil, nil, fmt.Errorf("checking miner service API version: %w", err)
256+
}
257+
258+
if !v.APIVersion.EqMajorMinor(lapi.MinerAPIVersion0) {
259+
return nil, nil, fmt.Errorf("miner service API version didn't match (expected %s, remote %s)", lapi.MinerAPIVersion0, v.APIVersion)
260+
}
261+
262+
return api, closer, nil
263+
}

0 commit comments

Comments
 (0)