FIP: Ungate Message Variants from Farcaster Pro Subscriptions #273
CassOnMars
started this conversation in
FIP Stage 1: Ideas
Replies: 1 comment
|
Yes yes yes I like it |
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
FIP: Ungate Message Variants from Farcaster Pro Subscriptions
Overview
Remove the protocol-level gates that condition specific
CastAddandUserDataAddmessage variants on an active Farcaster Pro tier subscription. After this FIP, the following message variants are accepted from any FID with sufficient storage, regardless of subscription state:CastType::TenKCast(the 10,000-byte cast variant)UserDataType::Banner(profile banner field)CastAddBody.embedsMAX_DATA_BYTES_FOR_10K_CAST(16 KiB) per-message size ceiling, applied to anyCastAddregardless of subscription stateThe Pro subscription itself, its on-chain tier-purchase event, and its surfaced tier metadata on user/profile endpoints all remain intact — the change is strictly to remove subscription as a consensus-level admission gate on specific message variants. Subscription becomes a client-side / application-level signal rather than a protocol-level capability.
1. Motivation
The current rules treat a small set of message variants as paywall-gated capabilities. A node validating a block at height N checks the proposer's claim that the sender has an active Pro subscription at
block_timestampand rejects the message if not. The subscription fees accrue to a single entity, and does not provide economic security or benefit to the protocol or other clients – indeed, other clients using only snapchain have to require users pay an entirely separate company to use these features.2. Current Gates Being Removed
To reduce scope, the minimal changeset is suggested:
CastType::TenKCastProUserFeaturewhenis_pro_user == false.MAX_DATA_BYTES_FOR_10K_CASTsize ceiling and the sametext_bytes.len() ∈ (1024, 10_000]range.UserDataType::BannerProUserFeaturewhenis_pro_user == false.CastAddBody.embedscountis_pro_user == true, 2 max otherwise.validate_messagedata-size selectorMAX_DATA_BYTES_FOR_10K_CAST(16 KiB) only whenis_pro_user && type == CastAdd.MAX_DATA_BYTES_FOR_10K_CASTapplied to everyCastAdd, regardless of subscription.validate_message/validate_cast_add_body/validate_user_data_add_bodyis_pro_user: boolparameterStores::is_pro_user(fid, timestamp).Stores::is_pro_userEventTypeTierPurchase)ProtocolFeature::FarcasterPro.What is not removed:
proto::TierType::Proand the rest of the tier type enumeration.EventTypeTierPurchase.OnchainEventStore::tier_subscription_expires_at/is_tier_subscription_active_at.(fid, tier_type, expires_at)to clients.ProtocolFeature::FarcasterProengine-version gate. Activation is by a new feature flag, not by repealing the existing one.3. Activation and Compatibility
3.1 New protocol feature
Introduce a new
ProtocolFeature::UngateMessageVariantsactivated at a coordinatedEngineVersionboundary. The pattern mirrors prior consensus-affecting upgrades:UNGATE_MIN_VERSIONis the next freeEngineVersion.3.2 Gate behaviour pre/post activation
Each validator computes the effective
is_pro_uservalue at the block'sEngineVersion:This shape preserves byte-identical replay of historical blocks (pre-activation messages still validate the way they originally did) while producing a single uniform admission policy after activation. The
validate_cast_add_bodyandvalidate_user_data_add_bodyfunctions are not re-shaped to drop the parameter until a second cleanup pass several versions later, when the historical-replay window is well behind us.3.3 Replay safety
StorageSlot-style retroactive recomputation does not apply here: cast and user-data validity is checked at admission and the result is reflected in trie state. Once a message is in the trie, no future validation pass re-checks it. The only consensus-visible effect of activation is that new admissions stop being filtered by the gate.This means:
3.4 Client compatibility
Clients today read:
UserDataAdd(Banner)field to render banners. The field is identical post-FIP — only the admission gate is removed. Existing clients continue to work; new clients can render banners for any FID rather than only Pro subscribers.CastAdd(TenKCast)text via the cast endpoints. Identical post-FIP — only the admission gate is removed.3.5 Indexer / external store compatibility
External indexers (Neynar and other client backends, Snapchain replicas, Hypersnap, GraphQL gateways) follow the same path: tier metadata stays surfaced; admission semantics relax. Indexers do not need to re-process historical blocks — pre-activation rejections were never recorded, so there is nothing to backfill.
4. Migration Strategy
4.1 Pre-activation (current state)
Both
is_pro_user_effective = stores.is_pro_user(...)and the rejection paths run as today. Operators run the upgraded binary in a no-op mode keyed off the engine version.4.2 Activation timestamp
At the
EngineVersion::Vnboundary, the validation paths flip:validate_cast_add_body: passis_pro_user = trueunconditionallyvalidate_user_data_add_body: passis_pro_user = trueunconditionallyvalidate_message's data-size selector: drop the&& is_pro_userqualifier from theCastAddarm4.3 Post-activation cleanup (deferrable, optional)
In a follow-up release once the historical replay window has comfortably moved past activation:
is_pro_user: boolparameter fromvalidate_message,validate_cast_add_body,validate_user_data_add_body.Stores::is_pro_user(...)lookup from the engine's per-message preamble.ValidationError::ProUserFeaturevariant.These are pure refactors — no consensus change, no engine-version gate needed — and can ship at any tagged release whose activation timestamp lies beyond the network's earliest-known peer's chain start.
5. Code Changes Required
src/version/version.rsUngateMessageVariantstoProtocolFeature; addis_enabledarm; addVnschedule entries per network; bumpLATEST_PROTOCOL_VERSION.src/storage/store/engine.rsis_pro_userlookup site that feedsvalidate_message, replace the lookup with the engine-version-conditional expression in §3.2.src/storage/store/block_engine.rssrc/core/validations/message.rssrc/core/validations/cast.rsConcrete diff at the engine call site
A symmetric change lands at the
block_engine.rssite.6. Testing Plan
6.1 Unit tests
Each existing test that asserts
ValidationError::ProUserFeatureis rejection-positive must be split into:EngineVersion < Vn): still rejects withProUserFeature.EngineVersion >= Vn): accepts.This includes:
validate_cast_add_bodywithCastType::TenKCastandis_pro_user = false.validate_user_data_add_bodywithUserDataType::Bannerandis_pro_user = false.MAX_DATA_BYTES_FOR_10K_CASTsize-selector test.6.2 Engine integration tests
TenKCastat a block timestamp just before activation: rejected. The same FID emits the same message at the next block-cadence boundary, with activation in effect: accepted.UserDataAdd(Banner)across the activation boundary: same pattern.6.3 Block-replay determinism
A node started cold against a chain that crosses the activation boundary must produce byte-identical trie roots at every height as a node that has been running across the activation. This is the standard replay guarantee for any version-gated change.
6.4 Stress / capacity
MAX_DATA_BYTES_FOR_10K_CASTis 16 KiB. Once it applies to every FID'sCastAdd, a network with N% of FIDs emitting 10k-character casts increases per-block average byte size byN% * (16 KiB - 2 KiB). The block-time and mempool sizing analysis is the same as inFIP: 3-Second Block Time— no new headroom is needed at the current cap, but operators should watch sustained block-size distributions in the weeks after activation.7. Out of Scope (Explicitly)
This FIP does not:
ProtocolFeature::FarcasterPro(which gates event ingestion; this FIP only ungates message variants).If a future FIP proposes removing the Pro tier or restructuring tier semantics, this FIP is a strict prerequisite: tier semantics cannot be cleanly restructured while consensus admission depends on tier state.
8. Summary
CastType::TenKCastadmissionUserDataType::BanneradmissionCastAddBody.embedscapCastAdddata-size capis_pro_userconsulted on admissionThe protocol stops carrying the gate. The subscription stays.
All reactions