2020-09-12 03:01:37 +00:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"fmt"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/filecoin-project/go-address"
|
|
|
|
"github.com/filecoin-project/lotus/api"
|
|
|
|
"github.com/filecoin-project/lotus/chain/types"
|
2020-09-12 06:07:20 +00:00
|
|
|
"github.com/ipfs/go-cid"
|
2020-09-12 03:01:37 +00:00
|
|
|
|
|
|
|
"go.opencensus.io/trace"
|
|
|
|
)
|
|
|
|
|
|
|
|
const LookbackCap = time.Hour
|
|
|
|
|
|
|
|
var (
|
|
|
|
ErrLookbackTooLong = fmt.Errorf("lookbacks of more than %s are disallowed", LookbackCap)
|
|
|
|
)
|
|
|
|
|
|
|
|
type GatewayAPI struct {
|
|
|
|
api api.FullNode
|
|
|
|
}
|
|
|
|
|
|
|
|
func (a *GatewayAPI) getTipsetTimestamp(ctx context.Context, tsk types.TipSetKey) (time.Time, error) {
|
|
|
|
if tsk.IsEmpty() {
|
|
|
|
return time.Now(), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
ts, err := a.api.ChainGetTipSet(ctx, tsk)
|
|
|
|
if err != nil {
|
|
|
|
return time.Time{}, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return time.Unix(int64(ts.Blocks()[0].Timestamp), 0), nil
|
|
|
|
}
|
|
|
|
|
2020-09-12 06:07:20 +00:00
|
|
|
func (a *GatewayAPI) checkTipset(ctx context.Context, ts types.TipSetKey) error {
|
2020-09-12 03:01:37 +00:00
|
|
|
when, err := a.getTipsetTimestamp(ctx, ts)
|
|
|
|
if err != nil {
|
2020-09-12 06:07:20 +00:00
|
|
|
return err
|
2020-09-12 03:01:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if time.Since(when) > time.Hour {
|
2020-09-12 06:07:20 +00:00
|
|
|
return ErrLookbackTooLong
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (a *GatewayAPI) ChainHead(ctx context.Context) (*types.TipSet, error) {
|
|
|
|
ctx, span := trace.StartSpan(ctx, "ChainHead")
|
|
|
|
defer span.End()
|
|
|
|
// TODO: cache and invalidate cache when timestamp is up (or have internal ChainNotify)
|
|
|
|
|
|
|
|
return a.api.ChainHead(ctx)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (a *GatewayAPI) ChainGetTipSet(ctx context.Context, tsk types.TipSetKey) (*types.TipSet, error) {
|
|
|
|
ctx, span := trace.StartSpan(ctx, "ChainGetTipSet")
|
|
|
|
defer span.End()
|
|
|
|
|
|
|
|
if err := a.checkTipset(ctx, tsk); err != nil {
|
|
|
|
return nil, fmt.Errorf("bad tipset: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: since we're limiting lookbacks, should just cache this (could really even cache the json response bytes)
|
|
|
|
return a.api.ChainGetTipSet(ctx, tsk)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (a *GatewayAPI) MpoolPush(ctx context.Context, sm *types.SignedMessage) (cid.Cid, error) {
|
|
|
|
ctx, span := trace.StartSpan(ctx, "MpoolPush")
|
|
|
|
defer span.End()
|
|
|
|
|
|
|
|
// TODO: additional anti-spam checks
|
|
|
|
|
2020-09-18 06:40:43 +00:00
|
|
|
return a.api.MpoolPushUntrusted(ctx, sm)
|
2020-09-12 06:07:20 +00:00
|
|
|
}
|
2020-09-29 15:25:45 +00:00
|
|
|
|
|
|
|
func (a *GatewayAPI) StateGetActor(ctx context.Context, actor address.Address, ts types.TipSetKey) (*types.Actor, error) {
|
|
|
|
ctx, span := trace.StartSpan(ctx, "StateGetActor")
|
|
|
|
defer span.End()
|
|
|
|
|
|
|
|
if err := a.checkTipset(ctx, ts); err != nil {
|
|
|
|
return nil, fmt.Errorf("bad tipset: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return a.api.StateGetActor(ctx, actor, ts)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (a *GatewayAPI) StateAccountKey(ctx context.Context, addr address.Address, tsk types.TipSetKey) (address.Address, error) {
|
|
|
|
ctx, span := trace.StartSpan(ctx, "StateAccountKey")
|
|
|
|
defer span.End()
|
|
|
|
|
|
|
|
if err := a.checkTipset(ctx, tsk); err != nil {
|
|
|
|
return address.Undef, fmt.Errorf("bad tipset: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return a.api.StateAccountKey(ctx, addr, tsk)
|
|
|
|
}
|