-
Notifications
You must be signed in to change notification settings - Fork 0
/
accounts.go
291 lines (250 loc) · 9.46 KB
/
accounts.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
package history
import (
"context"
sq "github.com/Masterminds/squirrel"
"github.com/shantanu-hashcash/go/services/aurora/internal/db2"
"github.com/shantanu-hashcash/go/support/errors"
"github.com/shantanu-hashcash/go/xdr"
)
// IsAuthRequired returns true if the account has the "AUTH_REQUIRED" option
// turned on.
func (account AccountEntry) IsAuthRequired() bool {
return xdr.AccountFlags(account.Flags).IsAuthRequired()
}
// IsAuthRevocable returns true if the account has the "AUTH_REVOCABLE" option
// turned on.
func (account AccountEntry) IsAuthRevocable() bool {
return xdr.AccountFlags(account.Flags).IsAuthRevocable()
}
// IsAuthImmutable returns true if the account has the "AUTH_IMMUTABLE" option
// turned on.
func (account AccountEntry) IsAuthImmutable() bool {
return xdr.AccountFlags(account.Flags).IsAuthImmutable()
}
// IsAuthClawbackEnabled returns true if the account has the "AUTH_CLAWBACK_ENABLED" option
// turned on.
func (account AccountEntry) IsAuthClawbackEnabled() bool {
return xdr.AccountFlags(account.Flags).IsAuthClawbackEnabled()
}
func (q *Q) CountAccounts(ctx context.Context) (int, error) {
sql := sq.Select("count(*)").From("accounts")
var count int
if err := q.Get(ctx, &count, sql); err != nil {
return 0, errors.Wrap(err, "could not run select query")
}
return count, nil
}
func (q *Q) GetAccountByID(ctx context.Context, id string) (AccountEntry, error) {
var account AccountEntry
sql := selectAccounts.Where(sq.Eq{"account_id": id})
err := q.Get(ctx, &account, sql)
return account, err
}
func (q *Q) GetAccountsByIDs(ctx context.Context, ids []string) ([]AccountEntry, error) {
var accounts []AccountEntry
sql := selectAccounts.Where(map[string]interface{}{"accounts.account_id": ids})
err := q.Select(ctx, &accounts, sql)
return accounts, err
}
// UpsertAccounts upserts a batch of accounts in the accounts table.
// There's currently no limit of the number of accounts this method can
// accept other than 2GB limit of the query string length what should be enough
// for each ledger with the current limits.
func (q *Q) UpsertAccounts(ctx context.Context, accounts []AccountEntry) error {
var accountID, inflationDestination, homeDomain, balance, buyingLiabilities,
sellingLiabilities, sequenceNumber, sequenceLedger, sequenceTime, numSubEntries,
flags, lastModifiedLedger, numSponsored, numSponsoring, masterWeight, thresholdLow,
thresholdMedium, thresholdHigh, sponsor []interface{}
for _, account := range accounts {
accountID = append(accountID, account.AccountID)
balance = append(balance, account.Balance)
buyingLiabilities = append(buyingLiabilities, account.BuyingLiabilities)
sellingLiabilities = append(sellingLiabilities, account.SellingLiabilities)
sequenceNumber = append(sequenceNumber, account.SequenceNumber)
sequenceLedger = append(sequenceLedger, account.SequenceLedger)
sequenceTime = append(sequenceTime, account.SequenceTime)
numSubEntries = append(numSubEntries, account.NumSubEntries)
inflationDestination = append(inflationDestination, account.InflationDestination)
homeDomain = append(homeDomain, account.HomeDomain)
flags = append(flags, account.Flags)
masterWeight = append(masterWeight, account.MasterWeight)
thresholdLow = append(thresholdLow, account.ThresholdLow)
thresholdMedium = append(thresholdMedium, account.ThresholdMedium)
thresholdHigh = append(thresholdHigh, account.ThresholdHigh)
lastModifiedLedger = append(lastModifiedLedger, account.LastModifiedLedger)
sponsor = append(sponsor, account.Sponsor)
numSponsored = append(numSponsored, account.NumSponsored)
numSponsoring = append(numSponsoring, account.NumSponsoring)
}
upsertFields := []upsertField{
{"account_id", "text", accountID},
{"balance", "bigint", balance},
{"buying_liabilities", "bigint", buyingLiabilities},
{"selling_liabilities", "bigint", sellingLiabilities},
{"sequence_number", "bigint", sequenceNumber},
{"sequence_ledger", "int", sequenceLedger},
{"sequence_time", "bigint", sequenceTime},
{"num_subentries", "int", numSubEntries},
{"inflation_destination", "text", inflationDestination},
{"flags", "int", flags},
{"home_domain", "text", homeDomain},
{"master_weight", "int", masterWeight},
{"threshold_low", "int", thresholdLow},
{"threshold_medium", "int", thresholdMedium},
{"threshold_high", "int", thresholdHigh},
{"last_modified_ledger", "int", lastModifiedLedger},
{"sponsor", "text", sponsor},
{"num_sponsored", "int", numSponsored},
{"num_sponsoring", "int", numSponsoring},
}
return q.upsertRows(ctx, "accounts", "account_id", upsertFields)
}
// RemoveAccounts deletes a row in the accounts table.
// Returns number of rows affected and error.
func (q *Q) RemoveAccounts(ctx context.Context, accountIDs []string) (int64, error) {
sql := sq.Delete("accounts").Where(sq.Eq{"account_id": accountIDs})
result, err := q.Exec(ctx, sql)
if err != nil {
return 0, err
}
return result.RowsAffected()
}
// AccountsForAsset returns a list of `AccountEntry` rows who are trustee to an
// asset
func (q *Q) AccountsForAsset(ctx context.Context, asset xdr.Asset, page db2.PageQuery) ([]AccountEntry, error) {
var assetType, code, issuer string
asset.MustExtract(&assetType, &code, &issuer)
sql := sq.
Select("accounts.*").
From("accounts").
Join("trust_lines ON accounts.account_id = trust_lines.account_id").
Where(map[string]interface{}{
"trust_lines.asset_type": int32(asset.Type),
"trust_lines.asset_issuer": issuer,
"trust_lines.asset_code": code,
})
sql, err := page.ApplyToUsingCursor(sql, "trust_lines.account_id", page.Cursor)
if err != nil {
return nil, errors.Wrap(err, "could not apply query to page")
}
var results []AccountEntry
if err := q.Select(ctx, &results, sql); err != nil {
return nil, errors.Wrap(err, "could not run select query")
}
return results, nil
}
// AccountsForLiquidityPool returns a list of `AccountEntry` rows who are trustee to a
// liquidity pool share asset
func (q *Q) AccountsForLiquidityPool(ctx context.Context, poolID string, page db2.PageQuery) ([]AccountEntry, error) {
sql := sq.
Select("accounts.*").
From("accounts").
Join("trust_lines ON accounts.account_id = trust_lines.account_id").
Where(map[string]interface{}{
"trust_lines.liquidity_pool_id": poolID,
})
sql, err := page.ApplyToUsingCursor(sql, "trust_lines.account_id", page.Cursor)
if err != nil {
return nil, errors.Wrap(err, "could not apply query to page")
}
var results []AccountEntry
if err := q.Select(ctx, &results, sql); err != nil {
return nil, errors.Wrap(err, "could not run select query")
}
return results, nil
}
func selectBySponsor(table, sponsor string, page db2.PageQuery) (sq.SelectBuilder, error) {
sql := sq.
Select("account_id").
From(table).
Where(map[string]interface{}{
"sponsor": sponsor,
})
sql, err := page.ApplyToUsingCursor(sql, "account_id", page.Cursor)
if err != nil {
return sql, errors.Wrap(err, "could not apply query to page")
}
return sql, err
}
func selectUnionBySponsor(tables []string, sponsor string, page db2.PageQuery) (sq.SelectBuilder, error) {
var selectIDs sq.SelectBuilder
for i, table := range tables {
sql, err := selectBySponsor(table, sponsor, page)
if err != nil {
return sql, errors.Wrap(err, "could not construct account id query")
}
sql = sql.Prefix("(").Suffix(")")
if i == 0 {
selectIDs = sql
continue
}
sqlStr, args, err := sql.ToSql()
if err != nil {
return sql, errors.Wrap(err, "could not construct account id query")
}
selectIDs = selectIDs.Suffix("UNION "+sqlStr, args...)
}
return sq.
Select("accounts.*").
FromSelect(selectIDs, "accountSet").
Join("accounts ON accounts.account_id = accountSet.account_id").
OrderBy("accounts.account_id " + page.Order).
Limit(page.Limit), nil
}
// AccountsForSponsor return all the accounts where `sponsor“ is sponsoring the account entry or
// any of its subentries (trust lines, signers, data, or account entry)
func (q *Q) AccountsForSponsor(ctx context.Context, sponsor string, page db2.PageQuery) ([]AccountEntry, error) {
sql, err := selectUnionBySponsor(
[]string{"accounts", "accounts_data", "accounts_signers", "trust_lines"},
sponsor,
page,
)
if err != nil {
return nil, errors.Wrap(err, "could not construct accounts query")
}
var results []AccountEntry
if err := q.Select(ctx, &results, sql); err != nil {
return nil, errors.Wrap(err, "could not run select query")
}
return results, nil
}
// AccountEntriesForSigner returns a list of `AccountEntry` rows for a given signer
func (q *Q) AccountEntriesForSigner(ctx context.Context, signer string, page db2.PageQuery) ([]AccountEntry, error) {
sql := sq.
Select("accounts.*").
From("accounts").
Join("accounts_signers ON accounts.account_id = accounts_signers.account_id").
Where(map[string]interface{}{
"accounts_signers.signer": signer,
})
sql, err := page.ApplyToUsingCursor(sql, "accounts_signers.account_id", page.Cursor)
if err != nil {
return nil, errors.Wrap(err, "could not apply query to page")
}
var results []AccountEntry
if err := q.Select(ctx, &results, sql); err != nil {
return nil, errors.Wrap(err, "could not run select query")
}
return results, nil
}
var selectAccounts = sq.Select(`
account_id,
balance,
buying_liabilities,
selling_liabilities,
sequence_number,
sequence_ledger,
sequence_time,
num_subentries,
inflation_destination,
flags,
home_domain,
master_weight,
threshold_low,
threshold_medium,
threshold_high,
last_modified_ledger,
sponsor,
num_sponsored,
num_sponsoring
`).From("accounts")