|
| 1 | +# Fix dlog-fabric-t12 (Multisig) panic caused by composite-owner output regression |
| 2 | + |
| 3 | +## Goal |
| 4 | +`dlog-fabric-t12` (EndToEnd Multisig, all three P2P transports: websocket, libp2p, replicas) |
| 5 | +panics deterministically on bob's/charlie's node inside `AcceptCashView.Call` |
| 6 | +(`integration/token/fungible/views/accept.go:38`). Root cause: commit `6269df950` |
| 7 | +changed `extractIssueOutputs`/`extractTransferOutputs` (`token/request.go`) to emit a |
| 8 | +single `Output` owned by the *composite* multisig/policy identity when a token has |
| 9 | +`len(recipients) > 1`, instead of one `Output` per individual co-owner. But |
| 10 | +`AcceptCashView.Call` still checks `outputs.ByRecipient(id)` where `id` is the |
| 11 | +responder's own *individual* identity (from `RespondRequestRecipientIdentityUsingWallet`), |
| 12 | +and `OutputStream.ByRecipient` (`token/stream.go`) does strict `id.Equal(t.Owner)` |
| 13 | +equality — which never matches the composite owner, so `assert.True(...)` panics. |
| 14 | +That panic propagates back to alice's `MultiSigLockView.Call` panic at `multisig.go:76` |
| 15 | +via `collectendorsements.go`'s `distributeTxToParties`/`fanOut`. |
| 16 | + |
| 17 | +Fix: make the ownership check membership-aware (composite-identity-aware), mirroring |
| 18 | +the existing pattern already used correctly in `AssertTokens` (`utils.go:32`: |
| 19 | +`output.Owner.Equal(id) || tx.TokenService().SigService().IsMe(ctx, output.Owner)`) |
| 20 | +and in `MultiSigAcceptSpendView.Call` (`multisig.go:209`). |
| 21 | + |
| 22 | +## Implementation steps |
| 23 | +1. [ ] Add a membership-aware output filter to `token/stream.go`, e.g. |
| 24 | + `ByRecipientOrMember(ctx context.Context, id Identity, sigService *SignatureService) *OutputStream`, |
| 25 | + filtering on `id.Equal(t.Owner) || sigService.IsMe(ctx, t.Owner)`. |
| 26 | +2. [ ] Update `AcceptCashView.Call` (`accept.go:38`) to use the new helper instead of |
| 27 | + strict `outputs.ByRecipient(id)`. |
| 28 | +3. [ ] Update `AcceptCashView.Call` (`accept.go:43`) loop (balance sanity check) to use |
| 29 | + the same helper — today it silently iterates zero outputs for composite owners |
| 30 | + (no panic, but the balance check is skipped), which is a related correctness gap. |
| 31 | +4. [ ] Leave `AssertTokens` (`utils.go:32`) untouched — already correct; it's the |
| 32 | + reference pattern. |
| 33 | +5. [ ] Confirm no other `ByRecipient` call site (`withdraw.go`, `upgrade.go`, `swap.go`, |
| 34 | + `nft/views/accept.go`, `dvp/views/*`) needs the same fix — none of those flows use |
| 35 | + multisig/policy composite owners, so they stay on strict `ByRecipient`. |
| 36 | +6. [ ] `make checks` and `make lint-auto-fix`. |
| 37 | +7. [ ] Run/validate `dlog-fabric-t12` (Multisig, T12 label) locally or via targeted CI run |
| 38 | + across the three transport configs. |
| 39 | + |
| 40 | +## Implementation Progress |
| 41 | +- [x] Added `ByRecipientOrMember` to `token/stream.go` (membership-aware filter using `sigService.IsMe`) |
| 42 | +- [x] Updated `accept.go:38`/`:43` to use it instead of strict `ByRecipient` |
| 43 | +- [x] `make checks` and `make lint-auto-fix` clean; `go test ./token/...` passes |
| 44 | +- [x] `make integration-tests-dlog-fabric-t12` — **3 Passed | 0 Failed** across websocket, libp2p, replicas transports (previously panicked deterministically on all three) |
| 45 | + |
| 46 | +✅ COMPLETE |
| 47 | + |
| 48 | +## Notes & Decisions |
| 49 | +- Scope: this fix targets `dlog-fabric-t12` only, per explicit user request. `dlog-fabric-t14`/ |
| 50 | + `fabricx-dlog-t14` remain separately flagged as still red on PR #1953 despite `6269df950` |
| 51 | + claiming to fix them — not investigated/fixed here. |
| 52 | +- `withdraw.go`, `upgrade.go`, `swap.go`, nft/dvp accept views confirmed not multisig-related; |
| 53 | + left untouched. |
0 commit comments