Skip to content

Commit 905966a

Browse files
rvaggmasih
authored andcommitted
Implement ChainGetTipSet in Lotus v2 APIs
Introduce the first API for Lotus v2, focusing on `ChainGetTipSet` within the `Chain` group. Define `TipSetSelector` for advanced tipset retrieval options, and create a compact JSON-RPC call format. Gracefully accommodate both EC and F3 finalized tipsets based on node configuration, where: * EC finalized tipset is returned when F3 is turned off, has no finalized tipset or F3 isn't ready. * F3 finalized is returned otherwise. Support three categories of selectors under `TipSetSelector`: * By tag: either "latest" or "finalized." * By height: epoch, plus optional fallback to previous non-null tipset. * By tipset key. The selection falls back to tag "latest" if the user specifies no selection criterion. The JSON-RPC format is designed to use JSON Object as the parameters passed to the RPC call to remain compact, and extensible. Examples include: * Latest Tipset: ```json {"jsonrpc":"2.0","method":"Filecoin.ChainGetTipSet","id":1} ``` * Finalized Tipset: ```json {"jsonrpc":"2.0","method":"Filecoin.ChainGetTipSet","params":{"tag":"finalized"},"id":1} ``` * Tipset at specific height: ```json {"jsonrpc":"2.0","method":"Filecoin.ChainGetTipSet","params":{"height":{"at":1413,"previous":true}},"id":1} ``` The open API spec and Markdown generation is excluded from this work to reduce the PR verbosity and will be included in a follow-up PR once the basic API primitives are reviewed. Note that all v2 APIs are experimental and may change with no notice. Relates to: #12719 Part of: #12990
1 parent 062ce4d commit 905966a

25 files changed

+974
-34
lines changed

Diff for: CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
1010
# UNRELEASED
1111

12+
- feat: implement ChainGetTipSet in Lotus v2 APIs
13+
1214
# Node and Miner v1.32.1 / 2025-03-28
1315

1416
The Lotus v1.32.1 release is a **MANDATORY patch release**, which will deliver the Filecoin network version 25, codenamed “Teep” 🦵. This release sets the upgrade epoch for the Mainnet to **Epoch 4867320 - 2025-04-10T23:00:00Z**, and correctly sets the F3 activationcontract address to `0xA19080A1Bcb82Bb61bcb9691EC94653Eb5315716`. You can find more details about how the F3 activation on Mainnet will be executed in the [F3 Activation Procedure](https://github.com/filecoin-project/go-f3/issues/920#issuecomment-2761448485).

Diff for: api/v2api/doc.go

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// Package v2api provides an interface for interacting with the v2 full node APIs
2+
// within the Filecoin network.
3+
//
4+
// This package is experimental and the API may change without notice.
5+
package v2api

Diff for: api/v2api/full.go

+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
package v2api
2+
3+
import (
4+
"context"
5+
6+
"github.com/filecoin-project/lotus/chain/types"
7+
)
8+
9+
//go:generate go run github.com/golang/mock/mockgen -destination=v2mocks/mock_full.go -package=v2mocks . FullNode
10+
11+
// FullNode represents an interface for the v2 full node APIs. This interface
12+
// currently consists of chain-related functionalities and the API is
13+
// experimental and subject to change.
14+
type FullNode interface {
15+
// MethodGroup: Chain
16+
// The Chain method group contains methods for interacting with
17+
// the blockchain.
18+
Chain
19+
}
20+
21+
// Chain defines a component of the FullNode interface that focuses on
22+
// functionalities related to blockchain tipsets.
23+
type Chain interface {
24+
// ChainGetTipSet retrieves a tipset that corresponds to the specified selector
25+
// criteria. The criteria can be provided in the form of a tipset key, a
26+
// blockchain height including an optional fallback to previous non-null tipset,
27+
// or a designated tag such as "latest" or "finalized".
28+
//
29+
// The "Finalized" tag returns the tipset that is considered finalized based on
30+
// the consensus protocol of the current node, either Filecoin EC Finality or
31+
// Filecoin Fast Finality (F3). The finalized tipset selection gracefully falls
32+
// back to EC finality in cases where F3 isn't ready or not running.
33+
//
34+
// In a case where no selector is provided, the method defaults to return the
35+
// tipset tagged with "latest".
36+
//
37+
// For more details, refer to the types.TipSetSelector and
38+
// types.NewTipSetSelector.
39+
//
40+
// Example usage:
41+
//
42+
// selector, err := types.NewTipSetSelector(types.TipsetTags.Latest)
43+
// if err != nil {
44+
// fmt.Println("Error creating tipset selector:", err)
45+
// return
46+
// }
47+
// tipSet, err := node.ChainGetTipSet(context.Background(), selector)
48+
// if err != nil {
49+
// fmt.Println("Error retrieving tipset:", err)
50+
// return
51+
// }
52+
// fmt.Printf("Latest TipSet: %v\n", tipSet)
53+
//
54+
ChainGetTipSet(context.Context, types.TipSetSelector) (*types.TipSet, error) //perm:read
55+
}

Diff for: api/v2api/permissioned.go

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package v2api
2+
3+
import (
4+
"github.com/filecoin-project/go-jsonrpc/auth"
5+
6+
"github.com/filecoin-project/lotus/api"
7+
)
8+
9+
func PermissionedFullAPI(a FullNode) FullNode {
10+
var out FullNodeStruct
11+
auth.PermissionedProxy(api.AllPermissions, api.DefaultPerms, a, &out.Internal)
12+
return &out
13+
}

Diff for: api/v2api/proxy_gen.go

+51
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Diff for: api/v2api/v2mocks/mock_full.go

+54
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Diff for: chain/lf3/f3.go

+15
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,21 @@ import (
2929
"github.com/filecoin-project/lotus/node/repo"
3030
)
3131

32+
var _ F3Backend = (*F3)(nil)
33+
34+
type F3Backend interface {
35+
GetOrRenewParticipationTicket(_ context.Context, minerID uint64, previous api.F3ParticipationTicket, instances uint64) (api.F3ParticipationTicket, error)
36+
Participate(_ context.Context, ticket api.F3ParticipationTicket) (api.F3ParticipationLease, error)
37+
ListParticipants() []api.F3Participant
38+
GetManifest(ctx context.Context) (*manifest.Manifest, error)
39+
GetCert(ctx context.Context, instance uint64) (*certs.FinalityCertificate, error)
40+
GetLatestCert(ctx context.Context) (*certs.FinalityCertificate, error)
41+
GetPowerTable(ctx context.Context, tsk types.TipSetKey) (gpbft.PowerEntries, error)
42+
GetF3PowerTable(ctx context.Context, tsk types.TipSetKey) (gpbft.PowerEntries, error)
43+
IsRunning() bool
44+
Progress() gpbft.InstanceProgress
45+
}
46+
3247
type F3 struct {
3348
inner *f3.F3
3449
ec *ecWrapper

Diff for: chain/types/tipset_selector.go

+128
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
package types
2+
3+
import (
4+
"encoding/json"
5+
"fmt"
6+
7+
"golang.org/x/xerrors"
8+
9+
"github.com/filecoin-project/go-jsonrpc"
10+
"github.com/filecoin-project/go-state-types/abi"
11+
)
12+
13+
// TipSetTag is a string that represents a pointer to a tipset.
14+
// See TipSetCriterion.
15+
type TipSetTag string
16+
17+
// TipSetTags represents the predefined set of tags for tipsets. The supported
18+
// tags are:
19+
// - Latest: the most recent tipset in the chain with the heaviest weight.
20+
// - Finalized: the most recent tipset considered final by the node.
21+
//
22+
// See TipSetTag.
23+
var TipSetTags = struct {
24+
Latest TipSetTag
25+
Finalized TipSetTag
26+
}{
27+
Latest: TipSetTag("latest"),
28+
Finalized: TipSetTag("finalized"),
29+
}
30+
31+
// TipSetSelector is a JSON-RPC parameter type that can be used to select a tipset.
32+
// See NewTipSetSelector, TipSetCriterion.
33+
type TipSetSelector = jsonrpc.RawParams
34+
35+
// TipSetCriterion captures the selection criteria for a tipset.
36+
//
37+
// The supported criterion for selection is one of the following:
38+
// - Key: the tipset key, see TipSetKey.
39+
// - Height: the tipset height with an optional fallback to non-null parent, see TipSetHeight.
40+
// - Tag: the tipset tag, either "latest" or "finalized", see TipSetTags.
41+
//
42+
// At most, only one such criterion can be specified at a time. Otherwise, the
43+
// criterion is considered. See Validate.
44+
type TipSetCriterion struct {
45+
Key *TipSetKey `json:"key,omitempty"`
46+
Height *TipSetHeight `json:"height,omitempty"`
47+
Tag *TipSetTag `json:"tag,omitempty"`
48+
}
49+
50+
// TipSetCriteria is a union of all possible criteria for selecting a tipset.
51+
type TipSetCriteria interface {
52+
TipSetTag | TipSetHeight | TipSetKey
53+
}
54+
55+
// NewTipSetSelector creates a new TipSetSelector from the given criterion. The
56+
// criterion must conform to one of the supported types: TipSetTag, TipSetHeight,
57+
// or TipSetKey.
58+
//
59+
// See TipSetCriteria type constraint.
60+
func NewTipSetSelector[T TipSetCriteria](t T) (TipSetSelector, error) {
61+
switch criterion := any(t).(type) {
62+
case TipSetTag:
63+
return json.Marshal(TipSetCriterion{Tag: &criterion})
64+
case TipSetHeight:
65+
return json.Marshal(TipSetCriterion{Height: &criterion})
66+
case TipSetKey:
67+
return json.Marshal(TipSetCriterion{Key: &criterion})
68+
default:
69+
// Dear Golang, this should be impossible because of the type constraint being
70+
// evaluated at compile time; yet, here we are. I would panic, but then we are
71+
// friends and this function returns errors anyhow.
72+
return nil, fmt.Errorf("unknown tipset slection criterion: %T", criterion)
73+
}
74+
}
75+
76+
// DecodeTipSetCriterion extracts a TipSetCriterion from the given
77+
// TipSetSelector. The returned criterion is validated before returning. If the
78+
// selector is empty, a nil criterion is returned.
79+
func DecodeTipSetCriterion(tss TipSetSelector) (*TipSetCriterion, error) {
80+
if len(tss) == 0 || string(tss) == "null" {
81+
return nil, nil
82+
}
83+
84+
var criterion TipSetCriterion
85+
if err := json.Unmarshal(tss, &criterion); err != nil {
86+
return nil, xerrors.Errorf("decoding tipset selector: %w", err)
87+
}
88+
if err := criterion.Validate(); err != nil {
89+
return nil, xerrors.Errorf("validating tipset criterion: %w", err)
90+
}
91+
return &criterion, nil
92+
}
93+
94+
// Validate ensures that the TipSetCriterion is valid. It checks that only one of
95+
// the selection criteria is specified. If no criteria are specified, it returns
96+
// nil, indicating that the default selection criteria should be used as defined
97+
// by the Lotus API Specification.
98+
func (tss *TipSetCriterion) Validate() error {
99+
if tss == nil {
100+
// Empty TipSetSelector is valid and implies whatever the default is dictated to
101+
// be by the API, which happens to be the tipset tagged as "latest".
102+
return nil
103+
}
104+
var criteria int
105+
if tss.Key != nil {
106+
criteria++
107+
}
108+
if tss.Tag != nil {
109+
criteria++
110+
}
111+
if tss.Height != nil {
112+
criteria++
113+
}
114+
if criteria > 1 {
115+
return xerrors.Errorf("only one tipset selection criteria must be specified, found: %v", criteria)
116+
}
117+
return nil
118+
}
119+
120+
// TipSetHeight is a criterion that selects a tipset At given height.
121+
//
122+
// In a case where the tipset at given height is null, and Previous is true,
123+
// it'll select the previous non-null tipset instead. Otherwise, it returns the
124+
// null tipset at the given height.
125+
type TipSetHeight struct {
126+
At abi.ChainEpoch `json:"at,omitempty"`
127+
Previous bool `json:"previous,omitempty"`
128+
}

0 commit comments

Comments
 (0)