|
| 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 ValidatorEntry struct { |
| 14 | + ValidatorPKID string `bun:",nullzero"` |
| 15 | + Domains []string `bun:",nullzero"` |
| 16 | + DisableDelegatedStake bool |
| 17 | + DelegatedStakeCommissionBasisPoints uint64 |
| 18 | + VotingPublicKey string `bun:",nullzero"` |
| 19 | + VotingAuthorization string `bun:",nullzero"` |
| 20 | + // Use bunbig.Int to store the balance as a numeric in the pg database. |
| 21 | + TotalStakeAmountNanos *bunbig.Int `pg:",use_zero"` |
| 22 | + LastActiveAtEpochNumber uint64 |
| 23 | + JailedAtEpochNumber uint64 |
| 24 | + |
| 25 | + ExtraData map[string]string `bun:"type:jsonb"` |
| 26 | + BadgerKey []byte `pg:",pk,use_zero"` |
| 27 | +} |
| 28 | + |
| 29 | +type PGValidatorEntry struct { |
| 30 | + bun.BaseModel `bun:"table:validator_entry"` |
| 31 | + ValidatorEntry |
| 32 | +} |
| 33 | + |
| 34 | +// TODO: Do I need this? |
| 35 | +type PGValidatorEntryUtxoOps struct { |
| 36 | + bun.BaseModel `bun:"table:validator_entry_utxo_ops"` |
| 37 | + ValidatorEntry |
| 38 | + UtxoOperation |
| 39 | +} |
| 40 | + |
| 41 | +// Convert the ValidatorEntry DeSo encoder to the PGValidatorEntry struct used by bun. |
| 42 | +func ValidatorEncoderToPGStruct(validatorEntry *lib.ValidatorEntry, keyBytes []byte, params *lib.DeSoParams) ValidatorEntry { |
| 43 | + pgValidatorEntry := ValidatorEntry{ |
| 44 | + ExtraData: consumer.ExtraDataBytesToString(validatorEntry.ExtraData), |
| 45 | + BadgerKey: keyBytes, |
| 46 | + } |
| 47 | + |
| 48 | + if validatorEntry.ValidatorPKID != nil { |
| 49 | + pgValidatorEntry.ValidatorPKID = consumer.PublicKeyBytesToBase58Check((*validatorEntry.ValidatorPKID)[:], params) |
| 50 | + } |
| 51 | + |
| 52 | + if validatorEntry.Domains != nil { |
| 53 | + pgValidatorEntry.Domains = make([]string, len(validatorEntry.Domains)) |
| 54 | + for ii, domain := range validatorEntry.Domains { |
| 55 | + pgValidatorEntry.Domains[ii] = string(domain) |
| 56 | + } |
| 57 | + } |
| 58 | + |
| 59 | + pgValidatorEntry.DisableDelegatedStake = validatorEntry.DisableDelegatedStake |
| 60 | + pgValidatorEntry.DelegatedStakeCommissionBasisPoints = validatorEntry.DelegatedStakeCommissionBasisPoints |
| 61 | + |
| 62 | + if validatorEntry.VotingPublicKey != nil { |
| 63 | + pgValidatorEntry.VotingPublicKey = validatorEntry.VotingPublicKey.ToString() |
| 64 | + } |
| 65 | + |
| 66 | + if validatorEntry.VotingAuthorization != nil { |
| 67 | + pgValidatorEntry.VotingAuthorization = validatorEntry.VotingAuthorization.ToString() |
| 68 | + } |
| 69 | + |
| 70 | + pgValidatorEntry.TotalStakeAmountNanos = bunbig.FromMathBig(validatorEntry.TotalStakeAmountNanos.ToBig()) |
| 71 | + pgValidatorEntry.LastActiveAtEpochNumber = validatorEntry.LastActiveAtEpochNumber |
| 72 | + pgValidatorEntry.JailedAtEpochNumber = validatorEntry.JailedAtEpochNumber |
| 73 | + |
| 74 | + return pgValidatorEntry |
| 75 | +} |
| 76 | + |
| 77 | +// ValidatorBatchOperation is the entry point for processing a batch of Validator entries. |
| 78 | +// It determines the appropriate handler based on the operation type and executes it. |
| 79 | +func ValidatorBatchOperation(entries []*lib.StateChangeEntry, db *bun.DB, params *lib.DeSoParams) error { |
| 80 | + // We check before we call this function that there is at least one operation type. |
| 81 | + // We also ensure before this that all entries have the same operation type. |
| 82 | + operationType := entries[0].OperationType |
| 83 | + var err error |
| 84 | + if operationType == lib.DbOperationTypeDelete { |
| 85 | + err = bulkDeleteValidatorEntry(entries, db, operationType) |
| 86 | + } else { |
| 87 | + err = bulkInsertValidatorEntry(entries, db, operationType, params) |
| 88 | + } |
| 89 | + if err != nil { |
| 90 | + return errors.Wrapf(err, "entries.ValidatorBatchOperation: Problem with operation type %v", operationType) |
| 91 | + } |
| 92 | + return nil |
| 93 | +} |
| 94 | + |
| 95 | +// bulkInsertValidatorEntry inserts a batch of validator entries into the database. |
| 96 | +func bulkInsertValidatorEntry(entries []*lib.StateChangeEntry, db *bun.DB, operationType lib.StateSyncerOperationType, params *lib.DeSoParams) error { |
| 97 | + // Track the unique entries we've inserted so we don't insert the same entry twice. |
| 98 | + uniqueEntries := consumer.UniqueEntries(entries) |
| 99 | + // Create a new array to hold the bun struct. |
| 100 | + pgEntrySlice := make([]*PGValidatorEntry, len(uniqueEntries)) |
| 101 | + |
| 102 | + // Loop through the entries and convert them to PGEntry. |
| 103 | + for ii, entry := range uniqueEntries { |
| 104 | + pgEntrySlice[ii] = &PGValidatorEntry{ValidatorEntry: ValidatorEncoderToPGStruct(entry.Encoder.(*lib.ValidatorEntry), entry.KeyBytes, params)} |
| 105 | + } |
| 106 | + |
| 107 | + // Execute the insert query. |
| 108 | + query := db.NewInsert().Model(&pgEntrySlice) |
| 109 | + |
| 110 | + if operationType == lib.DbOperationTypeUpsert { |
| 111 | + query = query.On("CONFLICT (badger_key) DO UPDATE") |
| 112 | + } |
| 113 | + |
| 114 | + if _, err := query.Returning("").Exec(context.Background()); err != nil { |
| 115 | + return errors.Wrapf(err, "entries.bulkInsertValidatorEntry: Error inserting entries") |
| 116 | + } |
| 117 | + return nil |
| 118 | +} |
| 119 | + |
| 120 | +// bulkDeleteValidatorEntry deletes a batch of validator entries from the database. |
| 121 | +func bulkDeleteValidatorEntry(entries []*lib.StateChangeEntry, db *bun.DB, operationType lib.StateSyncerOperationType) error { |
| 122 | + // Track the unique entries we've inserted so we don't insert the same entry twice. |
| 123 | + uniqueEntries := consumer.UniqueEntries(entries) |
| 124 | + |
| 125 | + // Transform the entries into a list of keys to delete. |
| 126 | + keysToDelete := consumer.KeysToDelete(uniqueEntries) |
| 127 | + |
| 128 | + // Execute the delete query. |
| 129 | + if _, err := db.NewDelete(). |
| 130 | + Model(&PGValidatorEntry{}). |
| 131 | + Where("badger_key IN (?)", bun.In(keysToDelete)). |
| 132 | + Returning(""). |
| 133 | + Exec(context.Background()); err != nil { |
| 134 | + return errors.Wrapf(err, "entries.bulkDeleteValidatorEntry: Error deleting entries") |
| 135 | + } |
| 136 | + |
| 137 | + return nil |
| 138 | +} |
0 commit comments