|
| 1 | +package entries |
| 2 | + |
| 3 | +import ( |
| 4 | + "context" |
| 5 | + "github.com/deso-protocol/core/lib" |
| 6 | + "github.com/deso-protocol/state-consumer/consumer" |
| 7 | + "github.com/pkg/errors" |
| 8 | + "github.com/uptrace/bun" |
| 9 | + "github.com/uptrace/bun/extra/bunbig" |
| 10 | +) |
| 11 | + |
| 12 | +// TODO: when to use nullzero vs use_zero? |
| 13 | +type LockedBalanceEntry struct { |
| 14 | + HODLerPKID string `bun:",nullzero"` |
| 15 | + ProfilePKID string `bun:",nullzero"` |
| 16 | + UnlockTimestampNanoSecs int64 |
| 17 | + VestingEndTimestampNanoSecs int64 |
| 18 | + BalanceBaseUnits *bunbig.Int `pg:",use_zero"` |
| 19 | + |
| 20 | + BadgerKey []byte `pg:",pk,use_zero"` |
| 21 | +} |
| 22 | + |
| 23 | +type PGLockedBalanceEntry struct { |
| 24 | + bun.BaseModel `bun:"table:locked_balance_entry"` |
| 25 | + LockedBalanceEntry |
| 26 | +} |
| 27 | + |
| 28 | +// TODO: Do I need this? |
| 29 | +type PGLockedBalanceEntryUtxoOps struct { |
| 30 | + bun.BaseModel `bun:"table:locked_balance_entry_utxo_ops"` |
| 31 | + LockedBalanceEntry |
| 32 | + UtxoOperation |
| 33 | +} |
| 34 | + |
| 35 | +// Convert the LockedBalanceEntry DeSo encoder to the PGLockedBalnceEntry struct used by bun. |
| 36 | +func LockedBalanceEntryEncoderToPGStruct(lockedBalanceEntry *lib.LockedBalanceEntry, keyBytes []byte, params *lib.DeSoParams) LockedBalanceEntry { |
| 37 | + pgLockedBalanceEntry := LockedBalanceEntry{ |
| 38 | + BadgerKey: keyBytes, |
| 39 | + } |
| 40 | + |
| 41 | + if lockedBalanceEntry.HODLerPKID != nil { |
| 42 | + pgLockedBalanceEntry.HODLerPKID = consumer.PublicKeyBytesToBase58Check((*lockedBalanceEntry.HODLerPKID)[:], params) |
| 43 | + } |
| 44 | + |
| 45 | + if lockedBalanceEntry.ProfilePKID != nil { |
| 46 | + pgLockedBalanceEntry.ProfilePKID = consumer.PublicKeyBytesToBase58Check((*lockedBalanceEntry.ProfilePKID)[:], params) |
| 47 | + } |
| 48 | + |
| 49 | + pgLockedBalanceEntry.UnlockTimestampNanoSecs = lockedBalanceEntry.UnlockTimestampNanoSecs |
| 50 | + pgLockedBalanceEntry.VestingEndTimestampNanoSecs = lockedBalanceEntry.VestingEndTimestampNanoSecs |
| 51 | + pgLockedBalanceEntry.BalanceBaseUnits = bunbig.FromMathBig(lockedBalanceEntry.BalanceBaseUnits.ToBig()) |
| 52 | + |
| 53 | + return pgLockedBalanceEntry |
| 54 | +} |
| 55 | + |
| 56 | +// LockedBalanceEntryBatchOperation is the entry point for processing a batch of LockedBalance entries. |
| 57 | +// It determines the appropriate handler based on the operation type and executes it. |
| 58 | +func LockedBalanceEntryBatchOperation(entries []*lib.StateChangeEntry, db *bun.DB, params *lib.DeSoParams) error { |
| 59 | + // We check before we call this function that there is at least one operation type. |
| 60 | + // We also ensure before this that all entries have the same operation type. |
| 61 | + operationType := entries[0].OperationType |
| 62 | + var err error |
| 63 | + if operationType == lib.DbOperationTypeDelete { |
| 64 | + err = bulkDeleteLockedBalanceEntry(entries, db, operationType) |
| 65 | + } else { |
| 66 | + err = bulkInsertLockedBalanceEntry(entries, db, operationType, params) |
| 67 | + } |
| 68 | + if err != nil { |
| 69 | + return errors.Wrapf(err, "entries.LockedBalanceEntryBatchOperation: Problem with operation type %v", operationType) |
| 70 | + } |
| 71 | + return nil |
| 72 | +} |
| 73 | + |
| 74 | +// bulkInsertLockedBalanceEntry inserts a batch of locked stake entries into the database. |
| 75 | +func bulkInsertLockedBalanceEntry(entries []*lib.StateChangeEntry, db *bun.DB, operationType lib.StateSyncerOperationType, params *lib.DeSoParams) error { |
| 76 | + // Track the unique entries we've inserted so we don't insert the same entry twice. |
| 77 | + uniqueEntries := consumer.UniqueEntries(entries) |
| 78 | + // Create a new array to hold the bun struct. |
| 79 | + pgEntrySlice := make([]*PGLockedBalanceEntry, len(uniqueEntries)) |
| 80 | + |
| 81 | + // Loop through the entries and convert them to PGEntry. |
| 82 | + for ii, entry := range uniqueEntries { |
| 83 | + pgEntrySlice[ii] = &PGLockedBalanceEntry{LockedBalanceEntry: LockedBalanceEntryEncoderToPGStruct(entry.Encoder.(*lib.LockedBalanceEntry), entry.KeyBytes, params)} |
| 84 | + } |
| 85 | + |
| 86 | + // Execute the insert query. |
| 87 | + query := db.NewInsert().Model(&pgEntrySlice) |
| 88 | + |
| 89 | + if operationType == lib.DbOperationTypeUpsert { |
| 90 | + query = query.On("CONFLICT (badger_key) DO UPDATE") |
| 91 | + } |
| 92 | + |
| 93 | + if _, err := query.Returning("").Exec(context.Background()); err != nil { |
| 94 | + return errors.Wrapf(err, "entries.bulkInsertLockedBalanceEntry: Error inserting entries") |
| 95 | + } |
| 96 | + return nil |
| 97 | +} |
| 98 | + |
| 99 | +// bulkDeleteLockedBalanceEntry deletes a batch of locked stake entries from the database. |
| 100 | +func bulkDeleteLockedBalanceEntry(entries []*lib.StateChangeEntry, db *bun.DB, operationType lib.StateSyncerOperationType) error { |
| 101 | + // Track the unique entries we've inserted so we don't insert the same entry twice. |
| 102 | + uniqueEntries := consumer.UniqueEntries(entries) |
| 103 | + |
| 104 | + // Transform the entries into a list of keys to delete. |
| 105 | + keysToDelete := consumer.KeysToDelete(uniqueEntries) |
| 106 | + |
| 107 | + // Execute the delete query. |
| 108 | + if _, err := db.NewDelete(). |
| 109 | + Model(&PGLockedBalanceEntry{}). |
| 110 | + Where("badger_key IN (?)", bun.In(keysToDelete)). |
| 111 | + Returning(""). |
| 112 | + Exec(context.Background()); err != nil { |
| 113 | + return errors.Wrapf(err, "entries.bulkDeleteLockedBalanceEntry: Error deleting entries") |
| 114 | + } |
| 115 | + |
| 116 | + return nil |
| 117 | +} |
0 commit comments