Skip to content
Open
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
1,181 changes: 430 additions & 751 deletions pkg/api/core/v1/types.pb.go

Large diffs are not rendered by default.

69 changes: 0 additions & 69 deletions pkg/common/legacy_reward_signing.go

This file was deleted.

6 changes: 0 additions & 6 deletions pkg/core/db/models.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

24 changes: 0 additions & 24 deletions pkg/core/db/reads.sql.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

21 changes: 21 additions & 0 deletions pkg/core/db/sql/migrations/00039_drop_launchpad_authority_rm.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
-- +migrate Up
-- launchpad_authority_rm (00034) mapped launchpad-derived per-mint claim
-- authorities to their Solana reward manager pubkeys. It had two readers: the
-- 00034 backfill, which resolved each pre-pool core_rewards row to a real RM,
-- and finalizeLegacyCreateReward, which replayed audius-mainnet-alpha-beta's
-- pre-pool reward bytes into pools at block-sync time.
--
-- Both are gone. The backfill ran once, and audius-mainnet-beta was written by
-- genesis-writer from table state, so it carries only the pool-shaped reward
-- transactions and the wire-compat layer has been removed.
drop table if exists launchpad_authority_rm;

-- +migrate Down
-- The 72 rows are not restored: the only consumer that could read them no
-- longer exists in any binary that runs this schema. Recreate the table empty
-- so 00034's Down still finds it.
create table if not exists launchpad_authority_rm (
authority text primary key,
rewards_manager_pubkey text not null,
created_at timestamp with time zone default now()
);
16 changes: 0 additions & 16 deletions pkg/core/db/sql/reads.sql
Original file line number Diff line number Diff line change
Expand Up @@ -664,22 +664,6 @@ from core_reward_pools
where authorities @> array[$1::text]
order by rewards_manager_pubkey;

-- name: GetLaunchpadRMByAuthority :one
-- Resolves a launchpad-derived per-mint claim authority (lowercased eth
-- hex) to the Solana reward manager state account that mint's rewards
-- live under. Used by the wire-compat layer at block-sync replay time:
-- when finalizeLegacyCreateReward sees an inline claim_authorities
-- array, it looks up the RM from any one of its lowercased entries and
-- routes the reward into a pool keyed by that RM — matching exactly
-- what the migration backfill produced for pre-migration rows.
-- Returns ErrNoRows if none of the requested authorities is in the
-- launchpad mapping (e.g., AUDIO rewards or test fixtures).
select rewards_manager_pubkey
from launchpad_authority_rm
where authority = any($1::text[])
order by rewards_manager_pubkey, authority
limit 1;

-- name: GetCoreUpload :one
select * from core_uploads where cid = $1 OR transcoded_cid = $1;

Expand Down
62 changes: 12 additions & 50 deletions pkg/core/server/rewards.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,30 +94,7 @@ var (

func (s *Server) isValidRewardTransaction(ctx context.Context, signedTx *corev1.SignedTransaction, blockHeight int64) error {
envelope := signedTx.GetReward()
if envelope == nil {
return fmt.Errorf("%w: reward message is nil", ErrRewardMessageValidation)
}
if envelope.Body == nil {
// Legacy wire-format detected (pre-pool-rollout shape with deadline +
// signature embedded in CreateReward / DeleteReward at tags 1000/1001).
//
// We REJECT legacy here — at CheckTx and ProcessProposal — because
// legacy CreateReward is inherently permissionless: it carries no
// pool_address and the old signing scheme had no membership check on
// claim_authorities. Allowing live legacy txs through validation would
// reopen the exact exploit class this PR is closing (an attacker
// crafts legacy bytes, picks any reward_id / amount / claim_authorities,
// and bypasses the pool gate).
//
// The corresponding code path in finalizeRewards still APPLIES legacy
// txs — that's intentional, for block-sync-from-genesis replay of
// already-committed historical blocks. Block sync only invokes
// FinalizeBlock; it does not re-run CheckTx or ProcessProposal. So
// "reject at validate, accept at finalize" gives us correct historical
// replay without admitting any new legacy traffic.
if legacy, err := tryParseLegacyReward(envelope); err == nil && legacy != nil {
return fmt.Errorf("%w: legacy reward wire format is not accepted for new transactions; clients must use the body+signature envelope", ErrRewardMessageValidation)
}
if envelope == nil || envelope.Body == nil {
return fmt.Errorf("%w: reward message body is nil", ErrRewardMessageValidation)
}

Expand All @@ -143,10 +120,6 @@ func (s *Server) validateCreateReward(ctx context.Context, createReward *corev1.
// could issue rewards under any other pool's RM and inherit its
// attestation rights — which is exactly what the per-RM
// sender-attestation gate is designed to prevent.
//
// The legacy permissionless path (inline claim_authorities, no RM) is
// preserved only for historical replay via the wire-compat layer; new
// live txs must specify rewards_manager_pubkey.
if err := validateRewardsManagerPubkey(createReward.RewardsManagerPubkey); err != nil {
return err
}
Expand Down Expand Up @@ -194,19 +167,8 @@ func (s *Server) finalizeRewardTransaction(ctx context.Context, req *abcitypes.F
}

func (s *Server) finalizeRewards(ctx context.Context, req *abcitypes.FinalizeBlockRequest, txhash string, messageIndex int64, envelope *corev1.RewardMessage, sender string) error {
if envelope == nil {
return fmt.Errorf("tx: %s, message index: %d, reward message not found", txhash, messageIndex)
}
if envelope.Body == nil {
// Legacy wire-format path; see rewards_legacy.go.
legacy, err := tryParseLegacyReward(envelope)
if err != nil {
return errors.Join(ErrRewardMessageFinalization, err)
}
if legacy == nil {
return fmt.Errorf("tx: %s, message index: %d, reward message body not found", txhash, messageIndex)
}
return s.finalizeLegacyRewardTransaction(ctx, req, legacy, txhash, messageIndex)
if envelope == nil || envelope.Body == nil {
return fmt.Errorf("tx: %s, message index: %d, reward message body not found", txhash, messageIndex)
}

signer, err := s.recoverDeadlinedSigner(req.Height, envelope.Body.DeadlineBlockHeight, envelope.Body, envelope.Signature)
Expand Down Expand Up @@ -253,16 +215,16 @@ func (s *Server) finalizeCreateReward(ctx context.Context, req *abcitypes.Finali
}

if err := qtx.InsertCoreReward(ctx, db.InsertCoreRewardParams{
TxHash: txhash,
Index: messageIndex,
Address: rewardAddress,
Sender: signer,
RewardID: createReward.RewardId,
Name: createReward.Name,
Amount: int64(createReward.Amount),
TxHash: txhash,
Index: messageIndex,
Address: rewardAddress,
Sender: signer,
RewardID: createReward.RewardId,
Name: createReward.Name,
Amount: int64(createReward.Amount),
RewardsManagerPubkey: pgtype.Text{String: createReward.RewardsManagerPubkey, Valid: true},
RawMessage: rawMessage,
BlockHeight: req.Height,
RawMessage: rawMessage,
BlockHeight: req.Height,
}); err != nil {
return fmt.Errorf("failed to insert reward: %w", err)
}
Expand Down
Loading