Skip to content

Commit

Permalink
Merge branch 'master' into rpc-method
Browse files Browse the repository at this point in the history
  • Loading branch information
rvagg authored Oct 25, 2024
2 parents 35374f3 + 082b7ca commit 68428e3
Show file tree
Hide file tree
Showing 19 changed files with 963 additions and 170 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@
- `lotus chain head` now supports a `--height` flag to print just the epoch number of the current chain head ([filecoin-project/lotus#12609](https://github.com/filecoin-project/lotus/pull/12609))
- `lotus-shed indexes inspect-indexes` now performs a comprehensive comparison of the event index data for each message by comparing the AMT root CID from the message receipt with the root of a reconstructed AMT. Previously `inspect-indexes` simply compared event counts, comparing AMT roots confirms all the event data is byte-perfect. ([filecoin-project/lotus#12570](https://github.com/filecoin-project/lotus/pull/12570))
- Expose APIs to list the miner IDs that are currently participating in F3 via node. ([filecoin-project/lotus#12608](https://github.com/filecoin-project/lotus/pull/12608))
- Implement new `lotus f3` CLI commands to list F3 participants, dump manifest, get/list finality certificates and check the F3 status. ([filecoin-project/lotus#12617](https://github.com/filecoin-project/lotus/pull/12617), [filecoin-project/lotus#12627](https://github.com/filecoin-project/lotus/pull/12627))
- Return a `"data"` field on the `"error"` returned from RPC when `eth_call` and `eth_estimateGas` APIs encounter `execution reverted` errors. ([filecoin-project/lotus#12553](https://github.com/filecoin-project/lotus/pull/12553))
- Implement `EthGetTransactionByBlockNumberAndIndex` (`eth_getTransactionByBlockNumberAndIndex`) and `EthGetTransactionByBlockHashAndIndex` (`eth_getTransactionByBlockHashAndIndex`) methods. ([filecoin-project/lotus#12618](https://github.com/filecoin-project/lotus/pull/12618))
- Implement new `lotus f3` CLI commands to list F3 participants, dump manifest and check the F3 status. ([filecoin-project/lotus#12617](https://github.com/filecoin-project/lotus/pull/12617))

## Bug Fixes
- Fix a bug in the `lotus-shed indexes backfill-events` command that may result in either duplicate events being backfilled where there are existing events (such an operation *should* be idempotent) or events erroneously having duplicate `logIndex` values when queried via ETH APIs. ([filecoin-project/lotus#12567](https://github.com/filecoin-project/lotus/pull/12567))
Expand Down
80 changes: 65 additions & 15 deletions api/api_errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,13 @@ import (
"errors"
"reflect"

"golang.org/x/xerrors"

"github.com/filecoin-project/go-jsonrpc"
)

var invalidExecutionRevertedMsg = xerrors.New("invalid execution reverted error")

const (
EOutOfGas = iota + jsonrpc.FirstUserCode
EActorNotFound
Expand All @@ -17,36 +21,39 @@ const (
EF3ParticipationTooManyInstances
EF3ParticipationTicketStartBeforeExisting
EF3NotReady
EExecutionReverted
)

var (
RPCErrors = jsonrpc.NewErrors()

// ErrF3Disabled signals that F3 consensus process is disabled.
ErrF3Disabled = errF3Disabled{}
ErrF3Disabled = &errF3Disabled{}
// ErrF3ParticipationTicketInvalid signals that F3ParticipationTicket cannot be decoded.
ErrF3ParticipationTicketInvalid = errF3ParticipationTicketInvalid{}
ErrF3ParticipationTicketInvalid = &errF3ParticipationTicketInvalid{}
// ErrF3ParticipationTicketExpired signals that the current GPBFT instance as surpassed the expiry of the ticket.
ErrF3ParticipationTicketExpired = errF3ParticipationTicketExpired{}
ErrF3ParticipationTicketExpired = &errF3ParticipationTicketExpired{}
// ErrF3ParticipationIssuerMismatch signals that the ticket is not issued by the current node.
ErrF3ParticipationIssuerMismatch = errF3ParticipationIssuerMismatch{}
ErrF3ParticipationIssuerMismatch = &errF3ParticipationIssuerMismatch{}
// ErrF3ParticipationTooManyInstances signals that participation ticket cannot be
// issued because it asks for too many instances.
ErrF3ParticipationTooManyInstances = errF3ParticipationTooManyInstances{}
ErrF3ParticipationTooManyInstances = &errF3ParticipationTooManyInstances{}
// ErrF3ParticipationTicketStartBeforeExisting signals that participation ticket
// is before the start instance of an existing lease held by the miner.
ErrF3ParticipationTicketStartBeforeExisting = errF3ParticipationTicketStartBeforeExisting{}
ErrF3ParticipationTicketStartBeforeExisting = &errF3ParticipationTicketStartBeforeExisting{}
// ErrF3NotReady signals that the F3 instance isn't ready for participation yet. The caller
// should back off and try again later.
ErrF3NotReady = errF3NotReady{}

_ error = (*ErrOutOfGas)(nil)
_ error = (*ErrActorNotFound)(nil)
_ error = (*errF3Disabled)(nil)
_ error = (*errF3ParticipationTicketInvalid)(nil)
_ error = (*errF3ParticipationTicketExpired)(nil)
_ error = (*errF3ParticipationIssuerMismatch)(nil)
_ error = (*errF3NotReady)(nil)
ErrF3NotReady = &errF3NotReady{}

_ error = (*ErrOutOfGas)(nil)
_ error = (*ErrActorNotFound)(nil)
_ error = (*errF3Disabled)(nil)
_ error = (*errF3ParticipationTicketInvalid)(nil)
_ error = (*errF3ParticipationTicketExpired)(nil)
_ error = (*errF3ParticipationIssuerMismatch)(nil)
_ error = (*errF3NotReady)(nil)
_ error = (*ErrExecutionReverted)(nil)
_ jsonrpc.RPCErrorCodec = (*ErrExecutionReverted)(nil)
)

func init() {
Expand All @@ -59,6 +66,7 @@ func init() {
RPCErrors.Register(EF3ParticipationTooManyInstances, new(*errF3ParticipationTooManyInstances))
RPCErrors.Register(EF3ParticipationTicketStartBeforeExisting, new(*errF3ParticipationTicketStartBeforeExisting))
RPCErrors.Register(EF3NotReady, new(*errF3NotReady))
RPCErrors.Register(EExecutionReverted, new(*ErrExecutionReverted))
}

func ErrorIsIn(err error, errorTypes []error) bool {
Expand Down Expand Up @@ -110,3 +118,45 @@ func (errF3ParticipationTicketStartBeforeExisting) Error() string {
type errF3NotReady struct{}

func (errF3NotReady) Error() string { return "f3 isn't yet ready to participate" }

// ErrExecutionReverted is used to return execution reverted with a reason for a revert in the `data` field.
type ErrExecutionReverted struct {
Message string
Data string
}

// Error returns the error message.
func (e *ErrExecutionReverted) Error() string { return e.Message }

// FromJSONRPCError converts a JSONRPCError to ErrExecutionReverted.
func (e *ErrExecutionReverted) FromJSONRPCError(jerr jsonrpc.JSONRPCError) error {
if jerr.Code != EExecutionReverted || jerr.Message == "" || jerr.Data == nil {
return invalidExecutionRevertedMsg
}

data, ok := jerr.Data.(string)
if !ok {
return xerrors.Errorf("expected string data in execution reverted error, got %T", jerr.Data)
}

e.Message = jerr.Message
e.Data = data
return nil
}

// ToJSONRPCError converts ErrExecutionReverted to a JSONRPCError.
func (e *ErrExecutionReverted) ToJSONRPCError() (jsonrpc.JSONRPCError, error) {
return jsonrpc.JSONRPCError{
Code: EExecutionReverted,
Message: e.Message,
Data: e.Data,
}, nil
}

// NewErrExecutionReverted creates a new ErrExecutionReverted with the given reason.
func NewErrExecutionReverted(reason string) *ErrExecutionReverted {
return &ErrExecutionReverted{
Message: "execution reverted",
Data: reason,
}
}
16 changes: 14 additions & 2 deletions chain/lf3/f3.go
Original file line number Diff line number Diff line change
Expand Up @@ -184,8 +184,20 @@ func (fff *F3) GetLatestCert(ctx context.Context) (*certs.FinalityCertificate, e
return fff.inner.GetLatestCert(ctx)
}

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

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

func (fff *F3) GetPowerTable(ctx context.Context, tsk types.TipSetKey) (gpbft.PowerEntries, error) {
Expand Down
1 change: 1 addition & 0 deletions chain/lf3/participation.go
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,7 @@ func (p *Participant) awaitLeaseExpiry(ctx context.Context, lease api.F3Particip
}
log.Errorw("Failed to check F3 progress while awaiting lease expiry. Retrying after backoff.", "attempts", p.backoff.Attempt(), "backoff", p.backoff.Duration(), "err", err)
p.backOff(ctx)
continue
case manifest == nil || manifest.NetworkName != lease.Network:
// If we got an unexpected manifest, or no manifest, go back to the
// beginning and try to get another ticket. Switching from having a manifest
Expand Down
75 changes: 75 additions & 0 deletions chain/lf3/participation_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package lf3_test

import (
"context"
"errors"
"testing"
"time"

"github.com/jpillora/backoff"
"github.com/stretchr/testify/require"

"github.com/filecoin-project/go-address"
"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/node/modules/dtypes"
)

type manifestFailAPI struct {
manifestRequested chan struct{}
}

func (m *manifestFailAPI) F3GetManifest(ctx context.Context) (*manifest.Manifest, error) {
select {
case m.manifestRequested <- struct{}{}:
default:
}
return nil, errors.New("test error")
}

func (m *manifestFailAPI) F3GetOrRenewParticipationTicket(ctx context.Context, minerID address.Address, previous api.F3ParticipationTicket, instances uint64) (api.F3ParticipationTicket, error) {
switch string(previous) {
case "good ticket":
return api.F3ParticipationTicket("bad ticket"), nil
case "":
return api.F3ParticipationTicket("good ticket"), nil
default:
panic("unexpected ticket")
}
}

func (m *manifestFailAPI) F3GetProgress(ctx context.Context) (gpbft.Instant, error) {
return gpbft.Instant{}, nil
}

func (m *manifestFailAPI) F3Participate(ctx context.Context, ticket api.F3ParticipationTicket) (api.F3ParticipationLease, error) {
return api.F3ParticipationLease{
Network: "test",
Issuer: "foobar",
MinerID: 0,
FromInstance: 0,
ValidityTerm: 10,
}, nil
}

// Test that we correctly handle failed requests for the manifest and keep trying to get it.
func TestParticipantManifestFailure(t *testing.T) {
api := &manifestFailAPI{manifestRequested: make(chan struct{}, 5)}
addr, err := address.NewIDAddress(1000)
require.NoError(t, err)

p := lf3.NewParticipant(context.Background(), api, dtypes.MinerAddress(addr),
&backoff.Backoff{
Min: 1 * time.Second,
Max: 1 * time.Minute,
Factor: 1.5,
}, 13, 5)
require.NoError(t, p.Start(context.Background()))
<-api.manifestRequested
<-api.manifestRequested
<-api.manifestRequested
require.NoError(t, p.Stop(context.Background()))
}
Loading

0 comments on commit 68428e3

Please sign in to comment.