Skip to content

Commit

Permalink
feat(f3): resolve finality for eth APIs according to F3
Browse files Browse the repository at this point in the history
  • Loading branch information
rvagg committed Dec 10, 2024
1 parent 8b3de48 commit 4a7a492
Show file tree
Hide file tree
Showing 13 changed files with 855 additions and 148 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@
# UNRELEASED

- Add json output of tipsets to `louts chain list`. ([filecoin-project/lotus#12691](https://github.com/filecoin-project/lotus/pull/12691))
- **Ethereum APIs meet F3!** When F3 is enabled and running, Ethereum APIs that accept block descriptors `"finalized"` and `"safe"` will use F3 to determine the block to select instead of the default 30 block delay for `"safe"` and 900 block delay for `"finalized"`. ([filecoin-project/lotus#12762](https://github.com/filecoin-project/lotus/pull/12762))

# UNRELEASED v.1.32.0


See https://github.com/filecoin-project/lotus/blob/release/v1.32.0/CHANGELOG.md

# Node and Miner v1.31.0 / 2024-12-02
Expand Down
42 changes: 42 additions & 0 deletions chain/lf3/disabled.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package lf3

import (
"context"

"github.com/filecoin-project/go-f3/certs"
"github.com/filecoin-project/go-f3/gpbft"
"github.com/filecoin-project/go-f3/manifest"

"github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/chain/types"
)

type DisabledF3 struct{}

var _ F3API = DisabledF3{}

func (DisabledF3) GetOrRenewParticipationTicket(_ context.Context, _ uint64, _ api.F3ParticipationTicket, _ uint64) (api.F3ParticipationTicket, error) {
return api.F3ParticipationTicket{}, api.ErrF3Disabled
}
func (DisabledF3) Participate(_ context.Context, _ api.F3ParticipationTicket) (api.F3ParticipationLease, error) {
return api.F3ParticipationLease{}, api.ErrF3Disabled
}
func (DisabledF3) GetCert(_ context.Context, _ uint64) (*certs.FinalityCertificate, error) {
return nil, api.ErrF3Disabled
}
func (DisabledF3) GetLatestCert(_ context.Context) (*certs.FinalityCertificate, error) {
return nil, api.ErrF3Disabled
}
func (DisabledF3) GetManifest(_ context.Context) (*manifest.Manifest, error) {
return nil, api.ErrF3Disabled
}
func (DisabledF3) GetPowerTable(_ context.Context, _ types.TipSetKey) (gpbft.PowerEntries, error) {
return nil, api.ErrF3Disabled
}
func (DisabledF3) GetF3PowerTable(_ context.Context, _ types.TipSetKey) (gpbft.PowerEntries, error) {
return nil, api.ErrF3Disabled
}
func (DisabledF3) IsEnabled() bool { return false }
func (DisabledF3) IsRunning() (bool, error) { return false, api.ErrF3Disabled }
func (DisabledF3) Progress() (gpbft.Instant, error) { return gpbft.Instant{}, api.ErrF3Disabled }
func (DisabledF3) ListParticipants() ([]api.F3Participant, error) { return nil, api.ErrF3Disabled }
40 changes: 30 additions & 10 deletions chain/lf3/f3.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,20 @@ import (
"github.com/filecoin-project/lotus/node/repo"
)

type F3API interface {
GetOrRenewParticipationTicket(ctx context.Context, minerID uint64, previous api.F3ParticipationTicket, instances uint64) (api.F3ParticipationTicket, error)
Participate(ctx context.Context, ticket api.F3ParticipationTicket) (api.F3ParticipationLease, error)
GetCert(ctx context.Context, instance uint64) (*certs.FinalityCertificate, error)
GetLatestCert(ctx context.Context) (*certs.FinalityCertificate, error)
GetManifest(ctx context.Context) (*manifest.Manifest, error)
GetPowerTable(ctx context.Context, tsk types.TipSetKey) (gpbft.PowerEntries, error)
GetF3PowerTable(ctx context.Context, tsk types.TipSetKey) (gpbft.PowerEntries, error)
IsEnabled() bool
IsRunning() (bool, error)
Progress() (gpbft.Instant, error)
ListParticipants() ([]api.F3Participant, error)
}

type F3 struct {
inner *f3.F3
ec *ecWrapper
Expand All @@ -37,6 +51,8 @@ type F3 struct {
leaser *leaser
}

var _ F3API = (*F3)(nil)

type F3Params struct {
fx.In

Expand Down Expand Up @@ -184,20 +200,20 @@ func (fff *F3) GetLatestCert(ctx context.Context) (*certs.FinalityCertificate, e
return fff.inner.GetLatestCert(ctx)
}

func (fff *F3) GetManifest(ctx context.Context) *manifest.Manifest {
func (fff *F3) GetManifest(ctx context.Context) (*manifest.Manifest, error) {
m := fff.inner.Manifest()
if m.InitialPowerTable.Defined() {
return m
return m, nil
}
cert0, err := fff.inner.GetCert(ctx, 0)
if err != nil {
return m
return m, nil
}

var mCopy = *m
m = &mCopy
m.InitialPowerTable = cert0.ECChain.Base().PowerTable
return m
return m, nil
}

func (fff *F3) GetPowerTable(ctx context.Context, tsk types.TipSetKey) (gpbft.PowerEntries, error) {
Expand All @@ -208,15 +224,19 @@ func (fff *F3) GetF3PowerTable(ctx context.Context, tsk types.TipSetKey) (gpbft.
return fff.inner.GetPowerTable(ctx, tsk.Bytes())
}

func (fff *F3) IsRunning() bool {
return fff.inner.IsRunning()
func (fff *F3) IsEnabled() bool {
return true
}

func (fff *F3) IsRunning() (bool, error) {
return fff.inner.IsRunning(), nil
}

func (fff *F3) Progress() gpbft.Instant {
return fff.inner.Progress()
func (fff *F3) Progress() (gpbft.Instant, error) {
return fff.inner.Progress(), nil
}

func (fff *F3) ListParticipants() []api.F3Participant {
func (fff *F3) ListParticipants() ([]api.F3Participant, error) {
leases := fff.leaser.getValidLeases()
participants := make([]api.F3Participant, len(leases))
for i, lease := range leases {
Expand All @@ -226,5 +246,5 @@ func (fff *F3) ListParticipants() []api.F3Participant {
ValidityTerm: lease.ValidityTerm,
}
}
return participants
return participants, nil
}
162 changes: 162 additions & 0 deletions chain/lf3/mock/mock_f3.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
package mock

import (
"context"
"sync"

"golang.org/x/xerrors"

"github.com/filecoin-project/go-f3/certs"
"github.com/filecoin-project/go-f3/gpbft"
"github.com/filecoin-project/go-f3/manifest"

"github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/chain/lf3"
"github.com/filecoin-project/lotus/chain/types"
)

type MockF3API struct {
lk sync.Mutex

latestCert *certs.FinalityCertificate
manifest *manifest.Manifest
enabled bool
running bool
}

func (m *MockF3API) GetOrRenewParticipationTicket(ctx context.Context, minerID uint64, previous api.F3ParticipationTicket, instances uint64) (api.F3ParticipationTicket, error) {
if !m.IsEnabled() {
return api.F3ParticipationTicket{}, api.ErrF3Disabled
}
return api.F3ParticipationTicket{}, nil
}

func (m *MockF3API) Participate(ctx context.Context, ticket api.F3ParticipationTicket) (api.F3ParticipationLease, error) {
if !m.IsEnabled() {
return api.F3ParticipationLease{}, api.ErrF3Disabled
}
return api.F3ParticipationLease{}, nil
}

func (m *MockF3API) GetCert(ctx context.Context, instance uint64) (*certs.FinalityCertificate, error) {
if !m.IsEnabled() {
return nil, api.ErrF3Disabled
}
return nil, nil
}

// SetLatestCert sets the latest certificate to be returned by GetLatestCert. If GetLatestCert is
// called before this method, it will return an error.
func (m *MockF3API) SetLatestCert(cert *certs.FinalityCertificate) {
m.lk.Lock()
defer m.lk.Unlock()

m.latestCert = cert
}

func (m *MockF3API) GetLatestCert(ctx context.Context) (*certs.FinalityCertificate, error) {
m.lk.Lock()
defer m.lk.Unlock()

if !m.enabled {
return nil, api.ErrF3Disabled
}

if m.latestCert == nil {
return nil, xerrors.Errorf("no latest cert set in test, did you mean to?")
}

return m.latestCert, nil
}

// SetManifest sets the manifest to be returned by GetManifest. If GetManifest is called before this
// method, it will return an error.
//
// Use manifest.LocalDevnetManifest() for a convenient manifest to use in tests.
func (m *MockF3API) SetManifest(manifest *manifest.Manifest) {
m.lk.Lock()
defer m.lk.Unlock()

m.manifest = manifest
}

func (m *MockF3API) GetManifest(ctx context.Context) (*manifest.Manifest, error) {
m.lk.Lock()
defer m.lk.Unlock()

if !m.enabled {
return nil, api.ErrF3Disabled
}

if m.manifest == nil {
return nil, xerrors.Errorf("no manifest set in test, did you mean to?")
}

return m.manifest, nil
}

func (m *MockF3API) GetPowerTable(ctx context.Context, tsk types.TipSetKey) (gpbft.PowerEntries, error) {
if !m.IsEnabled() {
return nil, api.ErrF3Disabled
}

return nil, nil
}

func (m *MockF3API) GetF3PowerTable(ctx context.Context, tsk types.TipSetKey) (gpbft.PowerEntries, error) {
if !m.IsEnabled() {
return nil, api.ErrF3Disabled
}

return nil, nil
}

func (m *MockF3API) SetEnabled(enabled bool) {
m.lk.Lock()
defer m.lk.Unlock()

m.enabled = enabled
}

func (m *MockF3API) IsEnabled() bool {
m.lk.Lock()
defer m.lk.Unlock()

return m.enabled
}

func (m *MockF3API) SetRunning(running bool) {
m.lk.Lock()
defer m.lk.Unlock()

m.running = running
}

func (m *MockF3API) IsRunning() (bool, error) {
m.lk.Lock()
defer m.lk.Unlock()

if !m.enabled {
return false, api.ErrF3Disabled
}

return m.running, nil
}

func (m *MockF3API) Progress() (gpbft.Instant, error) {
if !m.IsEnabled() {
return gpbft.Instant{}, api.ErrF3Disabled
}

return gpbft.Instant{}, nil
}

func (m *MockF3API) ListParticipants() ([]api.F3Participant, error) {
if !m.IsEnabled() {
return nil, api.ErrF3Disabled
}

return nil, nil
}

var _ lf3.F3API = (*MockF3API)(nil)
Loading

0 comments on commit 4a7a492

Please sign in to comment.