code.vegaprotocol.io/vega@v0.79.0/core/banking/snapshot.go (about) 1 // Copyright (C) 2023 Gobalsky Labs Limited 2 // 3 // This program is free software: you can redistribute it and/or modify 4 // it under the terms of the GNU Affero General Public License as 5 // published by the Free Software Foundation, either version 3 of the 6 // License, or (at your option) any later version. 7 // 8 // This program is distributed in the hope that it will be useful, 9 // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 // GNU Affero General Public License for more details. 12 // 13 // You should have received a copy of the GNU Affero General Public License 14 // along with this program. If not, see <http://www.gnu.org/licenses/>. 15 16 package banking 17 18 import ( 19 "context" 20 "fmt" 21 "math/big" 22 "sort" 23 "time" 24 25 "code.vegaprotocol.io/vega/core/types" 26 vgcontext "code.vegaprotocol.io/vega/libs/context" 27 "code.vegaprotocol.io/vega/libs/num" 28 "code.vegaprotocol.io/vega/libs/proto" 29 "code.vegaprotocol.io/vega/logging" 30 checkpoint "code.vegaprotocol.io/vega/protos/vega/checkpoint/v1" 31 snapshot "code.vegaprotocol.io/vega/protos/vega/snapshot/v1" 32 33 "github.com/emirpasic/gods/sets/treeset" 34 ) 35 36 var ( 37 withdrawalsKey = (&types.PayloadBankingWithdrawals{}).Key() 38 depositsKey = (&types.PayloadBankingDeposits{}).Key() 39 seenKey = (&types.PayloadBankingSeen{}).Key() 40 assetActionsKey = (&types.PayloadBankingAssetActions{}).Key() 41 recurringTransfersKey = (&types.PayloadBankingRecurringTransfers{}).Key() 42 scheduledTransfersKey = (&types.PayloadBankingScheduledTransfers{}).Key() 43 primaryBridgeStateKey = (&types.PayloadBankingPrimaryBridgeState{}).Key() 44 secondaryBridgeStateKey = (&types.PayloadBankingEVMBridgeStates{}).Key() 45 recurringGovTransfersKey = (&types.PayloadBankingRecurringGovernanceTransfers{}).Key() 46 scheduledGovTransfersKey = (&types.PayloadBankingScheduledGovernanceTransfers{}).Key() 47 transferFeeDiscountsKey = (&types.PayloadBankingTransferFeeDiscounts{}).Key() 48 49 hashKeys = []string{ 50 withdrawalsKey, 51 depositsKey, 52 seenKey, 53 assetActionsKey, 54 recurringTransfersKey, 55 scheduledTransfersKey, 56 primaryBridgeStateKey, 57 secondaryBridgeStateKey, 58 recurringGovTransfersKey, 59 scheduledGovTransfersKey, 60 transferFeeDiscountsKey, 61 } 62 ) 63 64 type bankingSnapshotState struct { 65 serialisedWithdrawals []byte 66 serialisedDeposits []byte 67 serialisedSeen []byte 68 serialisedAssetActions []byte 69 serialisedRecurringTransfers []byte 70 serialisedScheduledTransfers []byte 71 serialisedPrimaryBridgeState []byte 72 serialisedSecondaryBridgeState []byte 73 serialisedGovRecurringTransfers []byte 74 serialisedGovScheduledTransfers []byte 75 serialisedTransferFeeDiscounts []byte 76 } 77 78 func (e *Engine) Namespace() types.SnapshotNamespace { 79 return types.BankingSnapshot 80 } 81 82 func (e *Engine) Keys() []string { 83 return hashKeys 84 } 85 86 func (e *Engine) Stopped() bool { 87 return false 88 } 89 90 func (e *Engine) serialisePrimaryBridgeState() ([]byte, error) { 91 payload := types.Payload{ 92 Data: &types.PayloadBankingPrimaryBridgeState{ 93 BankingBridgeState: &types.BankingBridgeState{ 94 Active: e.primaryBridgeState.active, 95 BlockHeight: e.primaryBridgeState.block, 96 LogIndex: e.primaryBridgeState.logIndex, 97 ChainID: e.primaryEthChainID, 98 }, 99 }, 100 } 101 return proto.Marshal(payload.IntoProto()) 102 } 103 104 func (e *Engine) serialiseSecondaryBridgeState() ([]byte, error) { 105 payload := types.Payload{ 106 Data: &types.PayloadBankingEVMBridgeStates{ 107 // we only have one bridge state atm, its easy 108 BankingBridgeStates: []*checkpoint.BridgeState{ 109 { 110 Active: e.secondaryBridgeState.active, 111 BlockHeight: e.secondaryBridgeState.block, 112 LogIndex: e.secondaryBridgeState.logIndex, 113 ChainId: e.secondaryEthChainID, 114 }, 115 }, 116 }, 117 } 118 return proto.Marshal(payload.IntoProto()) 119 } 120 121 func (e *Engine) serialiseRecurringTransfers() ([]byte, error) { 122 payload := types.Payload{ 123 Data: &types.PayloadBankingRecurringTransfers{ 124 BankingRecurringTransfers: e.getRecurringTransfers(), 125 NextMetricUpdate: e.nextMetricUpdate, 126 }, 127 } 128 129 return proto.Marshal(payload.IntoProto()) 130 } 131 132 func (e *Engine) serialiseScheduledTransfers() ([]byte, error) { 133 payload := types.Payload{ 134 Data: &types.PayloadBankingScheduledTransfers{ 135 BankingScheduledTransfers: e.getScheduledTransfers(), 136 }, 137 } 138 139 return proto.Marshal(payload.IntoProto()) 140 } 141 142 func (e *Engine) serialiseRecurringGovernanceTransfers() ([]byte, error) { 143 payload := types.Payload{ 144 Data: &types.PayloadBankingRecurringGovernanceTransfers{ 145 BankingRecurringGovernanceTransfers: e.getRecurringGovernanceTransfers(), 146 }, 147 } 148 149 return proto.Marshal(payload.IntoProto()) 150 } 151 152 func (e *Engine) serialiseScheduledGovernanceTransfers() ([]byte, error) { 153 payload := types.Payload{ 154 Data: &types.PayloadBankingScheduledGovernanceTransfers{ 155 BankingScheduledGovernanceTransfers: e.getScheduledGovernanceTransfers(), 156 }, 157 } 158 159 return proto.Marshal(payload.IntoProto()) 160 } 161 162 func (e *Engine) serialisedTransferFeeDiscounts() ([]byte, error) { 163 partyAssetDiscounts := make([]*snapshot.PartyAssetAmount, 0, len(e.feeDiscountPerPartyAndAsset)) 164 165 for k, v := range e.feeDiscountPerPartyAndAsset { 166 partyAssetDiscounts = append(partyAssetDiscounts, &snapshot.PartyAssetAmount{ 167 Party: k.party, 168 Asset: k.asset, 169 Amount: v.String(), 170 }) 171 } 172 sort.SliceStable(partyAssetDiscounts, func(i, j int) bool { 173 if partyAssetDiscounts[i].Party == partyAssetDiscounts[j].Party { 174 return partyAssetDiscounts[i].Asset < partyAssetDiscounts[j].Asset 175 } 176 return partyAssetDiscounts[i].Party < partyAssetDiscounts[j].Party 177 }) 178 179 payload := types.Payload{ 180 Data: &types.PayloadBankingTransferFeeDiscounts{ 181 BankingTransferFeeDiscounts: &snapshot.BankingTransferFeeDiscounts{ 182 PartyAssetDiscount: partyAssetDiscounts, 183 }, 184 }, 185 } 186 187 return proto.Marshal(payload.IntoProto()) 188 } 189 190 func (e *Engine) serialiseAssetActions() ([]byte, error) { 191 payload := types.Payload{ 192 Data: &types.PayloadBankingAssetActions{ 193 BankingAssetActions: &types.BankingAssetActions{ 194 AssetAction: e.getAssetActions(), 195 }, 196 }, 197 } 198 return proto.Marshal(payload.IntoProto()) 199 } 200 201 func (e *Engine) serialiseWithdrawals() ([]byte, error) { 202 withdrawals := make([]*types.RWithdrawal, 0, len(e.withdrawals)) 203 for _, v := range e.withdrawals { 204 withdrawals = append(withdrawals, &types.RWithdrawal{Ref: v.ref.String(), Withdrawal: v.w}) 205 } 206 207 sort.SliceStable(withdrawals, func(i, j int) bool { return withdrawals[i].Ref < withdrawals[j].Ref }) 208 209 payload := types.Payload{ 210 Data: &types.PayloadBankingWithdrawals{ 211 BankingWithdrawals: &types.BankingWithdrawals{ 212 Withdrawals: withdrawals, 213 }, 214 }, 215 } 216 return proto.Marshal(payload.IntoProto()) 217 } 218 219 func (e *Engine) serialiseSeen() ([]byte, error) { 220 seen := &types.PayloadBankingSeen{ 221 BankingSeen: &types.BankingSeen{ 222 LastSeenPrimaryEthBlock: e.lastSeenPrimaryEthBlock, 223 LastSeenSecondaryEthBlock: e.lastSeenSecondaryEthBlock, 224 }, 225 } 226 seen.BankingSeen.Refs = make([]string, 0, e.seenAssetActions.Size()) 227 iter := e.seenAssetActions.Iterator() 228 for iter.Next() { 229 seen.BankingSeen.Refs = append(seen.BankingSeen.Refs, iter.Value().(string)) 230 } 231 payload := types.Payload{Data: seen} 232 return proto.Marshal(payload.IntoProto()) 233 } 234 235 func (e *Engine) serialiseDeposits() ([]byte, error) { 236 e.log.Debug("serialiseDeposits: called") 237 deposits := make([]*types.BDeposit, 0, len(e.deposits)) 238 for _, v := range e.deposits { 239 deposits = append(deposits, &types.BDeposit{ID: v.ID, Deposit: v}) 240 } 241 242 sort.SliceStable(deposits, func(i, j int) bool { return deposits[i].ID < deposits[j].ID }) 243 244 if e.log.IsDebug() { 245 e.log.Info("serialiseDeposits: number of deposits:", logging.Int("len(deposits)", len(deposits))) 246 for i, d := range deposits { 247 e.log.Info("serialiseDeposits:", logging.Int("index", i), logging.String("ID", d.ID), logging.String("deposit", d.Deposit.String())) 248 } 249 } 250 payload := types.Payload{ 251 Data: &types.PayloadBankingDeposits{ 252 BankingDeposits: &types.BankingDeposits{ 253 Deposit: deposits, 254 }, 255 }, 256 } 257 258 return proto.Marshal(payload.IntoProto()) 259 } 260 261 func (e *Engine) serialiseK(serialFunc func() ([]byte, error), dataField *[]byte) ([]byte, error) { 262 data, err := serialFunc() 263 if err != nil { 264 return nil, err 265 } 266 *dataField = data 267 return data, nil 268 } 269 270 // get the serialised form and hash of the given key. 271 func (e *Engine) serialise(k string) ([]byte, error) { 272 switch k { 273 case depositsKey: 274 return e.serialiseK(e.serialiseDeposits, &e.bss.serialisedDeposits) 275 case withdrawalsKey: 276 return e.serialiseK(e.serialiseWithdrawals, &e.bss.serialisedWithdrawals) 277 case seenKey: 278 return e.serialiseK(e.serialiseSeen, &e.bss.serialisedSeen) 279 case assetActionsKey: 280 return e.serialiseK(e.serialiseAssetActions, &e.bss.serialisedAssetActions) 281 case recurringTransfersKey: 282 return e.serialiseK(e.serialiseRecurringTransfers, &e.bss.serialisedRecurringTransfers) 283 case scheduledTransfersKey: 284 return e.serialiseK(e.serialiseScheduledTransfers, &e.bss.serialisedScheduledTransfers) 285 case recurringGovTransfersKey: 286 return e.serialiseK(e.serialiseRecurringGovernanceTransfers, &e.bss.serialisedGovRecurringTransfers) 287 case scheduledGovTransfersKey: 288 return e.serialiseK(e.serialiseScheduledGovernanceTransfers, &e.bss.serialisedGovScheduledTransfers) 289 case transferFeeDiscountsKey: 290 return e.serialiseK(e.serialisedTransferFeeDiscounts, &e.bss.serialisedTransferFeeDiscounts) 291 case primaryBridgeStateKey: 292 return e.serialiseK(e.serialisePrimaryBridgeState, &e.bss.serialisedPrimaryBridgeState) 293 case secondaryBridgeStateKey: 294 return e.serialiseK(e.serialiseSecondaryBridgeState, &e.bss.serialisedSecondaryBridgeState) 295 default: 296 return nil, types.ErrSnapshotKeyDoesNotExist 297 } 298 } 299 300 func (e *Engine) GetState(k string) ([]byte, []types.StateProvider, error) { 301 state, err := e.serialise(k) 302 return state, nil, err 303 } 304 305 func (e *Engine) LoadState(ctx context.Context, p *types.Payload) ([]types.StateProvider, error) { 306 if e.Namespace() != p.Data.Namespace() { 307 return nil, types.ErrInvalidSnapshotNamespace 308 } 309 // see what we're reloading 310 switch pl := p.Data.(type) { 311 case *types.PayloadBankingDeposits: 312 return nil, e.restoreDeposits(pl.BankingDeposits, p) 313 case *types.PayloadBankingWithdrawals: 314 return nil, e.restoreWithdrawals(pl.BankingWithdrawals, p) 315 case *types.PayloadBankingSeen: 316 return nil, e.restoreSeen(ctx, pl.BankingSeen, p) 317 case *types.PayloadBankingAssetActions: 318 return nil, e.restoreAssetActions(pl.BankingAssetActions, p) 319 case *types.PayloadBankingRecurringTransfers: 320 return nil, e.restoreRecurringTransfers(ctx, pl.BankingRecurringTransfers, pl.NextMetricUpdate, p) 321 case *types.PayloadBankingScheduledTransfers: 322 return nil, e.restoreScheduledTransfers(ctx, pl.BankingScheduledTransfers, p) 323 case *types.PayloadBankingRecurringGovernanceTransfers: 324 return nil, e.restoreRecurringGovernanceTransfers(ctx, pl.BankingRecurringGovernanceTransfers, p) 325 case *types.PayloadBankingScheduledGovernanceTransfers: 326 return nil, e.restoreScheduledGovernanceTransfers(ctx, pl.BankingScheduledGovernanceTransfers, p) 327 case *types.PayloadBankingPrimaryBridgeState: 328 return nil, e.restorePrimaryBridgeState(pl.BankingBridgeState, p) 329 case *types.PayloadBankingEVMBridgeStates: 330 return nil, e.restoreSecondaryBridgeState(pl.BankingBridgeStates, p) 331 case *types.PayloadBankingTransferFeeDiscounts: 332 return nil, e.restoreTransferFeeDiscounts(pl.BankingTransferFeeDiscounts, p) 333 default: 334 return nil, types.ErrUnknownSnapshotType 335 } 336 } 337 338 func (e *Engine) restoreRecurringTransfers(ctx context.Context, transfers *checkpoint.RecurringTransfers, nextMetricUpdate time.Time, p *types.Payload) error { 339 var err error 340 // ignore events here as we don't need to send them 341 _ = e.loadRecurringTransfers(ctx, transfers) 342 e.bss.serialisedRecurringTransfers, err = proto.Marshal(p.IntoProto()) 343 e.nextMetricUpdate = nextMetricUpdate 344 return err 345 } 346 347 func (e *Engine) restoreRecurringGovernanceTransfers(ctx context.Context, transfers []*checkpoint.GovernanceTransfer, p *types.Payload) error { 348 var err error 349 _ = e.loadRecurringGovernanceTransfers(ctx, transfers) 350 e.bss.serialisedGovRecurringTransfers, err = proto.Marshal(p.IntoProto()) 351 return err 352 } 353 354 func (e *Engine) restoreScheduledTransfers(ctx context.Context, transfers []*checkpoint.ScheduledTransferAtTime, p *types.Payload) error { 355 var err error 356 357 // ignore events 358 _, err = e.loadScheduledTransfers(ctx, transfers) 359 if err != nil { 360 return err 361 } 362 e.bss.serialisedScheduledTransfers, err = proto.Marshal(p.IntoProto()) 363 return err 364 } 365 366 func (e *Engine) restoreScheduledGovernanceTransfers(ctx context.Context, transfers []*checkpoint.ScheduledGovernanceTransferAtTime, p *types.Payload) error { 367 var err error 368 e.loadScheduledGovernanceTransfers(ctx, transfers) 369 e.bss.serialisedGovScheduledTransfers, err = proto.Marshal(p.IntoProto()) 370 return err 371 } 372 373 func (e *Engine) restorePrimaryBridgeState(state *types.BankingBridgeState, p *types.Payload) (err error) { 374 if state != nil { 375 e.primaryBridgeState = &bridgeState{ 376 active: state.Active, 377 block: state.BlockHeight, 378 logIndex: state.LogIndex, 379 } 380 } 381 382 e.bss.serialisedPrimaryBridgeState, err = proto.Marshal(p.IntoProto()) 383 return 384 } 385 386 func (e *Engine) restoreSecondaryBridgeState(state []*checkpoint.BridgeState, p *types.Payload) (err error) { 387 if state != nil { 388 e.secondaryBridgeState = &bridgeState{ 389 active: state[0].Active, 390 block: state[0].BlockHeight, 391 logIndex: state[0].LogIndex, 392 } 393 } 394 395 e.bss.serialisedSecondaryBridgeState, err = proto.Marshal(p.IntoProto()) 396 return 397 } 398 399 func (e *Engine) restoreDeposits(deposits *types.BankingDeposits, p *types.Payload) error { 400 var err error 401 402 for _, d := range deposits.Deposit { 403 e.deposits[d.ID] = d.Deposit 404 } 405 406 e.bss.serialisedDeposits, err = proto.Marshal(p.IntoProto()) 407 return err 408 } 409 410 func (e *Engine) restoreWithdrawals(withdrawals *types.BankingWithdrawals, p *types.Payload) error { 411 var err error 412 for _, w := range withdrawals.Withdrawals { 413 ref := new(big.Int) 414 ref.SetString(w.Ref, 10) 415 e.withdrawalCnt.Add(e.withdrawalCnt, big.NewInt(1)) 416 e.withdrawals[w.Withdrawal.ID] = withdrawalRef{ 417 w: w.Withdrawal, 418 ref: ref, 419 } 420 } 421 422 e.bss.serialisedWithdrawals, err = proto.Marshal(p.IntoProto()) 423 424 return err 425 } 426 427 func (e *Engine) restoreSeen(ctx context.Context, seen *types.BankingSeen, p *types.Payload) error { 428 var err error 429 e.log.Info("restoring seen", logging.Int("n", len(seen.Refs))) 430 e.seenAssetActions = treeset.NewWithStringComparator() 431 for _, v := range seen.Refs { 432 e.seenAssetActions.Add(v) 433 } 434 435 if vgcontext.InProgressUpgradeFrom(ctx, "v0.76.8") { 436 e.log.Info("migration code updating primary bridge last seen", 437 logging.String("address", e.bridgeAddresses[e.primaryEthChainID]), 438 logging.Uint64("last-seen", seen.LastSeenPrimaryEthBlock), 439 ) 440 e.ethEventSource.UpdateContractBlock( 441 e.bridgeAddresses[e.primaryEthChainID], 442 e.primaryEthChainID, 443 seen.LastSeenPrimaryEthBlock, 444 ) 445 e.log.Info("migration code updating primary bridge last seen", 446 logging.String("address", e.bridgeAddresses[e.secondaryEthChainID]), 447 logging.Uint64("last-seen", seen.LastSeenSecondaryEthBlock), 448 ) 449 e.ethEventSource.UpdateContractBlock( 450 e.bridgeAddresses[e.secondaryEthChainID], 451 e.secondaryEthChainID, 452 seen.LastSeenSecondaryEthBlock, 453 ) 454 } 455 456 e.lastSeenPrimaryEthBlock = seen.LastSeenPrimaryEthBlock 457 e.lastSeenSecondaryEthBlock = seen.LastSeenSecondaryEthBlock 458 e.bss.serialisedSeen, err = proto.Marshal(p.IntoProto()) 459 return err 460 } 461 462 func (e *Engine) restoreAssetActions(aa *types.BankingAssetActions, p *types.Payload) error { 463 var err error 464 465 if err := e.loadAssetActions(aa.AssetAction); err != nil { 466 return fmt.Errorf("could not load asset actions: %w", err) 467 } 468 469 for _, aa := range e.assetActions { 470 if err := e.witness.RestoreResource(aa, e.onCheckDone); err != nil { 471 e.log.Panic("unable to restore witness resource", logging.String("id", aa.id), logging.Error(err)) 472 } 473 } 474 475 e.bss.serialisedAssetActions, err = proto.Marshal(p.IntoProto()) 476 return err 477 } 478 479 func (e *Engine) restoreTransferFeeDiscounts( 480 state *snapshot.BankingTransferFeeDiscounts, 481 p *types.Payload, 482 ) (err error) { 483 if state == nil { 484 return nil 485 } 486 487 e.feeDiscountPerPartyAndAsset = make(map[partyAssetKey]*num.Uint, len(state.PartyAssetDiscount)) 488 for _, v := range state.PartyAssetDiscount { 489 discount, _ := num.UintFromString(v.Amount, 10) 490 e.feeDiscountPerPartyAndAsset[e.feeDiscountKey(v.Asset, v.Party)] = discount 491 } 492 493 e.bss.serialisedTransferFeeDiscounts, err = proto.Marshal(p.IntoProto()) 494 return 495 } 496 497 func (e *Engine) OnEpochRestore(_ context.Context, ep types.Epoch) { 498 e.log.Debug("epoch restoration notification received", logging.String("epoch", ep.String())) 499 e.currentEpoch = ep.Seq 500 }