Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions .github/workflows/go-check.yml
Original file line number Diff line number Diff line change
@@ -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
4 changes: 4 additions & 0 deletions .github/workflows/go-test-config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"skip32bit": true,
"skipOSes": ["windows"]
}
22 changes: 22 additions & 0 deletions .github/workflows/go-test.yml
Original file line number Diff line number Diff line change
@@ -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 }}
2 changes: 1 addition & 1 deletion cli/cmd/payments/approveoperator.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
Expand Down
2 changes: 1 addition & 1 deletion cli/cmd/payments/authorizesession.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
Expand Down
9 changes: 5 additions & 4 deletions cli/cmd/payments/calculate.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
Expand Down Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion cli/cmd/payments/deposit.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
Expand Down
2 changes: 1 addition & 1 deletion cli/cmd/payments/revokeoperator.go
Original file line number Diff line number Diff line change
Expand Up @@ -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{
Expand Down
2 changes: 1 addition & 1 deletion cli/cmd/payments/settlerail.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
Expand Down
2 changes: 1 addition & 1 deletion cli/cmd/providers/approve.go
Original file line number Diff line number Diff line change
Expand Up @@ -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{
Expand Down
2 changes: 1 addition & 1 deletion cli/cmd/providers/get.go
Original file line number Diff line number Diff line change
Expand Up @@ -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{
Expand Down
2 changes: 1 addition & 1 deletion cli/cmd/providers/list.go
Original file line number Diff line number Diff line change
@@ -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 (
Expand Down
4 changes: 2 additions & 2 deletions cli/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion pkg/services/chain/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,4 @@ func ExecuteContractCall(fn func() (*types.Transaction, error), context string)
return nil, fmt.Errorf("%s: %w", context, vmErr)
}
return tx, nil
}
}
2 changes: 1 addition & 1 deletion pkg/services/inspector/inspector.go
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down
156 changes: 1 addition & 155 deletions pkg/services/inspector/payments.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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()
Expand Down
Loading