|
| 1 | +package aiauditfixes2 |
| 2 | + |
| 3 | +import ( |
| 4 | + "context" |
| 5 | + "fmt" |
| 6 | + |
| 7 | + "cosmossdk.io/log" |
| 8 | + storetypes "cosmossdk.io/store/types" |
| 9 | + upgradetypes "cosmossdk.io/x/upgrade/types" |
| 10 | + |
| 11 | + sdk "github.com/cosmos/cosmos-sdk/types" |
| 12 | + "github.com/cosmos/cosmos-sdk/types/module" |
| 13 | + |
| 14 | + "github.com/pushchain/push-chain-node/app/upgrades" |
| 15 | + uexecutortypes "github.com/pushchain/push-chain-node/x/uexecutor/types" |
| 16 | + utsstypes "github.com/pushchain/push-chain-node/x/utss/types" |
| 17 | +) |
| 18 | + |
| 19 | +const UpgradeName = "ai-audit-fixes-2" |
| 20 | + |
| 21 | +func NewUpgrade() upgrades.Upgrade { |
| 22 | + return upgrades.Upgrade{ |
| 23 | + UpgradeName: UpgradeName, |
| 24 | + CreateUpgradeHandler: CreateUpgradeHandler, |
| 25 | + StoreUpgrades: storetypes.StoreUpgrades{ |
| 26 | + Added: []string{}, |
| 27 | + Deleted: []string{}, |
| 28 | + }, |
| 29 | + } |
| 30 | +} |
| 31 | + |
| 32 | +func CreateUpgradeHandler( |
| 33 | + mm upgrades.ModuleManager, |
| 34 | + configurator module.Configurator, |
| 35 | + ak *upgrades.AppKeepers, |
| 36 | +) upgradetypes.UpgradeHandler { |
| 37 | + return func(ctx context.Context, plan upgradetypes.Plan, fromVM module.VersionMap) (module.VersionMap, error) { |
| 38 | + sdkCtx := sdk.UnwrapSDKContext(ctx) |
| 39 | + logger := sdkCtx.Logger().With("upgrade", UpgradeName) |
| 40 | + logger.Info("Starting upgrade handler") |
| 41 | + |
| 42 | + // --------------------------------------------------------------- |
| 43 | + // 1. Run module migrations FIRST (consensus version bumps) |
| 44 | + // Must run before backfills so that the new proto schema |
| 45 | + // (e.g. revert_error field on UniversalTx) is applied |
| 46 | + // before we iterate existing entries. |
| 47 | + // - uexecutor: 5 → 6 (PendingOutbounds collection) |
| 48 | + // - utss: 1 → 2 (TssEvents collections) |
| 49 | + // --------------------------------------------------------------- |
| 50 | + versionMap, err := mm.RunMigrations(ctx, configurator, fromVM) |
| 51 | + if err != nil { |
| 52 | + return nil, fmt.Errorf("RunMigrations: %w", err) |
| 53 | + } |
| 54 | + |
| 55 | + // --------------------------------------------------------------- |
| 56 | + // 2. Backfill PendingOutbounds index from existing UniversalTx |
| 57 | + // (safe now — migrations have run, proto schema is current) |
| 58 | + // --------------------------------------------------------------- |
| 59 | + if err := backfillPendingOutbounds(ctx, ak, logger); err != nil { |
| 60 | + return nil, fmt.Errorf("backfillPendingOutbounds: %w", err) |
| 61 | + } |
| 62 | + |
| 63 | + // --------------------------------------------------------------- |
| 64 | + // 3. Backfill TssEvents from ProcessHistory + TssKeyHistory |
| 65 | + // --------------------------------------------------------------- |
| 66 | + if err := backfillTssEvents(ctx, ak, logger); err != nil { |
| 67 | + return nil, fmt.Errorf("backfillTssEvents: %w", err) |
| 68 | + } |
| 69 | + |
| 70 | + // --------------------------------------------------------------- |
| 71 | + // 4. Register usigverifier V2 precompile in EVM params |
| 72 | + // --------------------------------------------------------------- |
| 73 | + if err := registerPrecompileV2(sdkCtx, ak, logger); err != nil { |
| 74 | + return nil, fmt.Errorf("registerPrecompileV2: %w", err) |
| 75 | + } |
| 76 | + |
| 77 | + logger.Info("Upgrade complete", "upgrade", UpgradeName) |
| 78 | + return versionMap, nil |
| 79 | + } |
| 80 | +} |
| 81 | + |
| 82 | +// backfillPendingOutbounds iterates all UniversalTx entries and creates a |
| 83 | +// PendingOutboundEntry for every outbound that is still in PENDING status. |
| 84 | +func backfillPendingOutbounds(ctx context.Context, ak *upgrades.AppKeepers, logger log.Logger) error { |
| 85 | + keeper := ak.UExecutorKeeper |
| 86 | + logger.Info("Backfilling PendingOutbounds index") |
| 87 | + |
| 88 | + count := 0 |
| 89 | + iter, err := keeper.UniversalTx.Iterate(ctx, nil) |
| 90 | + if err != nil { |
| 91 | + return fmt.Errorf("failed to create UniversalTx iterator: %w", err) |
| 92 | + } |
| 93 | + defer iter.Close() |
| 94 | + |
| 95 | + for ; iter.Valid(); iter.Next() { |
| 96 | + kv, err := iter.KeyValue() |
| 97 | + if err != nil { |
| 98 | + return fmt.Errorf("failed to read UniversalTx entry: %w", err) |
| 99 | + } |
| 100 | + |
| 101 | + utxId := kv.Key |
| 102 | + utx := kv.Value |
| 103 | + |
| 104 | + for _, ob := range utx.OutboundTx { |
| 105 | + if ob == nil { |
| 106 | + continue |
| 107 | + } |
| 108 | + if ob.OutboundStatus == uexecutortypes.Status_PENDING { |
| 109 | + entry := uexecutortypes.PendingOutboundEntry{ |
| 110 | + OutboundId: ob.Id, |
| 111 | + UniversalTxId: utxId, |
| 112 | + CreatedAt: 0, // unknown historical height |
| 113 | + } |
| 114 | + if err := keeper.PendingOutbounds.Set(ctx, ob.Id, entry); err != nil { |
| 115 | + return fmt.Errorf("failed to set pending outbound %s: %w", ob.Id, err) |
| 116 | + } |
| 117 | + count++ |
| 118 | + } |
| 119 | + } |
| 120 | + } |
| 121 | + |
| 122 | + logger.Info("PendingOutbounds backfill complete", "total_indexed", count) |
| 123 | + return nil |
| 124 | +} |
| 125 | + |
| 126 | +// backfillTssEvents creates TssEvent entries from ProcessHistory and TssKeyHistory. |
| 127 | +// Skips if events already exist (re-run guard). |
| 128 | +func backfillTssEvents(ctx context.Context, ak *upgrades.AppKeepers, logger log.Logger) error { |
| 129 | + utssKeeper := ak.UTssKeeper |
| 130 | + logger.Info("Backfilling TssEvents") |
| 131 | + |
| 132 | + // Guard: skip if events already exist |
| 133 | + hasEvents := false |
| 134 | + _ = utssKeeper.TssEvents.Walk(ctx, nil, func(id uint64, event utsstypes.TssEvent) (bool, error) { |
| 135 | + hasEvents = true |
| 136 | + return true, nil |
| 137 | + }) |
| 138 | + if hasEvents { |
| 139 | + logger.Info("TssEvents already exist, skipping backfill") |
| 140 | + return nil |
| 141 | + } |
| 142 | + |
| 143 | + // Backfill from ProcessHistory |
| 144 | + err := utssKeeper.ProcessHistory.Walk(ctx, nil, func(processId uint64, process utsstypes.TssKeyProcess) (bool, error) { |
| 145 | + eventId, err := utssKeeper.NextTssEventId.Next(ctx) |
| 146 | + if err != nil { |
| 147 | + return true, fmt.Errorf("failed to generate tss event id: %w", err) |
| 148 | + } |
| 149 | + |
| 150 | + var status utsstypes.TssEventStatus |
| 151 | + switch process.Status { |
| 152 | + case utsstypes.TssKeyProcessStatus_TSS_KEY_PROCESS_PENDING: |
| 153 | + status = utsstypes.TssEventStatus_TSS_EVENT_ACTIVE |
| 154 | + case utsstypes.TssKeyProcessStatus_TSS_KEY_PROCESS_SUCCESS: |
| 155 | + status = utsstypes.TssEventStatus_TSS_EVENT_COMPLETED |
| 156 | + case utsstypes.TssKeyProcessStatus_TSS_KEY_PROCESS_FAILED: |
| 157 | + status = utsstypes.TssEventStatus_TSS_EVENT_EXPIRED |
| 158 | + default: |
| 159 | + status = utsstypes.TssEventStatus_TSS_EVENT_ACTIVE |
| 160 | + } |
| 161 | + |
| 162 | + tssEvent := utsstypes.TssEvent{ |
| 163 | + Id: eventId, |
| 164 | + EventType: utsstypes.TssEventType_TSS_EVENT_PROCESS_INITIATED, |
| 165 | + Status: status, |
| 166 | + ProcessId: process.Id, |
| 167 | + ProcessType: process.ProcessType.String(), |
| 168 | + Participants: process.Participants, |
| 169 | + ExpiryHeight: process.ExpiryHeight, |
| 170 | + BlockHeight: process.BlockHeight, |
| 171 | + } |
| 172 | + |
| 173 | + if err := utssKeeper.TssEvents.Set(ctx, eventId, tssEvent); err != nil { |
| 174 | + return true, fmt.Errorf("failed to store tss event: %w", err) |
| 175 | + } |
| 176 | + return false, nil |
| 177 | + }) |
| 178 | + if err != nil { |
| 179 | + return fmt.Errorf("failed to backfill process history events: %w", err) |
| 180 | + } |
| 181 | + |
| 182 | + // Backfill from TssKeyHistory |
| 183 | + var latestFinalizedEventId uint64 |
| 184 | + var latestFinalizedBlockHeight int64 |
| 185 | + hasFinalized := false |
| 186 | + |
| 187 | + err = utssKeeper.TssKeyHistory.Walk(ctx, nil, func(keyId string, key utsstypes.TssKey) (bool, error) { |
| 188 | + eventId, err := utssKeeper.NextTssEventId.Next(ctx) |
| 189 | + if err != nil { |
| 190 | + return true, fmt.Errorf("failed to generate tss event id: %w", err) |
| 191 | + } |
| 192 | + |
| 193 | + tssEvent := utsstypes.TssEvent{ |
| 194 | + Id: eventId, |
| 195 | + EventType: utsstypes.TssEventType_TSS_EVENT_KEY_FINALIZED, |
| 196 | + Status: utsstypes.TssEventStatus_TSS_EVENT_COMPLETED, |
| 197 | + ProcessId: key.ProcessId, |
| 198 | + Participants: key.Participants, |
| 199 | + KeyId: key.KeyId, |
| 200 | + TssPubkey: key.TssPubkey, |
| 201 | + BlockHeight: key.FinalizedBlockHeight, |
| 202 | + } |
| 203 | + |
| 204 | + if err := utssKeeper.TssEvents.Set(ctx, eventId, tssEvent); err != nil { |
| 205 | + return true, fmt.Errorf("failed to store tss key finalized event: %w", err) |
| 206 | + } |
| 207 | + |
| 208 | + if key.FinalizedBlockHeight >= latestFinalizedBlockHeight { |
| 209 | + latestFinalizedBlockHeight = key.FinalizedBlockHeight |
| 210 | + latestFinalizedEventId = eventId |
| 211 | + hasFinalized = true |
| 212 | + } |
| 213 | + return false, nil |
| 214 | + }) |
| 215 | + if err != nil { |
| 216 | + return fmt.Errorf("failed to backfill tss key history events: %w", err) |
| 217 | + } |
| 218 | + |
| 219 | + // Mark the latest finalized key event as ACTIVE |
| 220 | + if hasFinalized { |
| 221 | + latestEvent, err := utssKeeper.TssEvents.Get(ctx, latestFinalizedEventId) |
| 222 | + if err != nil { |
| 223 | + return fmt.Errorf("failed to get latest finalized event: %w", err) |
| 224 | + } |
| 225 | + latestEvent.Status = utsstypes.TssEventStatus_TSS_EVENT_ACTIVE |
| 226 | + if err := utssKeeper.TssEvents.Set(ctx, latestFinalizedEventId, latestEvent); err != nil { |
| 227 | + return fmt.Errorf("failed to update latest finalized event status: %w", err) |
| 228 | + } |
| 229 | + } |
| 230 | + |
| 231 | + logger.Info("TssEvents backfill complete") |
| 232 | + return nil |
| 233 | +} |
| 234 | + |
| 235 | +// registerPrecompileV2 adds the usigverifier V2 address to EVM ActiveStaticPrecompiles |
| 236 | +// so the EVM recognizes it as a callable precompile. |
| 237 | +func registerPrecompileV2(sdkCtx sdk.Context, ak *upgrades.AppKeepers, logger log.Logger) error { |
| 238 | + const usigVerifierV2Addr = "0xEC00000000000000000000000000000000000001" |
| 239 | + |
| 240 | + evmParams := ak.EVMKeeper.GetParams(sdkCtx) |
| 241 | + |
| 242 | + // Check if already registered |
| 243 | + for _, addr := range evmParams.ActiveStaticPrecompiles { |
| 244 | + if addr == usigVerifierV2Addr { |
| 245 | + logger.Info("usigverifier V2 precompile already registered in EVM params") |
| 246 | + return nil |
| 247 | + } |
| 248 | + } |
| 249 | + |
| 250 | + evmParams.ActiveStaticPrecompiles = append(evmParams.ActiveStaticPrecompiles, usigVerifierV2Addr) |
| 251 | + |
| 252 | + if err := ak.EVMKeeper.SetParams(sdkCtx, evmParams); err != nil { |
| 253 | + return fmt.Errorf("failed to set EVM params with new precompile: %w", err) |
| 254 | + } |
| 255 | + |
| 256 | + logger.Info("Registered usigverifier V2 precompile in EVM params", "address", usigVerifierV2Addr) |
| 257 | + return nil |
| 258 | +} |
0 commit comments