Skip to content

Commit

Permalink
Optimization: saving validators query (#299)
Browse files Browse the repository at this point in the history
  • Loading branch information
aopoltorzhicky authored Nov 3, 2024
1 parent c278fea commit c4561f4
Show file tree
Hide file tree
Showing 2 changed files with 143 additions and 45 deletions.
71 changes: 26 additions & 45 deletions internal/storage/postgres/transaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -277,53 +277,34 @@ func (tx Transaction) SaveValidators(ctx context.Context, validators ...*models.
return 0, nil
}

var count int
arr := make([]addedValidator, len(validators))
for i := range validators {
model := addedValidator{
Validator: validators[i],
}
query := tx.Tx().NewInsert().Model(&model).
Column("id", "delegator", "address", "cons_address", "moniker", "website", "identity", "contacts", "details", "rate", "max_rate", "max_change_rate", "min_self_delegation", "stake", "jailed", "commissions", "rewards", "height").
On("CONFLICT ON CONSTRAINT address_validator DO UPDATE")

if !validators[i].Rate.IsZero() {
query.Set("rate = EXCLUDED.rate")
}
if !validators[i].MinSelfDelegation.IsZero() {
query.Set("min_self_delegation = EXCLUDED.min_self_delegation")
}
if !validators[i].Stake.IsZero() {
query.Set("stake = added_validator.stake + EXCLUDED.stake")
}
if validators[i].Jailed != nil {
query.Set("jailed = EXCLUDED.jailed")
}
if !validators[i].Commissions.IsZero() {
query.Set("commissions = added_validator.commissions + EXCLUDED.commissions")
}
if !validators[i].Rewards.IsZero() {
query.Set("rewards = added_validator.rewards + EXCLUDED.rewards")
}
if validators[i].Moniker != models.DoNotModify {
query.Set("moniker = EXCLUDED.moniker")
}
if validators[i].Website != models.DoNotModify {
query.Set("website = EXCLUDED.website")
}
if validators[i].Identity != models.DoNotModify {
query.Set("identity = EXCLUDED.identity")
}
if validators[i].Contacts != models.DoNotModify {
query.Set("contacts = EXCLUDED.contacts")
}
if validators[i].Details != models.DoNotModify {
query.Set("details = EXCLUDED.details")
}
if _, err := query.Returning("xmax, id").Exec(ctx); err != nil {
return 0, err
}
arr[i].Validator = validators[i]
}

query := tx.Tx().NewInsert().Model(&arr).
Column("id", "delegator", "address", "cons_address", "moniker", "website", "identity", "contacts", "details", "rate", "max_rate", "max_change_rate", "min_self_delegation", "stake", "jailed", "commissions", "rewards", "height").
On("CONFLICT ON CONSTRAINT address_validator DO UPDATE").
Set("rate = CASE WHEN EXCLUDED.rate > 0 THEN EXCLUDED.rate ELSE added_validator.rate END").
Set("min_self_delegation = CASE WHEN EXCLUDED.min_self_delegation > 0 THEN EXCLUDED.min_self_delegation ELSE added_validator.min_self_delegation END").
Set("stake = added_validator.stake + EXCLUDED.stake").
Set("commissions = added_validator.commissions + EXCLUDED.commissions").
Set("rewards = added_validator.rewards + EXCLUDED.rewards").
Set("moniker = CASE WHEN EXCLUDED.moniker != '[do-not-modify]' THEN EXCLUDED.moniker ELSE added_validator.moniker END").
Set("website = CASE WHEN EXCLUDED.website != '[do-not-modify]' THEN EXCLUDED.website ELSE added_validator.website END").
Set("identity = CASE WHEN EXCLUDED.identity != '[do-not-modify]' THEN EXCLUDED.identity ELSE added_validator.identity END").
Set("contacts = CASE WHEN EXCLUDED.contacts != '[do-not-modify]' THEN EXCLUDED.contacts ELSE added_validator.contacts END").
Set("details = CASE WHEN EXCLUDED.details != '[do-not-modify]' THEN EXCLUDED.details ELSE added_validator.details END").
Set("jailed = CASE WHEN EXCLUDED.jailed IS NOT NULL THEN EXCLUDED.jailed ELSE added_validator.jailed END").
Returning("xmax, id")

if _, err := query.Exec(ctx); err != nil {
return 0, err
}

if model.Xmax == 0 {
var count int
for i := range arr {
if arr[i].Xmax == 0 {
count++
}
}
Expand Down
117 changes: 117 additions & 0 deletions internal/storage/postgres/transaction_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -974,6 +974,123 @@ func (s *TransactionTestSuite) TestUpdateSlashedDelegations() {
s.Require().EqualValues(2, balances[1].Id)
}

func (s *TransactionTestSuite) TestSaveValidators() {
ctx, ctxCancel := context.WithTimeout(context.Background(), 5*time.Second)
defer ctxCancel()

tx, err := BeginTransaction(ctx, s.storage.Transactable)
s.Require().NoError(err)

validators := []*storage.Validator{
{
Address: "celestiavaloper1cj45qyagkujxgdgv8lgjur56zjxtrsy40g3pw3",
Delegator: "celestia1cj45qyagkujxgdgv8lgjur56zjxtrsy42hncch",
ConsAddress: "95764047BDFFB5CCADFA635DC63365EEB65F00C2",
Rate: decimal.NewFromFloat32(0.2),
MaxRate: decimal.NewFromFloat32(0.2),
MaxChangeRate: decimal.Zero,
MinSelfDelegation: decimal.Zero,
Identity: "0068ECE5E6EB5359",
Stake: decimal.NewFromInt(100),
Moniker: "Polychain",
Commissions: decimal.Zero,
Rewards: decimal.Zero,
Height: 1001,
Jailed: testsuite.Ptr(false),
}, {
Address: "celestiavaloper189ecvq5avj0wehrcfnagpd5sd8pup9aqmdglmr",
Delegator: "celestia189ecvq5avj0wehrcfnagpd5sd8pup9aq7j2xd9",
Rate: decimal.NewFromFloat32(0.06),
Commissions: decimal.NewFromInt(100),
Rewards: decimal.NewFromInt(200),
Website: "test-website",
Identity: storage.DoNotModify,
Contacts: storage.DoNotModify,
Moniker: storage.DoNotModify,
Details: storage.DoNotModify,
Stake: decimal.Zero,
Height: 1001,
Jailed: testsuite.Ptr(true),
}, {
Address: "celestiavaloper17vmk8m246t648hpmde2q7kp4ft9uwrayy09dmw",
Delegator: "celestia17vmk8m246t648hpmde2q7kp4ft9uwrayps85dg",
Commissions: decimal.NewFromInt(100),
Rewards: decimal.NewFromInt(200),
Stake: decimal.Zero,
Website: storage.DoNotModify,
Identity: storage.DoNotModify,
Contacts: storage.DoNotModify,
Moniker: storage.DoNotModify,
Details: storage.DoNotModify,
Height: 1001,
},
}

count, err := tx.SaveValidators(ctx, validators...)
s.Require().NoError(err)
s.Require().EqualValues(1, count)

s.Require().NoError(tx.Flush(ctx))
s.Require().NoError(tx.Close(ctx))

entities, err := s.storage.Validator.ListByPower(ctx, storage.ValidatorFilters{
Limit: 10,
})
s.Require().NoError(err)
s.Require().Len(entities, 3)

first := entities[0]
s.Require().EqualValues("101", first.Commissions.String())
s.Require().EqualValues("201", first.Rewards.String())
s.Require().NotNil(first.Jailed)
s.Require().False(*first.Jailed)

second := entities[1]
s.Require().EqualValues("100", second.Stake.String())
s.Require().EqualValues("0.2", second.Rate.String())
s.Require().EqualValues("Polychain", second.Moniker)
s.Require().NotNil(second.Jailed)
s.Require().False(*second.Jailed)

third := entities[2]
s.Require().EqualValues("101", third.Commissions.String())
s.Require().EqualValues("201", third.Rewards.String())
s.Require().EqualValues("0.06", third.Rate.String())
s.Require().EqualValues("test-website", third.Website)
s.Require().NotNil(third.Jailed)
s.Require().True(*third.Jailed)

tx2, err := BeginTransaction(ctx, s.storage.Transactable)
s.Require().NoError(err)

validatorJailed := []*storage.Validator{
{
Address: "celestiavaloper189ecvq5avj0wehrcfnagpd5sd8pup9aqmdglmr",
Delegator: "celestia189ecvq5avj0wehrcfnagpd5sd8pup9aq7j2xd9",
Commissions: decimal.NewFromInt(100),
Rewards: decimal.NewFromInt(200),
Identity: storage.DoNotModify,
Website: storage.DoNotModify,
Contacts: storage.DoNotModify,
Moniker: storage.DoNotModify,
Details: storage.DoNotModify,
Stake: decimal.Zero,
},
}

count2, err := tx2.SaveValidators(ctx, validatorJailed...)
s.Require().NoError(err)
s.Require().EqualValues(0, count2)

s.Require().NoError(tx2.Flush(ctx))
s.Require().NoError(tx2.Close(ctx))

v, err := s.storage.Validator.ByAddress(ctx, "celestiavaloper189ecvq5avj0wehrcfnagpd5sd8pup9aqmdglmr")
s.Require().NoError(err)
s.Require().NotNil(v.Jailed)
s.Require().True(*v.Jailed)
}

func TestSuiteTransaction_Run(t *testing.T) {
suite.Run(t, new(TransactionTestSuite))
}

0 comments on commit c4561f4

Please sign in to comment.