Skip to content

Commit cd71e49

Browse files
authored
fix(costs/pdp): avoid PDP sybil fee getter
1 parent 6070d4b commit cd71e49

7 files changed

Lines changed: 318 additions & 208 deletions

File tree

costs/constants.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@ var (
2626
// Access via CDNFixedLockupValue() to prevent in-place mutation of the global.
2727
cdnFixedLockup = big.NewInt(1_000_000_000_000_000_000)
2828

29+
// usdfcSybilFee is the flat lockup charged for each new dataset (0.1 USDFC).
30+
usdfcSybilFee = big.NewInt(100_000_000_000_000_000)
31+
2932
// maxUint256 is 2^256-1.
3033
maxUint256 = new(big.Int).Sub(new(big.Int).Lsh(big.NewInt(1), 256), big.NewInt(1))
3134
// halfMaxUint256 is maxUint256 >> 1.
@@ -34,3 +37,7 @@ var (
3437
bigOne = big.NewInt(1)
3538
bigTiB = big.NewInt(chain.TiB)
3639
)
40+
41+
func usdfcSybilFeeValue() *big.Int {
42+
return new(big.Int).Set(usdfcSybilFee)
43+
}

costs/multi_cost.go

Lines changed: 8 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -85,16 +85,15 @@ func (s *Service) CalculateMultiContextCosts(
8585
}
8686

8787
var (
88-
pricing *warmstorage.ServicePrice
89-
account *payments.AccountState
90-
approval *payments.OperatorApproval
91-
usdfcSybilFee *big.Int
92-
mu sync.Mutex
93-
errs []error
94-
wg sync.WaitGroup
88+
pricing *warmstorage.ServicePrice
89+
account *payments.AccountState
90+
approval *payments.OperatorApproval
91+
mu sync.Mutex
92+
errs []error
93+
wg sync.WaitGroup
9594
)
9695

97-
wg.Add(4)
96+
wg.Add(3)
9897

9998
go func() {
10099
defer wg.Done()
@@ -132,18 +131,6 @@ func (s *Service) CalculateMultiContextCosts(
132131
approval = ap
133132
}()
134133

135-
go func() {
136-
defer wg.Done()
137-
fee, err := s.readUsdfcSybilFee(ctx)
138-
mu.Lock()
139-
defer mu.Unlock()
140-
if err != nil {
141-
errs = append(errs, fmt.Errorf("USDFC_SYBIL_FEE: %w", err))
142-
return
143-
}
144-
usdfcSybilFee = fee
145-
}()
146-
147134
wg.Wait()
148135

149136
if len(errs) > 0 {
@@ -176,7 +163,7 @@ func (s *Service) CalculateMultiContextCosts(
176163
currentSize,
177164
pricing,
178165
DefaultLockupPeriod,
179-
usdfcSybilFee,
166+
usdfcSybilFeeValue(),
180167
ref.IsNewDataSet,
181168
ref.WithCDN,
182169
)

costs/multi_cost_test.go

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,59 @@ func TestCalculateMultiContextCosts_AggregatesRates(t *testing.T) {
9090
}
9191
}
9292

93+
func TestCalculateMultiContextCosts_AddsLocalSybilFeePerNewDataSet(t *testing.T) {
94+
svc := buildSvc(t,
95+
&mockWS{price: defaultPrice()},
96+
&mockPay{
97+
account: &payments.AccountState{Funds: new(big.Int), LockupCurrent: new(big.Int), LockupRate: new(big.Int)},
98+
approval: maxApproval(),
99+
},
100+
usdfc(999),
101+
)
102+
svc.caller = sybilFeeUnavailableCaller{}
103+
opts := &UploadCostOptions{BufferEpochs: -1}
104+
105+
allExisting, err := svc.CalculateMultiContextCosts(
106+
context.Background(),
107+
common.Address{},
108+
bi(1024),
109+
[]MultiContextRef{{}, {}},
110+
opts,
111+
)
112+
if err != nil {
113+
t.Fatalf("all existing CalculateMultiContextCosts: %v", err)
114+
}
115+
allNew, err := svc.CalculateMultiContextCosts(
116+
context.Background(),
117+
common.Address{},
118+
bi(1024),
119+
[]MultiContextRef{{IsNewDataSet: true}, {IsNewDataSet: true}},
120+
opts,
121+
)
122+
if err != nil {
123+
t.Fatalf("all new CalculateMultiContextCosts: %v", err)
124+
}
125+
mixed, err := svc.CalculateMultiContextCosts(
126+
context.Background(),
127+
common.Address{},
128+
bi(1024),
129+
[]MultiContextRef{{IsNewDataSet: true}, {}},
130+
opts,
131+
)
132+
if err != nil {
133+
t.Fatalf("mixed CalculateMultiContextCosts: %v", err)
134+
}
135+
136+
twoNewDelta := new(big.Int).Sub(allNew.DepositNeeded, allExisting.DepositNeeded)
137+
if twoNewDelta.Cmp(usdfcFrac(2)) != 0 {
138+
t.Errorf("two new dataset sybil delta: got %s, want %s", twoNewDelta, usdfcFrac(2))
139+
}
140+
oneNewDelta := new(big.Int).Sub(mixed.DepositNeeded, allExisting.DepositNeeded)
141+
if oneNewDelta.Cmp(usdfcFrac(1)) != 0 {
142+
t.Errorf("one new dataset sybil delta: got %s, want %s", oneNewDelta, usdfcFrac(1))
143+
}
144+
}
145+
93146
func TestCalculateMultiContextCosts_EmptyRefs(t *testing.T) {
94147
svc := buildSvc(t, &mockWS{price: defaultPrice()}, &mockPay{}, usdfcFrac(1))
95148
if _, err := svc.CalculateMultiContextCosts(

costs/service.go

Lines changed: 28 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,19 @@ import (
66
"fmt"
77
"log/slog"
88
"math/big"
9-
"strings"
109
"sync"
1110

1211
"github.com/ethereum/go-ethereum"
13-
"github.com/ethereum/go-ethereum/accounts/abi"
1412
"github.com/ethereum/go-ethereum/common"
1513
"github.com/strahe/synapse-go/chain"
1614
"github.com/strahe/synapse-go/internal/lifecycle"
1715
"github.com/strahe/synapse-go/payments"
1816
"github.com/strahe/synapse-go/warmstorage"
1917
)
2018

21-
// ContractCaller is the subset of ethereum.ContractCaller needed by Service.
19+
// ContractCaller is the chain reader accepted by Service. CallContract remains
20+
// part of the public interface for compatibility; current cost calculations
21+
// only use BlockNumber.
2222
type ContractCaller interface {
2323
CallContract(ctx context.Context, call ethereum.CallMsg, blockNumber *big.Int) ([]byte, error)
2424
BlockNumber(ctx context.Context) (uint64, error)
@@ -38,15 +38,14 @@ type PaymentsReader interface {
3838
// Service computes upload costs and account summaries for the FWSS ecosystem.
3939
// All methods are safe for concurrent use.
4040
type Service struct {
41-
c chain.Chain
42-
ws WarmStorageReader
43-
pay PaymentsReader
44-
caller ContractCaller
45-
pdpVerifier common.Address
46-
usdfc common.Address
47-
fwss common.Address
48-
logger *slog.Logger
49-
lifecycle *lifecycle.Lifecycle
41+
c chain.Chain
42+
ws WarmStorageReader
43+
pay PaymentsReader
44+
caller ContractCaller
45+
usdfc common.Address
46+
fwss common.Address
47+
logger *slog.Logger
48+
lifecycle *lifecycle.Lifecycle
5049
}
5150

5251
// Options configures a [Service].
@@ -61,7 +60,7 @@ type Options struct {
6160
// Payments reads account and allowance state. Required.
6261
Payments PaymentsReader
6362

64-
// Caller issues eth_call against the configured chain. Required.
63+
// Caller provides chain reads for cost calculations. Required.
6564
Caller ContractCaller
6665

6766
// Logger is the structured logger. If nil, logging is silent.
@@ -92,20 +91,15 @@ func New(opts Options) (*Service, error) {
9291
if addrs.USDFC == (common.Address{}) {
9392
return nil, fmt.Errorf("costs.New: %w: %v: missing USDFC address", chain.ErrUnknownChain, opts.Chain)
9493
}
95-
if addrs.PDPVerifier == (common.Address{}) {
96-
return nil, fmt.Errorf("costs.New: %w: %v: missing PDPVerifier address", chain.ErrUnknownChain, opts.Chain)
97-
}
98-
9994
return &Service{
100-
c: opts.Chain,
101-
ws: opts.WarmStorage,
102-
pay: opts.Payments,
103-
caller: opts.Caller,
104-
pdpVerifier: addrs.PDPVerifier,
105-
usdfc: addrs.USDFC,
106-
fwss: addrs.FWSS,
107-
logger: opts.Logger,
108-
lifecycle: opts.Lifecycle,
95+
c: opts.Chain,
96+
ws: opts.WarmStorage,
97+
pay: opts.Payments,
98+
caller: opts.Caller,
99+
usdfc: addrs.USDFC,
100+
fwss: addrs.FWSS,
101+
logger: opts.Logger,
102+
lifecycle: opts.Lifecycle,
109103
}, nil
110104
}
111105

@@ -144,16 +138,15 @@ func (s *Service) GetUploadCosts(
144138
}
145139

146140
var (
147-
pricing *warmstorage.ServicePrice
148-
account *payments.AccountState
149-
approval *payments.OperatorApproval
150-
usdfcSybilFee *big.Int
151-
mu sync.Mutex
152-
errs []error
153-
wg sync.WaitGroup
141+
pricing *warmstorage.ServicePrice
142+
account *payments.AccountState
143+
approval *payments.OperatorApproval
144+
mu sync.Mutex
145+
errs []error
146+
wg sync.WaitGroup
154147
)
155148

156-
wg.Add(4)
149+
wg.Add(3)
157150

158151
go func() {
159152
defer wg.Done()
@@ -191,18 +184,6 @@ func (s *Service) GetUploadCosts(
191184
approval = ap
192185
}()
193186

194-
go func() {
195-
defer wg.Done()
196-
fee, err := s.readUsdfcSybilFee(ctx)
197-
mu.Lock()
198-
defer mu.Unlock()
199-
if err != nil {
200-
errs = append(errs, fmt.Errorf("USDFC_SYBIL_FEE: %w", err))
201-
return
202-
}
203-
usdfcSybilFee = fee
204-
}()
205-
206187
wg.Wait()
207188

208189
if len(errs) > 0 {
@@ -225,7 +206,7 @@ func (s *Service) GetUploadCosts(
225206
currentDataSetSize,
226207
pricing,
227208
DefaultLockupPeriod,
228-
usdfcSybilFee,
209+
usdfcSybilFeeValue(),
229210
opts.IsNewDataSet,
230211
opts.EnableCDN,
231212
)
@@ -324,50 +305,3 @@ func (s *Service) currentEpoch(ctx context.Context) (*big.Int, error) {
324305
}
325306
return new(big.Int).SetUint64(block), nil
326307
}
327-
328-
const usdfcSybilFeeABIJSON = `[{
329-
"type": "function",
330-
"name": "USDFC_SYBIL_FEE",
331-
"inputs": [],
332-
"outputs": [{"name": "", "type": "uint256"}],
333-
"stateMutability": "view"
334-
}]`
335-
336-
var usdfcSybilFeeABI abi.ABI
337-
338-
func init() {
339-
var err error
340-
usdfcSybilFeeABI, err = abi.JSON(strings.NewReader(usdfcSybilFeeABIJSON))
341-
if err != nil {
342-
panic("costs: failed to parse USDFC_SYBIL_FEE ABI: " + err.Error()) //nolint:forbidigo // init() ABI parse: error implies a build/codegen bug, not a runtime condition
343-
}
344-
}
345-
346-
func (s *Service) readUsdfcSybilFee(ctx context.Context) (*big.Int, error) {
347-
data, err := usdfcSybilFeeABI.Pack("USDFC_SYBIL_FEE")
348-
if err != nil {
349-
return nil, fmt.Errorf("costs.readUsdfcSybilFee: pack: %w", err)
350-
}
351-
352-
result, err := s.caller.CallContract(ctx, ethereum.CallMsg{
353-
To: &s.pdpVerifier,
354-
Data: data,
355-
}, nil)
356-
if err != nil {
357-
return nil, fmt.Errorf("costs.readUsdfcSybilFee: call: %w", err)
358-
}
359-
360-
values, err := usdfcSybilFeeABI.Unpack("USDFC_SYBIL_FEE", result)
361-
if err != nil {
362-
return nil, fmt.Errorf("costs.readUsdfcSybilFee: unpack: %w", err)
363-
}
364-
if len(values) == 0 {
365-
return nil, fmt.Errorf("costs.readUsdfcSybilFee: empty result")
366-
}
367-
368-
fee, ok := values[0].(*big.Int)
369-
if !ok {
370-
return nil, fmt.Errorf("costs.readUsdfcSybilFee: unexpected type %T", values[0])
371-
}
372-
return fee, nil
373-
}

0 commit comments

Comments
 (0)