From e68c664e77fc3443d6420ca7edc0bcb724fc8c6f Mon Sep 17 00:00:00 2001 From: hannahhoward Date: Fri, 31 Jul 2026 22:30:33 -0700 Subject: [PATCH 1/2] ci: add Unified CI test/check workflows (pinned); remove dead rail-status slow path Co-Authored-By: Claude Fable 5 --- .github/workflows/go-check.yml | 18 +++ .github/workflows/go-test-config.json | 4 + .github/workflows/go-test.yml | 22 ++++ pkg/services/inspector/payments.go | 156 +------------------------- 4 files changed, 45 insertions(+), 155 deletions(-) create mode 100644 .github/workflows/go-check.yml create mode 100644 .github/workflows/go-test-config.json create mode 100644 .github/workflows/go-test.yml diff --git a/.github/workflows/go-check.yml b/.github/workflows/go-check.yml new file mode 100644 index 0000000..ebbadcb --- /dev/null +++ b/.github/workflows/go-check.yml @@ -0,0 +1,18 @@ +name: Go Checks + +on: + pull_request: + push: + branches: ["main"] + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.event_name == 'push' && github.sha || github.ref }} + cancel-in-progress: true + +jobs: + go-check: + uses: ipdxco/unified-github-workflows/.github/workflows/go-check.yml@63392e900bbe802fb1a826ba763f6f543773dc36 # v1.0 diff --git a/.github/workflows/go-test-config.json b/.github/workflows/go-test-config.json new file mode 100644 index 0000000..abfb8f9 --- /dev/null +++ b/.github/workflows/go-test-config.json @@ -0,0 +1,4 @@ +{ + "skip32bit": true, + "skipOSes": ["windows"] +} diff --git a/.github/workflows/go-test.yml b/.github/workflows/go-test.yml new file mode 100644 index 0000000..fae951c --- /dev/null +++ b/.github/workflows/go-test.yml @@ -0,0 +1,22 @@ +name: Go Test + +on: + pull_request: + push: + branches: ["main"] + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.event_name == 'push' && github.sha || github.ref }} + cancel-in-progress: true + +jobs: + go-test: + uses: ipdxco/unified-github-workflows/.github/workflows/go-test.yml@63392e900bbe802fb1a826ba763f6f543773dc36 # v1.0 + with: + go-versions: '["this"]' + secrets: + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} diff --git a/pkg/services/inspector/payments.go b/pkg/services/inspector/payments.go index a1adad2..bcb6367 100644 --- a/pkg/services/inspector/payments.go +++ b/pkg/services/inspector/payments.go @@ -209,11 +209,6 @@ func (s *Service) PaymentsStatus(ctx context.Context, tokenAddr, payer common.Ad } // 7. Calculate derived values for each rail in parallel - type railStatusResult struct { - index int - status *types.RailStatus - } - // Flatten all rails for parallel processing type railJob struct { payeeAddr common.Address @@ -449,120 +444,6 @@ func (s *Service) getRailDetailInfo(ctx context.Context, railID *big.Int) (*rail }, nil } -// calculateRailStatus computes the derived values for a rail including actual settleable amounts -func (s *Service) calculateRailStatus(ctx context.Context, rail *railDetailInfo, railId *big.Int, isTerminated bool, currentEpoch, lockupLastSettledAt *big.Int) *types.RailStatus { - var unsettledEpochs, settleableEpochs *big.Int - - // Determine the settlement cap epoch - var capEpoch *big.Int - if isTerminated && rail.EndEpoch != nil && rail.EndEpoch.Cmp(big.NewInt(0)) > 0 { - // Terminated rail - unsettled is up to endEpoch - unsettledEpochs = new(big.Int).Sub(rail.EndEpoch, rail.SettledUpTo) - // For terminated rails, streaming lockup covers all remaining epochs - settleableEpochs = new(big.Int).Set(unsettledEpochs) - capEpoch = rail.EndEpoch - } else { - // Non-terminated rail - unsettledEpochs = new(big.Int).Sub(currentEpoch, rail.SettledUpTo) - - // Settleable is capped by lockupLastSettledAt - capEpoch = new(big.Int).Set(currentEpoch) - if lockupLastSettledAt.Cmp(currentEpoch) < 0 { - capEpoch = lockupLastSettledAt - } - settleableEpochs = new(big.Int).Sub(capEpoch, rail.SettledUpTo) - } - - // Clamp to zero if negative - if unsettledEpochs.Sign() < 0 { - unsettledEpochs = big.NewInt(0) - } - if settleableEpochs.Sign() < 0 { - settleableEpochs = big.NewInt(0) - } - - // Calculate theoretical amounts (assuming 100% proofs) - unsettledAmount := new(big.Int).Mul(unsettledEpochs, rail.PaymentRate) - settleableAmount := new(big.Int).Mul(settleableEpochs, rail.PaymentRate) - - // Determine if rail has a validator - hasValidator := rail.Validator != (common.Address{}) - - status := &types.RailStatus{ - RailId: railId, - PaymentRate: rail.PaymentRate, - SettledUpTo: rail.SettledUpTo, - LockupPeriod: rail.LockupPeriod, - LockupFixed: rail.LockupFixed, - IsTerminated: isTerminated, - EndEpoch: rail.EndEpoch, - Operator: rail.Operator, - Validator: rail.Validator, - CommissionRateBps: rail.CommissionRateBps, - UnsettledEpochs: unsettledEpochs, - UnsettledAmount: unsettledAmount, - SettleableEpochs: settleableEpochs, - SettleableAmount: settleableAmount, - HasValidator: hasValidator, - } - - // If no validator, actual = theoretical (CDN rails pay fully) - if !hasValidator { - status.ProvenEpochs = new(big.Int).Set(settleableEpochs) - status.ActualSettleable = new(big.Int).Set(settleableAmount) - status.ProofSuccessRate = 1.0 - return status - } - - // Query proving state - provingState, err := s.getRailProvingState(ctx, railId) - if err != nil { - log.Warnw("failed to get proving state, falling back to theoretical", "railId", railId, "error", err) - status.ProvenEpochs = new(big.Int).Set(settleableEpochs) - status.ActualSettleable = new(big.Int).Set(settleableAmount) - status.ProofSuccessRate = 1.0 - return status - } - - if !provingState.HasValidator { - // Rail not registered with service contract - status.ProvenEpochs = new(big.Int).Set(settleableEpochs) - status.ActualSettleable = new(big.Int).Set(settleableAmount) - status.ProofSuccessRate = 1.0 - return status - } - - // Count proven epochs - provenEpochs, err := s.countProvenEpochs(ctx, provingState, rail.SettledUpTo, capEpoch) - if err != nil { - log.Warnw("failed to count proven epochs, falling back to theoretical", "railId", railId, "error", err) - status.ProvenEpochs = new(big.Int).Set(settleableEpochs) - status.ActualSettleable = new(big.Int).Set(settleableAmount) - status.ProofSuccessRate = 1.0 - return status - } - - // Cap by settleable (lockup constraint still applies) - if provenEpochs.Cmp(settleableEpochs) > 0 { - provenEpochs = new(big.Int).Set(settleableEpochs) - } - - status.ProvenEpochs = provenEpochs - status.ActualSettleable = new(big.Int).Mul(provenEpochs, rail.PaymentRate) - - // Calculate success rate - if settleableEpochs.Sign() > 0 { - provenF := new(big.Float).SetInt(provenEpochs) - settleableF := new(big.Float).SetInt(settleableEpochs) - rateF := new(big.Float).Quo(provenF, settleableF) - status.ProofSuccessRate, _ = rateF.Float64() - } else { - status.ProofSuccessRate = 1.0 - } - - return status -} - // calculateRailStatusFast computes rail status using pre-fetched proving data (no extra RPC calls) func (s *Service) calculateRailStatusFast(ctx context.Context, rail *railDetailInfo, railId *big.Int, isTerminated bool, currentEpoch, lockupLastSettledAt, dataSetId, activationEpoch *big.Int, maxProvingPeriod uint64) *types.RailStatus { @@ -731,41 +612,6 @@ type railProvingState struct { HasValidator bool // false if dataSetId == 0 } -// getRailProvingState fetches proving state for a rail -func (s *Service) getRailProvingState(ctx context.Context, railId *big.Int) (*railProvingState, error) { - bindCtx := &bind.CallOpts{Context: ctx} - - // 1. railToDataSet(railId) -> dataSetId - dataSetId, err := s.ServiceViewContract.RailToDataSet(bindCtx, railId) - if err != nil { - return nil, fmt.Errorf("querying rail to dataset mapping: %w", err) - } - - // If dataSetId == 0, rail has no validator - if dataSetId.Cmp(big.NewInt(0)) == 0 { - return &railProvingState{HasValidator: false}, nil - } - - // 2. provingActivationEpoch(dataSetId) - activationEpoch, err := s.ServiceViewContract.ProvingActivationEpoch(bindCtx, dataSetId) - if err != nil { - return nil, fmt.Errorf("querying proving activation epoch: %w", err) - } - - // 3. getPDPConfig() - pdpConfig, err := s.ServiceViewContract.GetPDPConfig(bindCtx) - if err != nil { - return nil, fmt.Errorf("querying max proving period: %w", err) - } - - return &railProvingState{ - DataSetId: dataSetId, - ActivationEpoch: activationEpoch, - MaxProvingPeriod: pdpConfig.MaxProvingPeriod, - HasValidator: true, - }, nil -} - // calculateProvenPeriodsSlot computes storage slot for provenPeriods[dataSetId][bucketId] // Formula: keccak256(bucketId . keccak256(dataSetId . baseSlot)) func calculateProvenPeriodsSlot(dataSetId *big.Int, bucketId uint64) [32]byte { @@ -803,7 +649,7 @@ func (s *Service) countProvenEpochs( ctx context.Context, state *railProvingState, fromEpoch *big.Int, // settledUpTo (exclusive start) - toEpoch *big.Int, // currentEpoch (inclusive end) + toEpoch *big.Int, // currentEpoch (inclusive end) ) (*big.Int, error) { fromEpochU := fromEpoch.Uint64() toEpochU := toEpoch.Uint64() From 7a69c7d610d023383aa89b11761245beab1f3d19 Mon Sep 17 00:00:00 2001 From: hannahhoward Date: Fri, 31 Jul 2026 22:37:32 -0700 Subject: [PATCH 2/2] chore: gofmt -s the repo (first run of the gofmt check) Co-Authored-By: Claude Fable 5 --- cli/cmd/payments/approveoperator.go | 2 +- cli/cmd/payments/authorizesession.go | 2 +- cli/cmd/payments/calculate.go | 9 +++++---- cli/cmd/payments/deposit.go | 2 +- cli/cmd/payments/revokeoperator.go | 2 +- cli/cmd/payments/settlerail.go | 2 +- cli/cmd/providers/approve.go | 2 +- cli/cmd/providers/get.go | 2 +- cli/cmd/providers/list.go | 2 +- cli/cmd/root.go | 4 ++-- pkg/services/chain/errors.go | 2 +- pkg/services/inspector/inspector.go | 2 +- pkg/services/types/types.go | 6 +++--- 13 files changed, 20 insertions(+), 19 deletions(-) diff --git a/cli/cmd/payments/approveoperator.go b/cli/cmd/payments/approveoperator.go index e75550b..f26f94d 100644 --- a/cli/cmd/payments/approveoperator.go +++ b/cli/cmd/payments/approveoperator.go @@ -4,12 +4,12 @@ import ( "fmt" "math/big" - "github.com/spf13/cobra" "github.com/fil-forge/forgectl/cli/config" "github.com/fil-forge/forgectl/cli/printer" "github.com/fil-forge/forgectl/pkg/services/chain" "github.com/fil-forge/forgectl/pkg/services/inspector" payerservice "github.com/fil-forge/forgectl/pkg/services/payer" + "github.com/spf13/cobra" ) var ( diff --git a/cli/cmd/payments/authorizesession.go b/cli/cmd/payments/authorizesession.go index a4c26fa..039c5c2 100644 --- a/cli/cmd/payments/authorizesession.go +++ b/cli/cmd/payments/authorizesession.go @@ -10,13 +10,13 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/signer/core/apitypes" - "github.com/spf13/cobra" "github.com/fil-forge/filecoin-services/go/eip712" "github.com/fil-forge/forgectl/cli/config" "github.com/fil-forge/forgectl/cli/printer" "github.com/fil-forge/forgectl/pkg/services/chain" "github.com/fil-forge/forgectl/pkg/services/inspector" payerservice "github.com/fil-forge/forgectl/pkg/services/payer" + "github.com/spf13/cobra" ) const ( diff --git a/cli/cmd/payments/calculate.go b/cli/cmd/payments/calculate.go index a6e4df0..d335865 100644 --- a/cli/cmd/payments/calculate.go +++ b/cli/cmd/payments/calculate.go @@ -9,8 +9,8 @@ import ( "github.com/fil-forge/forgectl/cli/printer" "github.com/fil-forge/forgectl/pkg/services/inspector" - "github.com/spf13/cobra" "github.com/fil-forge/forgectl/cli/config" + "github.com/spf13/cobra" ) const ( @@ -128,9 +128,10 @@ func ParseSize(sizeStr string) (*big.Int, error) { // based on the dataset size and lockup parameters. // // Formula from https://filecoinproject.slack.com/archives/C07CGTXHHT4/p1759276539956319 -// rateAllowance = (sizeInBytes × pricePerTiBPerMonth) / (TiB_IN_BYTES × epochsPerMonth) -// lockupAllowance = ratePerEpoch × lockupPeriodInEpochs -// maxLockupPeriod = maxLockupPeriodDays × EpochsPerDay +// +// rateAllowance = (sizeInBytes × pricePerTiBPerMonth) / (TiB_IN_BYTES × epochsPerMonth) +// lockupAllowance = ratePerEpoch × lockupPeriodInEpochs +// maxLockupPeriod = maxLockupPeriodDays × EpochsPerDay // // Parameters: // - sizeInBytes: The dataset size in bytes diff --git a/cli/cmd/payments/deposit.go b/cli/cmd/payments/deposit.go index 68c14d9..6b47090 100644 --- a/cli/cmd/payments/deposit.go +++ b/cli/cmd/payments/deposit.go @@ -5,12 +5,12 @@ import ( "math/big" "strings" - "github.com/spf13/cobra" "github.com/fil-forge/forgectl/cli/config" "github.com/fil-forge/forgectl/cli/printer" "github.com/fil-forge/forgectl/pkg/services/chain" "github.com/fil-forge/forgectl/pkg/services/inspector" payerservice "github.com/fil-forge/forgectl/pkg/services/payer" + "github.com/spf13/cobra" ) var ( diff --git a/cli/cmd/payments/revokeoperator.go b/cli/cmd/payments/revokeoperator.go index ef4a971..ae78738 100644 --- a/cli/cmd/payments/revokeoperator.go +++ b/cli/cmd/payments/revokeoperator.go @@ -4,12 +4,12 @@ import ( "fmt" "math/big" - "github.com/spf13/cobra" "github.com/fil-forge/forgectl/cli/config" "github.com/fil-forge/forgectl/cli/printer" "github.com/fil-forge/forgectl/pkg/services/chain" "github.com/fil-forge/forgectl/pkg/services/inspector" payerservice "github.com/fil-forge/forgectl/pkg/services/payer" + "github.com/spf13/cobra" ) var revokeOperatorCmd = &cobra.Command{ diff --git a/cli/cmd/payments/settlerail.go b/cli/cmd/payments/settlerail.go index 267f238..c3e8500 100644 --- a/cli/cmd/payments/settlerail.go +++ b/cli/cmd/payments/settlerail.go @@ -4,12 +4,12 @@ import ( "fmt" "math/big" - "github.com/spf13/cobra" "github.com/fil-forge/forgectl/cli/config" "github.com/fil-forge/forgectl/cli/printer" "github.com/fil-forge/forgectl/pkg/services/chain" "github.com/fil-forge/forgectl/pkg/services/inspector" payerservice "github.com/fil-forge/forgectl/pkg/services/payer" + "github.com/spf13/cobra" ) var ( diff --git a/cli/cmd/providers/approve.go b/cli/cmd/providers/approve.go index fdb331f..1f21509 100644 --- a/cli/cmd/providers/approve.go +++ b/cli/cmd/providers/approve.go @@ -4,12 +4,12 @@ import ( "fmt" "strconv" - "github.com/spf13/cobra" "github.com/fil-forge/forgectl/cli/config" "github.com/fil-forge/forgectl/cli/printer" "github.com/fil-forge/forgectl/pkg/services/chain" "github.com/fil-forge/forgectl/pkg/services/inspector" "github.com/fil-forge/forgectl/pkg/services/operator" + "github.com/spf13/cobra" ) var approveCmd = &cobra.Command{ diff --git a/cli/cmd/providers/get.go b/cli/cmd/providers/get.go index 9250867..1900153 100644 --- a/cli/cmd/providers/get.go +++ b/cli/cmd/providers/get.go @@ -5,11 +5,11 @@ import ( "strconv" "github.com/ethereum/go-ethereum/common" - "github.com/spf13/cobra" "github.com/fil-forge/forgectl/cli/config" "github.com/fil-forge/forgectl/cli/printer" "github.com/fil-forge/forgectl/pkg/services/inspector" "github.com/fil-forge/forgectl/pkg/services/types" + "github.com/spf13/cobra" ) var getCmd = &cobra.Command{ diff --git a/cli/cmd/providers/list.go b/cli/cmd/providers/list.go index 748d505..056d6af 100644 --- a/cli/cmd/providers/list.go +++ b/cli/cmd/providers/list.go @@ -1,10 +1,10 @@ package providers import ( - "github.com/spf13/cobra" "github.com/fil-forge/forgectl/cli/config" "github.com/fil-forge/forgectl/cli/printer" "github.com/fil-forge/forgectl/pkg/services/inspector" + "github.com/spf13/cobra" ) var ( diff --git a/cli/cmd/root.go b/cli/cmd/root.go index c090298..734c841 100644 --- a/cli/cmd/root.go +++ b/cli/cmd/root.go @@ -5,11 +5,11 @@ import ( "errors" "strings" - "github.com/spf13/cobra" - "github.com/spf13/viper" "github.com/fil-forge/forgectl/cli/cmd/metrics" "github.com/fil-forge/forgectl/cli/cmd/payments" "github.com/fil-forge/forgectl/cli/cmd/providers" + "github.com/spf13/cobra" + "github.com/spf13/viper" ) var cfgFile string diff --git a/pkg/services/chain/errors.go b/pkg/services/chain/errors.go index ac1b9c3..2775eb5 100644 --- a/pkg/services/chain/errors.go +++ b/pkg/services/chain/errors.go @@ -27,4 +27,4 @@ func ExecuteContractCall(fn func() (*types.Transaction, error), context string) return nil, fmt.Errorf("%s: %w", context, vmErr) } return tx, nil -} \ No newline at end of file +} diff --git a/pkg/services/inspector/inspector.go b/pkg/services/inspector/inspector.go index 568927c..b754faa 100644 --- a/pkg/services/inspector/inspector.go +++ b/pkg/services/inspector/inspector.go @@ -12,8 +12,8 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethclient" - logging "github.com/ipfs/go-log/v2" "github.com/fil-forge/filecoin-services/go/bindings" + logging "github.com/ipfs/go-log/v2" ) var log = logging.Logger("service/inspector") diff --git a/pkg/services/types/types.go b/pkg/services/types/types.go index bf88b7d..99bb1d2 100644 --- a/pkg/services/types/types.go +++ b/pkg/services/types/types.go @@ -66,9 +66,9 @@ type PayeeStatus struct { Rails []*RailStatus `json:"rails"` // Aggregated totals across all rails (using clear terminology) - TotalOwed *big.Int `json:"totalOwed"` // total accrued since last settlement (was TotalUnsettled) - TotalClaimable *big.Int `json:"totalClaimable"` // can settle now: funded + proven (was TotalActualSettleable) - TotalUnfunded *big.Int `json:"totalUnfunded"` // payer hasn't locked funds yet (Owed - Theoretical) + TotalOwed *big.Int `json:"totalOwed"` // total accrued since last settlement (was TotalUnsettled) + TotalClaimable *big.Int `json:"totalClaimable"` // can settle now: funded + proven (was TotalActualSettleable) + TotalUnfunded *big.Int `json:"totalUnfunded"` // payer hasn't locked funds yet (Owed - Theoretical) TotalProofFaults *big.Int `json:"totalProofFaults"` // lost due to missed proofs (Theoretical - Claimable) // Legacy fields for backwards compatibility (deprecated, use above)