service_market_test.gno
40.90 Kb · 1214 lines
1package service_market
2
3import (
4 "chain"
5 "chain/banker"
6 "strings"
7 "testing"
8
9 "gno.land/p/nt/testutils/v0"
10 "gno.land/p/nt/uassert/v0"
11)
12
13var (
14 testAdmin = testutils.TestAddress("smadmin")
15 prov1 = testutils.TestAddress("smprov1")
16 prov2 = testutils.TestAddress("smprov2")
17 cust1 = testutils.TestAddress("smcust1")
18 cust2 = testutils.TestAddress("smcust2")
19 mallory = testutils.TestAddress("smmallory")
20)
21
22// Established harness facts, carried from the sibling realms' suites:
23// init runs with an empty origin context (the real deploy captures the
24// origin caller); the banker resets between tests while realm globals
25// persist, so conservation is asserted in DELTA form after re-seeding
26// carried liabilities; testing.SetRealm affects only the frame that
27// calls it; and testing.SkipHeights WIPES the origin/realm context, so
28// every caller is re-armed after a skip.
29func init() {
30 admin = testAdmin
31 feeRecipient = testAdmin
32 self = chain.PackageAddress("gno.land/r/g1qp5pt8cdq2f6kfdamn3yuxwg6quqnfpyewzz39/service_market")
33}
34
35type baseline struct{ held, escrow, users, fees int64 }
36
37func begin() baseline {
38 if l := Liabilities(); l > 0 {
39 testing.IssueCoins(Address(), ugnot(l))
40 }
41 return snap()
42}
43
44func snap() baseline {
45 return baseline{held: Held(), escrow: EscrowTotal(), users: UsersTotal(), fees: FeesAccrued()}
46}
47
48// conserved asserts ΔH == ΔE + ΔU + ΔF + extraSurplus, the realm's
49// stated monetary invariant in delta form.
50func (b baseline) conserved(t *testing.T, extraSurplus int64) {
51 t.Helper()
52 dH := Held() - b.held
53 dE := EscrowTotal() - b.escrow
54 dU := UsersTotal() - b.users
55 dF := FeesAccrued() - b.fees
56 if dH != dE+dU+dF+extraSurplus {
57 t.Fatalf("conservation violated: ΔH=%d ΔE=%d ΔU=%d ΔF=%d ΔS=%d", dH, dE, dU, dF, extraSurplus)
58 }
59 if Liabilities() != EscrowTotal()+UsersTotal()+FeesAccrued() {
60 t.Fatalf("Liabilities() = %d, want E+U+F", Liabilities())
61 }
62}
63
64// appInvariant re-derives the escrow pool from the orders themselves.
65// EscrowTotal is a running counter; this proves it still equals Σ amount
66// over non-terminal orders, which is the claim SweepDenom's reserve
67// rests on.
68func appInvariant(t *testing.T) {
69 t.Helper()
70 var sum int64
71 for id := int64(0); id < NumOrders(); id++ {
72 _, _, _, amount, _, status := OrderInfo(id)
73 switch status {
74 case OrderPurchased, OrderDelivered:
75 sum += amount
76 case OrderReleased, OrderRefunded:
77 default:
78 t.Fatalf("order %d has unknown status %q", id, status)
79 }
80 }
81 if sum != EscrowTotal() {
82 t.Fatalf("EscrowTotal() = %d, but Σ open orders = %d", EscrowTotal(), sum)
83 }
84}
85
86func coinsOf(addr address) int64 {
87 return banker.NewReadonlyBanker().GetCoin(addr, Denom)
88}
89
90func ugnot(n int64) chain.Coins {
91 return chain.NewCoins(chain.NewCoin(Denom, n))
92}
93
94// NOTE ON THE HARNESS. testing.SetRealm applies to the frame that CALLS
95// it, so the caller identity must be armed in the SAME frame as the
96// entrypoint invocation. A nested `as(from)` helper is silently
97// ineffective: the realm reverts when that helper returns, and the call
98// lands as the default test caller instead of `from` — which is a test
99// that quietly stops testing what it names. Hence the three lines
100// inline at every site, matching the sibling suites.
101
102// registerAs publishes a service (non-payable: envelope explicitly cleared).
103func registerAs(cur realm, from address, title, desc string, price, delivery int64) int64 {
104 testing.SetRealm(testing.NewUserRealm(from))
105 testing.SetOriginCaller(from)
106 testing.SetOriginSend(nil)
107 return RegisterService(cross(cur), title, desc, price, delivery, MaxFeeBps)
108}
109
110// purchaseAs performs a chain-faithful purchase: envelope staged AND landed.
111func purchaseAs(cur realm, from address, serviceID, pay int64) int64 {
112 testing.SetRealm(testing.NewUserRealm(from))
113 testing.SetOriginCaller(from)
114 testing.SetOriginSend(ugnot(pay))
115 testing.IssueCoins(Address(), ugnot(pay))
116 return PurchaseService(cross(cur), serviceID)
117}
118
119func TestInitialConfig(t *testing.T) {
120 if Admin() != testAdmin || FeeRecipient() != testAdmin {
121 t.Fatal("seeded roles mismatch")
122 }
123 var zero address
124 if PendingAdmin() != zero {
125 t.Fatal("pending admin not zero")
126 }
127 if FeeBps() != 0 || NumServices() != 0 || NumOrders() != 0 {
128 t.Fatal("initial counters not zero")
129 }
130 if Held() != 0 || Liabilities() != 0 || EscrowTotal() != 0 {
131 t.Fatal("initial accounting not zero")
132 }
133 if Address() == zero {
134 t.Fatal("realm address is zero")
135 }
136}
137
138func TestRegisterService(cur realm, t *testing.T) {
139 b := begin()
140 id := registerAs(cur, prov1, "logo design", "two concepts and revisions", 500000, 20000)
141
142 provider, title, price, delivery, snapBps, status, orderCount := ServiceInfo(id)
143 if provider != prov1 || title != "logo design" || price != 500000 ||
144 delivery != 20000 || snapBps != 0 || status != ServiceActive || orderCount != 0 {
145 t.Fatalf("fields wrong: %v %q %d %d %d %s %d",
146 provider, title, price, delivery, snapBps, status, orderCount)
147 }
148 if ServiceDescription(id) != "two concepts and revisions" {
149 t.Fatal("description mismatch")
150 }
151 if ServicesOf(prov1) != 1 {
152 t.Fatalf("ServicesOf = %d, want 1", ServicesOf(prov1))
153 }
154 p, fee, toProvider := Quote(id)
155 if p != 500000 || fee != 0 || toProvider != 500000 {
156 t.Fatalf("Quote = %d/%d/%d", p, fee, toProvider)
157 }
158 appInvariant(t)
159 b.conserved(t, 0)
160}
161
162func TestRegisterRejects(cur realm, t *testing.T) {
163 b := begin()
164
165 // Non-payable: an attached envelope is refused, not stranded.
166 testing.SetRealm(testing.NewUserRealm(prov1))
167 testing.SetOriginCaller(prov1)
168 testing.SetOriginSend(ugnot(100))
169 uassert.AbortsWithMessage(t, cur, "this function does not accept coins", func() {
170 RegisterService(cross(cur), "x", "y", 1, MinDeliveryBlocks, MaxFeeBps)
171 })
172 testing.SetRealm(testing.NewUserRealm(prov1))
173 testing.SetOriginCaller(prov1)
174 testing.SetOriginSend(nil)
175
176 uassert.AbortsContains(t, cur, "title must be", func() {
177 RegisterService(cross(cur), "", "d", 1, MinDeliveryBlocks, MaxFeeBps)
178 })
179 uassert.AbortsContains(t, cur, "title may only contain", func() {
180 RegisterService(cross(cur), "bad*title", "d", 1, MinDeliveryBlocks, MaxFeeBps)
181 })
182 uassert.AbortsContains(t, cur, "description must be", func() {
183 RegisterService(cross(cur), "ok", strings.Repeat("x", MaxDescLen+1), 1, MinDeliveryBlocks, MaxFeeBps)
184 })
185 uassert.AbortsContains(t, cur, "price must be at least", func() {
186 RegisterService(cross(cur), "ok", "d", 0, MinDeliveryBlocks, MaxFeeBps)
187 })
188 uassert.AbortsContains(t, cur, "deliveryBlocks must be", func() {
189 RegisterService(cross(cur), "ok", "d", 1, MinDeliveryBlocks-1, MaxFeeBps)
190 })
191 uassert.AbortsContains(t, cur, "deliveryBlocks must be", func() {
192 RegisterService(cross(cur), "ok", "d", 1, MaxDeliveryBlocks+1, MaxFeeBps)
193 })
194 uassert.AbortsContains(t, cur, "maxFeeBps must be", func() {
195 RegisterService(cross(cur), "ok", "d", 1, MinDeliveryBlocks, MaxFeeBps+1)
196 })
197 appInvariant(t)
198 b.conserved(t, 0)
199}
200
201// The provider's published terms cannot be devalued by an admin fee
202// change between registration and purchase: registration itself refuses
203// a fee above the ceiling the provider signed for. This is the grants Y1
204// pattern, applied at the offer rather than the grant.
205func TestFeeCeilingAndSnapshot(cur realm, t *testing.T) {
206 b := begin()
207
208 testing.SetRealm(testing.NewUserRealm(testAdmin))
209 testing.SetOriginCaller(testAdmin)
210 testing.SetOriginSend(nil)
211 SetFeeBps(cross(cur), 500)
212
213 testing.SetRealm(testing.NewUserRealm(prov1))
214 testing.SetOriginCaller(prov1)
215 testing.SetOriginSend(nil)
216 uassert.AbortsContains(t, cur, "exceeds your ceiling", func() {
217 RegisterService(cross(cur), "cheap only", "d", 1000, MinDeliveryBlocks, 100)
218 })
219
220 // Registered at 500 bps.
221 id := registerAs(cur, prov1, "copywriting", "800 words", 1000000, 20000)
222 _, _, _, _, snapBps, _, _ := ServiceInfo(id)
223 if snapBps != 500 {
224 t.Fatalf("snapshot bps = %d, want 500", snapBps)
225 }
226
227 // Admin raises the fee afterwards; the existing service keeps 500.
228 testing.SetRealm(testing.NewUserRealm(testAdmin))
229 testing.SetOriginCaller(testAdmin)
230 testing.SetOriginSend(nil)
231 SetFeeBps(cross(cur), MaxFeeBps)
232 _, _, _, _, snapBps, _, _ = ServiceInfo(id)
233 if snapBps != 500 {
234 t.Fatalf("snapshot bps changed to %d", snapBps)
235 }
236
237 // And an order placed now carries the SERVICE's 500, not the live cap.
238 oid := purchaseAs(cur, cust1, id, 1000000)
239 _, _, _, _, orderBps, _ := OrderInfo(oid)
240 if orderBps != 500 {
241 t.Fatalf("order bps = %d, want 500", orderBps)
242 }
243
244 // Clean up: release so later tests start from a settled pool.
245 testing.SetRealm(testing.NewUserRealm(prov1))
246 testing.SetOriginCaller(prov1)
247 testing.SetOriginSend(nil)
248 MarkDelivered(cross(cur), oid, "ipfs://copy")
249 testing.SetRealm(testing.NewUserRealm(cust1))
250 testing.SetOriginCaller(cust1)
251 testing.SetOriginSend(nil)
252 AcceptDelivery(cross(cur), oid)
253
254 testing.SetRealm(testing.NewUserRealm(testAdmin))
255 testing.SetOriginCaller(testAdmin)
256 testing.SetOriginSend(nil)
257 SetFeeBps(cross(cur), 0)
258 appInvariant(t)
259 b.conserved(t, 0)
260}
261
262func TestPurchaseEscrows(cur realm, t *testing.T) {
263 b := begin()
264 p0 := BalanceOf(prov1)
265 sid := registerAs(cur, prov1, "translation", "en to fr", 300000, 20000)
266
267 oid := purchaseAs(cur, cust1, sid, 300000)
268 serviceID, customer, provider, amount, _, status := OrderInfo(oid)
269 if serviceID != sid || customer != cust1 || provider != prov1 ||
270 amount != 300000 || status != OrderPurchased {
271 t.Fatalf("order wrong: %d %v %v %d %s", serviceID, customer, provider, amount, status)
272 }
273 // The money is in escrow, NOT yet in anyone's claimable balance.
274 if EscrowTotal()-b.escrow != 300000 {
275 t.Fatalf("ΔE = %d, want 300000", EscrowTotal()-b.escrow)
276 }
277 if BalanceOf(prov1) != p0 {
278 t.Fatalf("provider credited before resolution: %d -> %d", p0, BalanceOf(prov1))
279 }
280 deliveryDeadline, acceptanceDeadline := OrderDeadlines(oid)
281 if deliveryDeadline != Height()+20000 {
282 t.Fatalf("delivery deadline = %d", deliveryDeadline)
283 }
284 if acceptanceDeadline != 0 {
285 t.Fatalf("acceptance deadline set before delivery: %d", acceptanceDeadline)
286 }
287 _, _, _, _, _, _, orderCount := ServiceInfo(sid)
288 if orderCount != 1 {
289 t.Fatalf("service order count = %d", orderCount)
290 }
291 appInvariant(t)
292 b.conserved(t, 0)
293}
294
295func TestPurchaseRejects(cur realm, t *testing.T) {
296 b := begin()
297 sid := registerAs(cur, prov1, "editing", "line edit", 250000, 20000)
298
299 // Wrong amount, in both directions.
300 testing.SetRealm(testing.NewUserRealm(cust1))
301 testing.SetOriginCaller(cust1)
302 testing.SetOriginSend(ugnot(249999))
303 testing.IssueCoins(Address(), ugnot(249999))
304 uassert.AbortsContains(t, cur, "send exactly the listed price", func() {
305 PurchaseService(cross(cur), sid)
306 })
307 testing.SetOriginSend(ugnot(250001))
308 testing.IssueCoins(Address(), ugnot(250001))
309 uassert.AbortsContains(t, cur, "send exactly the listed price", func() {
310 PurchaseService(cross(cur), sid)
311 })
312
313 // Self-purchase.
314 testing.SetRealm(testing.NewUserRealm(prov1))
315 testing.SetOriginCaller(prov1)
316 testing.SetOriginSend(ugnot(250000))
317 testing.IssueCoins(Address(), ugnot(250000))
318 uassert.AbortsWithMessage(t, cur, "the provider cannot purchase their own service", func() {
319 PurchaseService(cross(cur), sid)
320 })
321
322 // Unknown service.
323 testing.SetRealm(testing.NewUserRealm(cust1))
324 testing.SetOriginCaller(cust1)
325 testing.SetOriginSend(ugnot(250000))
326 testing.IssueCoins(Address(), ugnot(250000))
327 uassert.AbortsWithMessage(t, cur, "unknown service id", func() {
328 PurchaseService(cross(cur), 9999)
329 })
330 testing.SetRealm(testing.NewUserRealm(cust1))
331 testing.SetOriginCaller(cust1)
332 testing.SetOriginSend(nil)
333
334 // Those aborts each landed coins at the realm that the transaction
335 // then reverted. In the harness the send is simulated rather than
336 // rolled back, so the excess shows up as surplus; assert it is
337 // EXACTLY surplus and has not leaked into escrow or a balance.
338 appInvariant(t)
339 if EscrowTotal() != b.escrow {
340 t.Fatalf("a rejected purchase moved escrow: %d -> %d", b.escrow, EscrowTotal())
341 }
342 if UsersTotal() != b.users {
343 t.Fatalf("a rejected purchase credited a balance")
344 }
345}
346
347// Retiring stops NEW orders and nothing else. An order already in
348// flight keeps its own copy of provider, amount and fee.
349func TestRetireService(cur realm, t *testing.T) {
350 b := begin()
351 n0 := ServicesOf(prov1)
352 p0 := BalanceOf(prov1)
353 sid := registerAs(cur, prov1, "consulting", "one hour", 400000, 20000)
354 oid := purchaseAs(cur, cust1, sid, 400000)
355
356 testing.SetRealm(testing.NewUserRealm(mallory))
357 testing.SetOriginCaller(mallory)
358 testing.SetOriginSend(nil)
359 uassert.AbortsWithMessage(t, cur, "only the provider may retire this service", func() {
360 RetireService(cross(cur), sid)
361 })
362
363 testing.SetRealm(testing.NewUserRealm(prov1))
364 testing.SetOriginCaller(prov1)
365 testing.SetOriginSend(nil)
366 RetireService(cross(cur), sid)
367 _, _, _, _, _, status, _ := ServiceInfo(sid)
368 if status != ServiceRetired {
369 t.Fatalf("status = %s", status)
370 }
371 if ServicesOf(prov1) != n0 {
372 t.Fatalf("retire did not free the provider slot: %d -> %d", n0, ServicesOf(prov1))
373 }
374
375 // Terminal: no un-retire, and no second retire.
376 uassert.AbortsWithMessage(t, cur, "service is not active", func() {
377 RetireService(cross(cur), sid)
378 })
379
380 // New orders refused...
381 testing.SetRealm(testing.NewUserRealm(cust2))
382 testing.SetOriginCaller(cust2)
383 testing.SetOriginSend(ugnot(400000))
384 testing.IssueCoins(Address(), ugnot(400000))
385 uassert.AbortsWithMessage(t, cur, "service is not active", func() {
386 PurchaseService(cross(cur), sid)
387 })
388
389 // ...but the in-flight order still completes normally.
390 testing.SetRealm(testing.NewUserRealm(prov1))
391 testing.SetOriginCaller(prov1)
392 testing.SetOriginSend(nil)
393 MarkDelivered(cross(cur), oid, "notes.pdf")
394 testing.SetRealm(testing.NewUserRealm(cust1))
395 testing.SetOriginCaller(cust1)
396 testing.SetOriginSend(nil)
397 AcceptDelivery(cross(cur), oid)
398 _, _, _, _, _, ostatus := OrderInfo(oid)
399 if ostatus != OrderReleased {
400 t.Fatalf("in-flight order broke on retire: %s", ostatus)
401 }
402 if BalanceOf(prov1) != p0+400000 {
403 t.Fatalf("provider credited %d, want %d", BalanceOf(prov1)-p0, 400000)
404 }
405 appInvariant(t)
406 // The refused cust2 purchase landed its 400000 at the realm; on chain
407 // the abort reverts that send, but the harness simulates it rather
408 // than rolling it back, so it surfaces as out-of-band surplus. It is
409 // asserted as surplus precisely to prove it did NOT reach escrow or a
410 // balance.
411 b.conserved(t, 400000)
412}
413
414func TestServiceCapPerProvider(cur realm, t *testing.T) {
415 b := begin()
416 ids := make([]int64, 0, MaxServicesPerProvider)
417 for i := 0; i < MaxServicesPerProvider; i++ {
418 ids = append(ids, registerAs(cur, prov2, "svc", "d", 1000, MinDeliveryBlocks))
419 }
420 if ServicesOf(prov2) != MaxServicesPerProvider {
421 t.Fatalf("ServicesOf = %d", ServicesOf(prov2))
422 }
423 testing.SetRealm(testing.NewUserRealm(prov2))
424 testing.SetOriginCaller(prov2)
425 testing.SetOriginSend(nil)
426 uassert.AbortsContains(t, cur, "services per provider", func() {
427 RegisterService(cross(cur), "one too many", "d", 1000, MinDeliveryBlocks, MaxFeeBps)
428 })
429
430 // Retiring frees exactly one slot.
431 RetireService(cross(cur), ids[0])
432 ids = append(ids, registerAs(cur, prov2, "replacement", "d", 1000, MinDeliveryBlocks))
433 testing.SetRealm(testing.NewUserRealm(prov2))
434 testing.SetOriginCaller(prov2)
435 testing.SetOriginSend(nil)
436 uassert.AbortsContains(t, cur, "services per provider", func() {
437 RegisterService(cross(cur), "still too many", "d", 1000, MinDeliveryBlocks, MaxFeeBps)
438 })
439
440 // The cap is per provider, not global.
441 registerAs(cur, prov1, "unaffected", "d", 1000, MinDeliveryBlocks)
442
443 // Teardown: realm globals persist between tests in this harness, so
444 // leaving prov2 pinned at the cap would silently break every later
445 // test that registers as prov2. Retire everything this test opened.
446 testing.SetRealm(testing.NewUserRealm(prov2))
447 testing.SetOriginCaller(prov2)
448 testing.SetOriginSend(nil)
449 for _, id := range ids[1:] {
450 RetireService(cross(cur), id)
451 }
452 if ServicesOf(prov2) != 0 {
453 t.Fatalf("teardown left %d services on prov2", ServicesOf(prov2))
454 }
455 appInvariant(t)
456 b.conserved(t, 0)
457}
458
459// ---- the three required protections ----
460
461// UNAUTHORIZED SETTLEMENT. Nobody but the customer can resolve a
462// delivered order early — not the provider who did the work, not the
463// admin, not the fee recipient, not a stranger, not another realm.
464func TestUnauthorizedSettlement(cur realm, t *testing.T) {
465 b := begin()
466 p0 := BalanceOf(prov1)
467 sid := registerAs(cur, prov1, "audit work", "review the thing", 1000000, 20000)
468 oid := purchaseAs(cur, cust1, sid, 1000000)
469
470 // Only the provider may mark delivered.
471 for _, bad := range []address{cust1, testAdmin, mallory, prov2} {
472 testing.SetRealm(testing.NewUserRealm(bad))
473 testing.SetOriginCaller(bad)
474 testing.SetOriginSend(nil)
475 uassert.AbortsWithMessage(t, cur, "only the provider may mark this order delivered", func() {
476 MarkDelivered(cross(cur), oid, "x")
477 })
478 }
479 // Not even from another code realm.
480 testing.SetRealm(testing.NewCodeRealm("gno.land/r/demo/attacker"))
481 testing.SetOriginSend(nil)
482 uassert.AbortsWithMessage(t, cur, "only the provider may mark this order delivered", func() {
483 MarkDelivered(cross(cur), oid, "x")
484 })
485
486 testing.SetRealm(testing.NewUserRealm(prov1))
487 testing.SetOriginCaller(prov1)
488 testing.SetOriginSend(nil)
489 MarkDelivered(cross(cur), oid, "ipfs://report")
490
491 // Only the customer may accept. THE key authorization.
492 for _, bad := range []address{prov1, testAdmin, mallory, cust2} {
493 testing.SetRealm(testing.NewUserRealm(bad))
494 testing.SetOriginCaller(bad)
495 testing.SetOriginSend(nil)
496 uassert.AbortsWithMessage(t, cur, "only the customer may accept this delivery", func() {
497 AcceptDelivery(cross(cur), oid)
498 })
499 }
500 testing.SetRealm(testing.NewCodeRealm("gno.land/r/demo/attacker"))
501 testing.SetOriginSend(nil)
502 uassert.AbortsWithMessage(t, cur, "only the customer may accept this delivery", func() {
503 AcceptDelivery(cross(cur), oid)
504 })
505
506 // The timeout valve is permissionless but NOT early: even the
507 // provider cannot pull it before the window lapses.
508 testing.SetRealm(testing.NewUserRealm(prov1))
509 testing.SetOriginCaller(prov1)
510 testing.SetOriginSend(nil)
511 uassert.AbortsContains(t, cur, "acceptance window has not lapsed", func() {
512 ReleaseTimeout(cross(cur), oid)
513 })
514
515 // Nothing has moved.
516 if BalanceOf(prov1) != p0 {
517 t.Fatalf("provider credited without resolution: %d -> %d", p0, BalanceOf(prov1))
518 }
519 if EscrowTotal()-b.escrow != 1000000 {
520 t.Fatalf("escrow moved: ΔE=%d", EscrowTotal()-b.escrow)
521 }
522
523 // The customer, and only the customer, resolves it.
524 testing.SetRealm(testing.NewUserRealm(cust1))
525 testing.SetOriginCaller(cust1)
526 testing.SetOriginSend(nil)
527 AcceptDelivery(cross(cur), oid)
528 if BalanceOf(prov1)-p0 != 1000000 {
529 t.Fatalf("provider credited %d, want 1000000 at 0 bps", BalanceOf(prov1)-p0)
530 }
531 appInvariant(t)
532 b.conserved(t, 0)
533}
534
535// There is no admin path to escrow at all. The admin's only powers are
536// the fee for FUTURE services, the fee recipient, and succession.
537func TestAdminCannotTouchEscrow(cur realm, t *testing.T) {
538 b := begin()
539 sid := registerAs(cur, prov1, "held work", "d", 700000, 20000)
540 oid := purchaseAs(cur, cust1, sid, 700000)
541
542 testing.SetRealm(testing.NewUserRealm(testAdmin))
543 testing.SetOriginCaller(testAdmin)
544 testing.SetOriginSend(nil)
545 uassert.AbortsWithMessage(t, cur, "only the provider may mark this order delivered", func() {
546 MarkDelivered(cross(cur), oid, "x")
547 })
548 uassert.AbortsWithMessage(t, cur, "only the provider may decline this order", func() {
549 DeclineOrder(cross(cur), oid)
550 })
551 uassert.AbortsContains(t, cur, "delivery window has not lapsed", func() {
552 ClaimRefund(cross(cur), oid)
553 })
554
555 // And sweep cannot reach live escrow: the reserve covers E too.
556 testing.IssueCoins(Address(), ugnot(12345)) // genuine out-of-band surplus
557 before := coinsOf(testAdmin)
558 SweepDenom(cross(cur), Denom)
559 if got := coinsOf(testAdmin) - before; got != 12345 {
560 t.Fatalf("swept %d, want exactly the 12345 surplus", got)
561 }
562 if EscrowTotal() != b.escrow+700000 {
563 t.Fatalf("sweep reached escrow: %d", EscrowTotal())
564 }
565 appInvariant(t)
566}
567
568// DOUBLE PAYMENT. Every terminal transition is reachable at most once,
569// and the two terminal outcomes are mutually exclusive.
570func TestNoDoublePayment(cur realm, t *testing.T) {
571 b := begin()
572 sid := registerAs(cur, prov1, "double check", "d", 600000, 20000)
573
574 // Accept twice.
575 oid := purchaseAs(cur, cust1, sid, 600000)
576 testing.SetRealm(testing.NewUserRealm(prov1))
577 testing.SetOriginCaller(prov1)
578 testing.SetOriginSend(nil)
579 MarkDelivered(cross(cur), oid, "v1")
580 testing.SetRealm(testing.NewUserRealm(cust1))
581 testing.SetOriginCaller(cust1)
582 testing.SetOriginSend(nil)
583 AcceptDelivery(cross(cur), oid)
584 credited := BalanceOf(prov1)
585 uassert.AbortsWithMessage(t, cur, "order is not awaiting acceptance", func() {
586 AcceptDelivery(cross(cur), oid)
587 })
588 if BalanceOf(prov1) != credited {
589 t.Fatalf("second accept paid again: %d -> %d", credited, BalanceOf(prov1))
590 }
591
592 // Released orders cannot then be refunded, timed out, or re-delivered.
593 uassert.AbortsWithMessage(t, cur, "order is not awaiting acceptance", func() {
594 ReleaseTimeout(cross(cur), oid)
595 })
596 uassert.AbortsWithMessage(t, cur, "order is not awaiting delivery", func() {
597 ClaimRefund(cross(cur), oid)
598 })
599 testing.SetRealm(testing.NewUserRealm(prov1))
600 testing.SetOriginCaller(prov1)
601 testing.SetOriginSend(nil)
602 uassert.AbortsWithMessage(t, cur, "order is not awaiting delivery", func() {
603 DeclineOrder(cross(cur), oid)
604 })
605 uassert.AbortsWithMessage(t, cur, "order is not awaiting delivery", func() {
606 MarkDelivered(cross(cur), oid, "v2")
607 })
608
609 // Decline twice, and a declined order cannot then be released.
610 oid2 := purchaseAs(cur, cust2, sid, 600000)
611 testing.SetRealm(testing.NewUserRealm(prov1))
612 testing.SetOriginCaller(prov1)
613 testing.SetOriginSend(nil)
614 DeclineOrder(cross(cur), oid2)
615 refunded := BalanceOf(cust2)
616 uassert.AbortsWithMessage(t, cur, "order is not awaiting delivery", func() {
617 DeclineOrder(cross(cur), oid2)
618 })
619 if BalanceOf(cust2) != refunded {
620 t.Fatalf("second decline refunded again")
621 }
622 testing.SetRealm(testing.NewUserRealm(cust2))
623 testing.SetOriginCaller(cust2)
624 testing.SetOriginSend(nil)
625 uassert.AbortsWithMessage(t, cur, "order is not awaiting acceptance", func() {
626 AcceptDelivery(cross(cur), oid2)
627 })
628 appInvariant(t)
629 b.conserved(t, 0)
630}
631
632// A claim pays out once; the ledger is debited before coins move.
633func TestNoDoubleClaim(cur realm, t *testing.T) {
634 b := begin()
635 p0 := BalanceOf(prov1) // carried in from earlier tests; ClaimAll drains it too
636 sid := registerAs(cur, prov1, "claim once", "d", 800000, 20000)
637 oid := purchaseAs(cur, cust1, sid, 800000)
638 testing.SetRealm(testing.NewUserRealm(prov1))
639 testing.SetOriginCaller(prov1)
640 testing.SetOriginSend(nil)
641 MarkDelivered(cross(cur), oid, "done")
642 testing.SetRealm(testing.NewUserRealm(cust1))
643 testing.SetOriginCaller(cust1)
644 testing.SetOriginSend(nil)
645 AcceptDelivery(cross(cur), oid)
646
647 testing.SetRealm(testing.NewUserRealm(prov1))
648 testing.SetOriginCaller(prov1)
649 testing.SetOriginSend(nil)
650 before := coinsOf(prov1)
651 ClaimAll(cross(cur))
652 if got := coinsOf(prov1) - before; got != p0+800000 {
653 t.Fatalf("claimed %d, want %d", got, p0+800000)
654 }
655 if BalanceOf(prov1) != 0 {
656 t.Fatal("balance not zeroed")
657 }
658 uassert.AbortsWithMessage(t, cur, "nothing to claim", func() {
659 ClaimAll(cross(cur))
660 })
661 uassert.AbortsContains(t, cur, "insufficient", func() {
662 Claim(cross(cur), 1)
663 })
664 if got := coinsOf(prov1) - before; got != p0+800000 {
665 t.Fatalf("a second claim paid out: total %d", got)
666 }
667 appInvariant(t)
668 b.conserved(t, 0)
669}
670
671// STUCK FUNDS, arm 1: the provider abandons the order. Anyone may
672// return the escrow to the customer once the delivery window lapses.
673func TestStuckFundsProviderAbandons(cur realm, t *testing.T) {
674 b := begin()
675 sid := registerAs(cur, prov1, "never delivered", "d", 900000, MinDeliveryBlocks)
676 oid := purchaseAs(cur, cust1, sid, 900000)
677
678 // Too early, even for the customer.
679 testing.SetRealm(testing.NewUserRealm(cust1))
680 testing.SetOriginCaller(cust1)
681 testing.SetOriginSend(nil)
682 uassert.AbortsContains(t, cur, "delivery window has not lapsed", func() {
683 ClaimRefund(cross(cur), oid)
684 })
685
686 testing.SkipHeights(MinDeliveryBlocks)
687
688 // A total stranger pulls the valve; the money goes to the CUSTOMER,
689 // not to the caller.
690 testing.SetRealm(testing.NewUserRealm(mallory))
691 testing.SetOriginCaller(mallory)
692 testing.SetOriginSend(nil)
693 mBefore := BalanceOf(mallory)
694 ClaimRefund(cross(cur), oid)
695 if BalanceOf(mallory) != mBefore {
696 t.Fatal("the valve paid its caller")
697 }
698 if BalanceOf(cust1) != 900000 {
699 t.Fatalf("customer refund = %d, want 900000", BalanceOf(cust1))
700 }
701 if FeesAccrued() != b.fees {
702 t.Fatal("a refund accrued a protocol fee")
703 }
704 _, _, _, _, _, status := OrderInfo(oid)
705 if status != OrderRefunded {
706 t.Fatalf("status = %s", status)
707 }
708 // And the customer can actually get the coins out.
709 testing.SetRealm(testing.NewUserRealm(cust1))
710 testing.SetOriginCaller(cust1)
711 testing.SetOriginSend(nil)
712 before := coinsOf(cust1)
713 ClaimAll(cross(cur))
714 if got := coinsOf(cust1) - before; got != 900000 {
715 t.Fatalf("customer withdrew %d", got)
716 }
717 appInvariant(t)
718 b.conserved(t, 0)
719}
720
721// STUCK FUNDS, arm 2: the customer goes silent after delivery. Anyone
722// may release the escrow to the provider once acceptance lapses. This
723// is the valve whose polarity is INVERTED from every sibling realm's,
724// and getting it wrong would strand completed work.
725func TestStuckFundsCustomerGoesSilent(cur realm, t *testing.T) {
726 b := begin()
727 sid := registerAs(cur, prov1, "delivered ignored", "d", 1000000, MaxDeliveryBlocks)
728 oid := purchaseAs(cur, cust1, sid, 1000000)
729 testing.SetRealm(testing.NewUserRealm(prov1))
730 testing.SetOriginCaller(prov1)
731 testing.SetOriginSend(nil)
732 MarkDelivered(cross(cur), oid, "ipfs://final")
733
734 _, acceptanceDeadline := OrderDeadlines(oid)
735 if acceptanceDeadline != Height()+AcceptanceBlocks {
736 t.Fatalf("acceptance deadline = %d, want height+%d", acceptanceDeadline, AcceptanceBlocks)
737 }
738
739 testing.SkipHeights(AcceptanceBlocks)
740
741 testing.SetRealm(testing.NewUserRealm(mallory))
742 testing.SetOriginCaller(mallory)
743 testing.SetOriginSend(nil)
744 mBefore := BalanceOf(mallory)
745 ReleaseTimeout(cross(cur), oid)
746 if BalanceOf(mallory) != mBefore {
747 t.Fatal("the valve paid its caller")
748 }
749 if BalanceOf(prov1) != 1000000 {
750 t.Fatalf("provider = %d, want 1000000", BalanceOf(prov1))
751 }
752 _, _, _, _, _, status := OrderInfo(oid)
753 if status != OrderReleased {
754 t.Fatalf("status = %s", status)
755 }
756 appInvariant(t)
757 b.conserved(t, 0)
758}
759
760// The delivery deadline protects the customer, so late delivery is
761// allowed while the refund valve is still un-pulled — but the refund
762// valve closes the instant delivery lands, and reopening it is not
763// possible.
764func TestLateDeliveryRace(cur realm, t *testing.T) {
765 b := begin()
766 p0 := BalanceOf(prov1)
767 sid := registerAs(cur, prov1, "late but wanted", "d", 500000, MinDeliveryBlocks)
768 oid := purchaseAs(cur, cust1, sid, 500000)
769
770 testing.SkipHeights(MinDeliveryBlocks + 10)
771
772 // Provider delivers late; permitted.
773 testing.SetRealm(testing.NewUserRealm(prov1))
774 testing.SetOriginCaller(prov1)
775 testing.SetOriginSend(nil)
776 MarkDelivered(cross(cur), oid, "late.zip")
777
778 // The refund valve is now closed: the order is no longer awaiting
779 // delivery, so the lapsed delivery deadline is irrelevant.
780 testing.SetRealm(testing.NewUserRealm(mallory))
781 testing.SetOriginCaller(mallory)
782 testing.SetOriginSend(nil)
783 uassert.AbortsWithMessage(t, cur, "order is not awaiting delivery", func() {
784 ClaimRefund(cross(cur), oid)
785 })
786 testing.SetRealm(testing.NewUserRealm(cust1))
787 testing.SetOriginCaller(cust1)
788 testing.SetOriginSend(nil)
789 uassert.AbortsWithMessage(t, cur, "order is not awaiting delivery", func() {
790 ClaimRefund(cross(cur), oid)
791 })
792
793 // The customer still holds the real lever: accept, or wait out the
794 // acceptance window.
795 AcceptDelivery(cross(cur), oid)
796 if BalanceOf(prov1)-p0 != 500000 {
797 t.Fatalf("provider credited %d, want 500000", BalanceOf(prov1)-p0)
798 }
799 appInvariant(t)
800 b.conserved(t, 0)
801}
802
803// ---- fees, sweep, administration ----
804
805func TestFeeSplitAndWithdraw(cur realm, t *testing.T) {
806 b := begin()
807 p0 := BalanceOf(prov1)
808 testing.SetRealm(testing.NewUserRealm(testAdmin))
809 testing.SetOriginCaller(testAdmin)
810 testing.SetOriginSend(nil)
811 SetFeeBps(cross(cur), 250) // 2.5%
812
813 sid := registerAs(cur, prov1, "fee bearing", "d", 1000000, 20000)
814 p, fee, toProvider := Quote(sid)
815 if p != 1000000 || fee != 25000 || toProvider != 975000 {
816 t.Fatalf("Quote = %d/%d/%d", p, fee, toProvider)
817 }
818
819 oid := purchaseAs(cur, cust1, sid, 1000000)
820 testing.SetRealm(testing.NewUserRealm(prov1))
821 testing.SetOriginCaller(prov1)
822 testing.SetOriginSend(nil)
823 MarkDelivered(cross(cur), oid, "x")
824 testing.SetRealm(testing.NewUserRealm(cust1))
825 testing.SetOriginCaller(cust1)
826 testing.SetOriginSend(nil)
827 AcceptDelivery(cross(cur), oid)
828
829 if BalanceOf(prov1)-p0 != 975000 {
830 t.Fatalf("provider credited %d, want 975000", BalanceOf(prov1)-p0)
831 }
832 if FeesAccrued()-b.fees != 25000 {
833 t.Fatalf("fee pot ΔF = %d", FeesAccrued()-b.fees)
834 }
835
836 testing.SetRealm(testing.NewUserRealm(mallory))
837 testing.SetOriginCaller(mallory)
838 testing.SetOriginSend(nil)
839 uassert.AbortsWithMessage(t, cur, "only the fee recipient may withdraw fees", func() {
840 WithdrawFees(cross(cur))
841 })
842 testing.SetRealm(testing.NewUserRealm(testAdmin))
843 testing.SetOriginCaller(testAdmin)
844 testing.SetOriginSend(nil)
845 before := coinsOf(testAdmin)
846 WithdrawFees(cross(cur))
847 if got := coinsOf(testAdmin) - before; got != b.fees+25000 {
848 t.Fatalf("withdrew %d", got)
849 }
850 uassert.AbortsWithMessage(t, cur, "no fees accrued", func() {
851 WithdrawFees(cross(cur))
852 })
853
854 testing.SetRealm(testing.NewUserRealm(testAdmin))
855 testing.SetOriginCaller(testAdmin)
856 testing.SetOriginSend(nil)
857 SetFeeBps(cross(cur), 0)
858 appInvariant(t)
859 b.conserved(t, 0)
860}
861
862func TestSweepReservesEscrow(cur realm, t *testing.T) {
863 b := begin()
864 sid := registerAs(cur, prov1, "sweep guard", "d", 400000, 20000)
865 purchaseAs(cur, cust1, sid, 400000)
866
867 // No surplus yet. coinio.Sweep aborts rather than sending zero, so
868 // the escrow is unreachable by REVERT, not merely by arithmetic —
869 // which is the stronger of the two.
870 testing.SetRealm(testing.NewUserRealm(testAdmin))
871 testing.SetOriginCaller(testAdmin)
872 testing.SetOriginSend(nil)
873 before := coinsOf(testAdmin)
874 uassert.AbortsContains(t, cur, "no surplus to sweep", func() {
875 SweepDenom(cross(cur), Denom)
876 })
877 if coinsOf(testAdmin) != before {
878 t.Fatal("swept out of a zero-surplus realm")
879 }
880 if EscrowTotal() != b.escrow+400000 {
881 t.Fatal("sweep reached escrow")
882 }
883
884 // A foreign denom moves wholly.
885 testing.IssueCoins(Address(), chain.NewCoins(chain.NewCoin("gjunk", 77)))
886 SweepDenom(cross(cur), "gjunk")
887 if banker.NewReadonlyBanker().GetCoin(testAdmin, "gjunk") != 77 {
888 t.Fatal("foreign denom not swept")
889 }
890
891 testing.SetRealm(testing.NewUserRealm(mallory))
892 testing.SetOriginCaller(mallory)
893 testing.SetOriginSend(nil)
894 uassert.AbortsWithMessage(t, cur, "only the fee recipient may sweep surplus", func() {
895 SweepDenom(cross(cur), Denom)
896 })
897 appInvariant(t)
898}
899
900func TestAdminHandover(cur realm, t *testing.T) {
901 b := begin()
902 testing.SetRealm(testing.NewUserRealm(mallory))
903 testing.SetOriginCaller(mallory)
904 testing.SetOriginSend(nil)
905 uassert.AbortsWithMessage(t, cur, "admin only", func() {
906 TransferAdmin(cross(cur), mallory)
907 })
908 uassert.AbortsWithMessage(t, cur, "admin only", func() {
909 SetFeeBps(cross(cur), 10)
910 })
911 uassert.AbortsWithMessage(t, cur, "admin only", func() {
912 SetFeeRecipient(cross(cur), mallory)
913 })
914
915 testing.SetRealm(testing.NewUserRealm(testAdmin))
916 testing.SetOriginCaller(testAdmin)
917 testing.SetOriginSend(nil)
918 // A malformed nominee is rejected where the typo is made, for parity
919 // with SetFeeRecipient. The zero address keeps its documented meaning
920 // as the cancel sentinel and must NOT be caught by that check.
921 uassert.AbortsWithMessage(t, cur, "invalid admin address", func() {
922 TransferAdmin(cross(cur), address("g1notanaddress"))
923 })
924 TransferAdmin(cross(cur), prov2)
925 if Admin() != testAdmin {
926 t.Fatal("nomination took effect immediately")
927 }
928 if PendingAdmin() != prov2 {
929 t.Fatalf("pending = %v", PendingAdmin())
930 }
931 TransferAdmin(cross(cur), "")
932 if PendingAdmin() != "" {
933 t.Fatalf("zero address did not cancel: %v", PendingAdmin())
934 }
935 TransferAdmin(cross(cur), prov2)
936
937 // Wrong acceptor.
938 testing.SetRealm(testing.NewUserRealm(mallory))
939 testing.SetOriginCaller(mallory)
940 testing.SetOriginSend(nil)
941 uassert.AbortsWithMessage(t, cur, "only the nominated admin may accept", func() {
942 AcceptAdmin(cross(cur))
943 })
944 testing.SetRealm(testing.NewUserRealm(prov2))
945 testing.SetOriginCaller(prov2)
946 testing.SetOriginSend(nil)
947 AcceptAdmin(cross(cur))
948 if Admin() != prov2 {
949 t.Fatalf("admin = %v", Admin())
950 }
951 var zero address
952 if PendingAdmin() != zero {
953 t.Fatal("pending not cleared")
954 }
955
956 // Authority MOVED: the former admin is now powerless.
957 testing.SetRealm(testing.NewUserRealm(testAdmin))
958 testing.SetOriginCaller(testAdmin)
959 testing.SetOriginSend(nil)
960 uassert.AbortsWithMessage(t, cur, "admin only", func() {
961 SetFeeBps(cross(cur), 10)
962 })
963
964 // Hand it back so the rest of the suite keeps its seeded roles.
965 testing.SetRealm(testing.NewUserRealm(prov2))
966 testing.SetOriginCaller(prov2)
967 testing.SetOriginSend(nil)
968 TransferAdmin(cross(cur), testAdmin)
969 testing.SetRealm(testing.NewUserRealm(testAdmin))
970 testing.SetOriginCaller(testAdmin)
971 testing.SetOriginSend(nil)
972 AcceptAdmin(cross(cur))
973 if Admin() != testAdmin {
974 t.Fatal("handback failed")
975 }
976 appInvariant(t)
977 b.conserved(t, 0)
978}
979
980// ---- render safety ----
981
982func TestRenderSanitizesUntrustedText(cur realm, t *testing.T) {
983 begin()
984 evil := "[click](https://evil.example) "
985 sid := registerAs(cur, prov1, "render probe", evil, 100000, 20000)
986 oid := purchaseAs(cur, cust1, sid, 100000)
987 testing.SetRealm(testing.NewUserRealm(prov1))
988 testing.SetOriginCaller(prov1)
989 testing.SetOriginSend(nil)
990 MarkDelivered(cross(cur), oid, evil)
991
992 sOut := Render("s/" + itoa(sid))
993 if strings.Contains(sOut, "](https://evil.example)") {
994 t.Fatal("service description rendered an unescaped markdown link")
995 }
996 oOut := Render("o/" + itoa(oid))
997 if strings.Contains(oOut, "](https://evil.example/x.png)") {
998 t.Fatal("delivery uri rendered an unescaped markdown image")
999 }
1000
1001 // Unknown and malformed ids degrade to a warning, never a panic.
1002 for _, p := range []string{"s/abc", "o/abc", "s/999999", "o/999999"} {
1003 if !strings.Contains(Render(p), "[!WARNING]") {
1004 t.Fatalf("Render(%q) did not warn", p)
1005 }
1006 }
1007 if !strings.Contains(Render(""), "Service marketplace") {
1008 t.Fatal("home render broken")
1009 }
1010 appInvariant(t)
1011}
1012
1013// The home page is bounded regardless of catalog size.
1014func TestRenderIsBounded(cur realm, t *testing.T) {
1015 begin()
1016 for i := 0; i < RenderLimit+5; i++ {
1017 registerAs(cur, prov2, "bulk svc", "d", 1000, MinDeliveryBlocks)
1018 testing.SetRealm(testing.NewUserRealm(prov2))
1019 testing.SetOriginCaller(prov2)
1020 testing.SetOriginSend(nil)
1021 // Retire immediately so the per-provider cap is not the thing
1022 // under test here.
1023 RetireService(cross(cur), NumServices()-1)
1024 }
1025 out := Render("")
1026 if got := strings.Count(out, "\n- [#"); got > RenderLimit {
1027 t.Fatalf("home listed %d services, cap is %d", got, RenderLimit)
1028 }
1029 appInvariant(t)
1030}
1031
1032// ---- guards on every non-payable entrypoint ----
1033
1034func TestNonPayableEntrypointsRefuseCoins(cur realm, t *testing.T) {
1035 b := begin()
1036 sid := registerAs(cur, prov1, "send guard", "d", 100000, 20000)
1037 oid := purchaseAs(cur, cust1, sid, 100000)
1038
1039 stage := func(from address) {
1040 testing.SetRealm(testing.NewUserRealm(from))
1041 testing.SetOriginCaller(from)
1042 testing.SetOriginSend(ugnot(1))
1043 }
1044 msg := "this function does not accept coins"
1045
1046 stage(prov1)
1047 uassert.AbortsWithMessage(t, cur, msg, func() { MarkDelivered(cross(cur), oid, "x") })
1048 uassert.AbortsWithMessage(t, cur, msg, func() { DeclineOrder(cross(cur), oid) })
1049 uassert.AbortsWithMessage(t, cur, msg, func() { RetireService(cross(cur), sid) })
1050 uassert.AbortsWithMessage(t, cur, msg, func() { ClaimAll(cross(cur)) })
1051 uassert.AbortsWithMessage(t, cur, msg, func() { Claim(cross(cur), 1) })
1052 stage(cust1)
1053 uassert.AbortsWithMessage(t, cur, msg, func() { AcceptDelivery(cross(cur), oid) })
1054 uassert.AbortsWithMessage(t, cur, msg, func() { ClaimRefund(cross(cur), oid) })
1055 uassert.AbortsWithMessage(t, cur, msg, func() { ReleaseTimeout(cross(cur), oid) })
1056 stage(testAdmin)
1057 uassert.AbortsWithMessage(t, cur, msg, func() { SetFeeBps(cross(cur), 1) })
1058 uassert.AbortsWithMessage(t, cur, msg, func() { SetFeeRecipient(cross(cur), prov1) })
1059 uassert.AbortsWithMessage(t, cur, msg, func() { TransferAdmin(cross(cur), prov1) })
1060 uassert.AbortsWithMessage(t, cur, msg, func() { AcceptAdmin(cross(cur)) })
1061 uassert.AbortsWithMessage(t, cur, msg, func() { WithdrawFees(cross(cur)) })
1062 uassert.AbortsWithMessage(t, cur, msg, func() { SweepDenom(cross(cur), Denom) })
1063
1064 testing.SetRealm(testing.NewUserRealm(prov1))
1065 testing.SetOriginCaller(prov1)
1066 testing.SetOriginSend(nil)
1067 appInvariant(t)
1068 if EscrowTotal() != b.escrow+100000 {
1069 t.Fatal("a refused call moved escrow")
1070 }
1071}
1072
1073func TestUnknownIdsAbort(cur realm, t *testing.T) {
1074 begin()
1075 testing.SetRealm(testing.NewUserRealm(mallory))
1076 testing.SetOriginCaller(mallory)
1077 testing.SetOriginSend(nil)
1078 uassert.AbortsWithMessage(t, cur, "unknown service id", func() {
1079 RetireService(cross(cur), 999999)
1080 })
1081 uassert.AbortsWithMessage(t, cur, "unknown order id", func() {
1082 AcceptDelivery(cross(cur), 999999)
1083 })
1084 uassert.AbortsWithMessage(t, cur, "unknown order id", func() {
1085 ClaimRefund(cross(cur), 999999)
1086 })
1087 uassert.AbortsWithMessage(t, cur, "unknown order id", func() {
1088 ReleaseTimeout(cross(cur), 999999)
1089 })
1090 // A view is not a crossing call, so its failure is a plain panic
1091 // rather than an abort — a different assertion, not a weaker one.
1092 uassert.PanicsWithMessage(t, cur, "unknown service id", func() {
1093 ServiceDescription(999999)
1094 })
1095 uassert.PanicsWithMessage(t, cur, "unknown order id", func() {
1096 OrderInfo(999999)
1097 })
1098}
1099
1100func TestMarkDeliveredBoundsURI(cur realm, t *testing.T) {
1101 begin()
1102 sid := registerAs(cur, prov1, "uri bound", "d", 100000, 20000)
1103 oid := purchaseAs(cur, cust1, sid, 100000)
1104 testing.SetRealm(testing.NewUserRealm(prov1))
1105 testing.SetOriginCaller(prov1)
1106 testing.SetOriginSend(nil)
1107 uassert.AbortsContains(t, cur, "uri must be at most", func() {
1108 MarkDelivered(cross(cur), oid, strings.Repeat("u", MaxURILen+1))
1109 })
1110 MarkDelivered(cross(cur), oid, strings.Repeat("u", MaxURILen))
1111 if len(OrderURI(oid)) != MaxURILen {
1112 t.Fatal("uri not stored at the boundary")
1113 }
1114 appInvariant(t)
1115}
1116
1117func TestCheckedAddOverflow(t *testing.T) {
1118 const maxInt64 int64 = 1<<63 - 1
1119 if _, ok := checkedAdd(maxInt64, 1); ok {
1120 t.Fatal("overflow not detected")
1121 }
1122 if v, ok := checkedAdd(maxInt64-1, 1); !ok || v != maxInt64 {
1123 t.Fatal("boundary add rejected")
1124 }
1125 if v, ok := checkedAdd(5, -3); !ok || v != 2 {
1126 t.Fatal("negative delta broken")
1127 }
1128}
1129
1130// A full multi-party run, asserting conservation at every checkpoint —
1131// the property that all three protections ultimately rest on.
1132func TestFullLifecycleConservation(cur realm, t *testing.T) {
1133 b := begin()
1134 testing.SetRealm(testing.NewUserRealm(testAdmin))
1135 testing.SetOriginCaller(testAdmin)
1136 testing.SetOriginSend(nil)
1137 SetFeeBps(cross(cur), 100) // 1%
1138
1139 s1 := registerAs(cur, prov1, "alpha", "d", 1000000, MinDeliveryBlocks)
1140 s2 := registerAs(cur, prov2, "beta", "d", 2000000, MaxDeliveryBlocks)
1141 b.conserved(t, 0)
1142
1143 // Accepted.
1144 o1 := purchaseAs(cur, cust1, s1, 1000000)
1145 b.conserved(t, 0)
1146 testing.SetRealm(testing.NewUserRealm(prov1))
1147 testing.SetOriginCaller(prov1)
1148 testing.SetOriginSend(nil)
1149 MarkDelivered(cross(cur), o1, "a")
1150 testing.SetRealm(testing.NewUserRealm(cust1))
1151 testing.SetOriginCaller(cust1)
1152 testing.SetOriginSend(nil)
1153 AcceptDelivery(cross(cur), o1)
1154 b.conserved(t, 0)
1155
1156 // Declined.
1157 o2 := purchaseAs(cur, cust2, s2, 2000000)
1158 testing.SetRealm(testing.NewUserRealm(prov2))
1159 testing.SetOriginCaller(prov2)
1160 testing.SetOriginSend(nil)
1161 DeclineOrder(cross(cur), o2)
1162 b.conserved(t, 0)
1163
1164 // Expired to a refund.
1165 o3 := purchaseAs(cur, cust1, s1, 1000000)
1166 testing.SkipHeights(MinDeliveryBlocks)
1167 testing.SetRealm(testing.NewUserRealm(mallory))
1168 testing.SetOriginCaller(mallory)
1169 testing.SetOriginSend(nil)
1170 ClaimRefund(cross(cur), o3)
1171 b.conserved(t, 0)
1172
1173 // Timed out to a release.
1174 o4 := purchaseAs(cur, cust2, s2, 2000000)
1175 testing.SetRealm(testing.NewUserRealm(prov2))
1176 testing.SetOriginCaller(prov2)
1177 testing.SetOriginSend(nil)
1178 MarkDelivered(cross(cur), o4, "b")
1179 testing.SkipHeights(AcceptanceBlocks)
1180 testing.SetRealm(testing.NewUserRealm(mallory))
1181 testing.SetOriginCaller(mallory)
1182 testing.SetOriginSend(nil)
1183 ReleaseTimeout(cross(cur), o4)
1184 b.conserved(t, 0)
1185
1186 if EscrowTotal() != b.escrow {
1187 t.Fatalf("escrow not drained: %d -> %d", b.escrow, EscrowTotal())
1188 }
1189
1190 // Everyone withdraws; the realm ends holding only what it started
1191 // with plus the fee pot it still owes.
1192 for _, who := range []address{prov1, prov2, cust1, cust2, testAdmin, mallory} {
1193 if BalanceOf(who) == 0 {
1194 continue
1195 }
1196 testing.SetRealm(testing.NewUserRealm(who))
1197 testing.SetOriginCaller(who)
1198 testing.SetOriginSend(nil)
1199 ClaimAll(cross(cur))
1200 }
1201 // Every counterparty this suite has ever used is in that list, so
1202 // draining them must take U to exactly zero — not back to the
1203 // baseline, which still carried earlier tests' unclaimed credits.
1204 if UsersTotal() != 0 {
1205 t.Fatalf("claimable residue: %d", UsersTotal())
1206 }
1207 appInvariant(t)
1208 b.conserved(t, 0)
1209
1210 testing.SetRealm(testing.NewUserRealm(testAdmin))
1211 testing.SetOriginCaller(testAdmin)
1212 testing.SetOriginSend(nil)
1213 SetFeeBps(cross(cur), 0)
1214}