Skip to content

Commit acd13ff

Browse files
author
Jeff Yanta
committed
Multi-mint support for account info DB and GetTokenAccountInfos
1 parent 1ac9b04 commit acd13ff

File tree

18 files changed

+631
-391
lines changed

18 files changed

+631
-391
lines changed

pkg/code/async/geyser/external_deposit.go

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -258,17 +258,21 @@ func processPotentialExternalDepositIntoVm(ctx context.Context, data code_data.P
258258
return nil
259259
}
260260

261-
accountInfoRecord, err := data.GetAccountInfoByAuthorityAddress(ctx, userAuthority.PublicKey().ToBase58())
261+
accountInfoRecords, err := data.GetAccountInfoByAuthorityAddress(ctx, userAuthority.PublicKey().ToBase58())
262262
if err != nil {
263263
return errors.Wrap(err, "error getting account info record")
264264
}
265-
userVirtualTimelockVaultAccount, err := common.NewAccountFromPublicKeyString(accountInfoRecord.TokenAccount)
265+
coreMintAccountInfoRecord, ok := accountInfoRecords[common.CoreMintAccount.PublicKey().ToBase58()]
266+
if !ok {
267+
return errors.New("core mint account info record doesn't exist")
268+
}
269+
userVirtualTimelockVaultAccount, err := common.NewAccountFromPublicKeyString(coreMintAccountInfoRecord.TokenAccount)
266270
if err != nil {
267271
return errors.Wrap(err, "invalid virtual timelock vault account")
268272
}
269273

270274
// Use the account type to determine how we'll process this external deposit
271-
switch accountInfoRecord.AccountType {
275+
switch coreMintAccountInfoRecord.AccountType {
272276
case commonpb.AccountType_PRIMARY:
273277
// Check whether we've previously processed this external deposit
274278
_, err = data.GetExternalDeposit(ctx, signature, userVirtualTimelockVaultAccount.PublicKey().ToBase58())
@@ -279,7 +283,7 @@ func processPotentialExternalDepositIntoVm(ctx context.Context, data code_data.P
279283
return errors.Wrap(err, "error checking for existing external deposit record")
280284
}
281285

282-
ownerAccount, err := common.NewAccountFromPublicKeyString(accountInfoRecord.OwnerAccount)
286+
ownerAccount, err := common.NewAccountFromPublicKeyString(coreMintAccountInfoRecord.OwnerAccount)
283287
if err != nil {
284288
return errors.Wrap(err, "invalid owner account")
285289
}
@@ -398,15 +402,19 @@ func getDeltaQuarksFromTokenBalances(tokenAccount *common.Account, tokenBalances
398402
}
399403

400404
func markDepositsAsSynced(ctx context.Context, data code_data.Provider, userAuthority *common.Account) error {
401-
accountInfoRecord, err := data.GetAccountInfoByAuthorityAddress(ctx, userAuthority.PublicKey().ToBase58())
405+
accountInfoRecords, err := data.GetAccountInfoByAuthorityAddress(ctx, userAuthority.PublicKey().ToBase58())
402406
if err != nil {
403407
return errors.Wrap(err, "error getting account info record")
404408
}
409+
coreMintAccountInfoRecord, ok := accountInfoRecords[common.CoreMintAccount.PublicKey().ToBase58()]
410+
if !ok {
411+
return errors.New("core mint account info record doesn't exist")
412+
}
405413

406-
accountInfoRecord.RequiresDepositSync = false
407-
accountInfoRecord.DepositsLastSyncedAt = time.Now()
414+
coreMintAccountInfoRecord.RequiresDepositSync = false
415+
coreMintAccountInfoRecord.DepositsLastSyncedAt = time.Now()
408416

409-
err = data.UpdateAccountInfo(ctx, accountInfoRecord)
417+
err = data.UpdateAccountInfo(ctx, coreMintAccountInfoRecord)
410418
if err != nil {
411419
return errors.Wrap(err, "error updating account info record")
412420
}

pkg/code/balance/calculator_test.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ func TestDefaultCalculationMethods_NewCodeAccount(t *testing.T) {
4444
require.NoError(t, err)
4545
assert.EqualValues(t, 0, balance)
4646

47-
balanceByAccount, err := BatchCalculateFromCacheWithAccountRecords(env.ctx, env.data, accountRecords[commonpb.AccountType_PRIMARY][0])
47+
balanceByAccount, err := BatchCalculateFromCacheWithAccountRecords(env.ctx, env.data, accountRecords[common.CoreMintAccount.PublicKey().ToBase58()][commonpb.AccountType_PRIMARY][0])
4848
require.NoError(t, err)
4949
require.Len(t, balanceByAccount, 1)
5050
assert.EqualValues(t, 0, balanceByAccount[newTokenAccount.PublicKey().ToBase58()])
@@ -87,7 +87,7 @@ func TestDefaultCalculationMethods_DepositFromExternalWallet(t *testing.T) {
8787
accountRecords, err := common.GetLatestTokenAccountRecordsForOwner(env.ctx, env.data, owner)
8888
require.NoError(t, err)
8989

90-
balanceByAccount, err := BatchCalculateFromCacheWithAccountRecords(env.ctx, env.data, accountRecords[commonpb.AccountType_PRIMARY][0])
90+
balanceByAccount, err := BatchCalculateFromCacheWithAccountRecords(env.ctx, env.data, accountRecords[common.CoreMintAccount.PublicKey().ToBase58()][commonpb.AccountType_PRIMARY][0])
9191
require.NoError(t, err)
9292
require.Len(t, balanceByAccount, 1)
9393
assert.EqualValues(t, 11, balanceByAccount[depositAccount.PublicKey().ToBase58()])
@@ -181,7 +181,7 @@ func TestDefaultCalculationMethods_MultipleIntents(t *testing.T) {
181181
accountRecords4, err := common.GetLatestTokenAccountRecordsForOwner(env.ctx, env.data, owner4)
182182
require.NoError(t, err)
183183

184-
balanceByAccount, err := BatchCalculateFromCacheWithAccountRecords(env.ctx, env.data, accountRecords1[commonpb.AccountType_PRIMARY][0], accountRecords2[commonpb.AccountType_PRIMARY][0], accountRecords3[commonpb.AccountType_PRIMARY][0], accountRecords4[commonpb.AccountType_PRIMARY][0])
184+
balanceByAccount, err := BatchCalculateFromCacheWithAccountRecords(env.ctx, env.data, accountRecords1[common.CoreMintAccount.PublicKey().ToBase58()][commonpb.AccountType_PRIMARY][0], accountRecords2[common.CoreMintAccount.PublicKey().ToBase58()][commonpb.AccountType_PRIMARY][0], accountRecords3[common.CoreMintAccount.PublicKey().ToBase58()][commonpb.AccountType_PRIMARY][0], accountRecords4[common.CoreMintAccount.PublicKey().ToBase58()][commonpb.AccountType_PRIMARY][0])
185185
require.NoError(t, err)
186186
require.Len(t, balanceByAccount, 4)
187187
assert.EqualValues(t, 11, balanceByAccount[a1.PublicKey().ToBase58()])
@@ -244,7 +244,7 @@ func TestDefaultCalculationMethods_BackAndForth(t *testing.T) {
244244
accountRecords2, err := common.GetLatestTokenAccountRecordsForOwner(env.ctx, env.data, owner2)
245245
require.NoError(t, err)
246246

247-
balanceByAccount, err := BatchCalculateFromCacheWithAccountRecords(env.ctx, env.data, accountRecords1[commonpb.AccountType_PRIMARY][0], accountRecords2[commonpb.AccountType_PRIMARY][0])
247+
balanceByAccount, err := BatchCalculateFromCacheWithAccountRecords(env.ctx, env.data, accountRecords1[common.CoreMintAccount.PublicKey().ToBase58()][commonpb.AccountType_PRIMARY][0], accountRecords2[common.CoreMintAccount.PublicKey().ToBase58()][commonpb.AccountType_PRIMARY][0])
248248
require.NoError(t, err)
249249
require.Len(t, balanceByAccount, 2)
250250
assert.EqualValues(t, 0, balanceByAccount[a1.PublicKey().ToBase58()])
@@ -291,7 +291,7 @@ func TestDefaultCalculationMethods_SelfPayments(t *testing.T) {
291291
accountRecords, err := common.GetLatestTokenAccountRecordsForOwner(env.ctx, env.data, ownerAccount)
292292
require.NoError(t, err)
293293

294-
balanceByAccount, err := BatchCalculateFromCacheWithAccountRecords(env.ctx, env.data, accountRecords[commonpb.AccountType_PRIMARY][0])
294+
balanceByAccount, err := BatchCalculateFromCacheWithAccountRecords(env.ctx, env.data, accountRecords[common.CoreMintAccount.PublicKey().ToBase58()][commonpb.AccountType_PRIMARY][0])
295295
require.NoError(t, err)
296296
require.Len(t, balanceByAccount, 1)
297297
assert.EqualValues(t, 1, balanceByAccount[tokenAccount.PublicKey().ToBase58()])
@@ -329,7 +329,7 @@ func TestDefaultCalculationMethods_NotManagedByCode(t *testing.T) {
329329
_, err = CalculateFromCache(env.ctx, env.data, tokenAccount)
330330
assert.Equal(t, ErrNotManagedByCode, err)
331331

332-
_, err = BatchCalculateFromCacheWithAccountRecords(env.ctx, env.data, accountRecords[commonpb.AccountType_PRIMARY][0])
332+
_, err = BatchCalculateFromCacheWithAccountRecords(env.ctx, env.data, accountRecords[common.CoreMintAccount.PublicKey().ToBase58()][commonpb.AccountType_PRIMARY][0])
333333
assert.Equal(t, ErrNotManagedByCode, err)
334334

335335
_, err = BatchCalculateFromCacheWithTokenAccounts(env.ctx, env.data, tokenAccount)

pkg/code/common/mint.go

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,6 @@ var (
1818
CoreMintDecimals = config.CoreMintDecimals
1919
CoreMintName = config.CoreMintName
2020
CoreMintSymbol = config.CoreMintSymbol
21-
22-
UsdcMintAccount, _ = NewAccountFromPublicKeyBytes(usdc.TokenMint)
2321
)
2422

2523
func FromCoreMintQuarks(quarks uint64) uint64 {

pkg/code/common/owner.go

Lines changed: 61 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ type OwnerMetadata struct {
4040
}
4141

4242
// GetOwnerMetadata gets metadata about an owner account
43+
//
44+
// todo: assumes the core mint accounts are always opened first
4345
func GetOwnerMetadata(ctx context.Context, data code_data.Provider, owner *Account) (*OwnerMetadata, error) {
4446
mtdt := &OwnerMetadata{
4547
Account: owner,
@@ -82,23 +84,25 @@ func GetOwnerMetadata(ctx context.Context, data code_data.Provider, owner *Accou
8284
//
8385
// todo: Needs tests here, but most already exist in account service
8486
func GetOwnerManagementState(ctx context.Context, data code_data.Provider, owner *Account) (OwnerManagementState, error) {
85-
recordsByType, err := GetLatestTokenAccountRecordsForOwner(ctx, data, owner)
87+
recordsByMintAndType, err := GetLatestTokenAccountRecordsForOwner(ctx, data, owner)
8688
if err != nil {
8789
return OwnerManagementStateUnknown, err
8890
}
8991

9092
// Has an account ever been opened with the owner? If not, the owner is not a Code account.
9193
// SubmitIntent guarantees all accounts are opened, so there's no need to do anything more
9294
// than an empty check.
93-
if len(recordsByType) == 0 {
95+
if len(recordsByMintAndType) == 0 {
9496
return OwnerManagementStateNotFound, nil
9597
}
9698

9799
// Are all opened accounts managed by Code? If not, the owner is not a Code account.
98-
for _, batchAccountRecords := range recordsByType {
99-
for _, accountRecords := range batchAccountRecords {
100-
if accountRecords.IsTimelock() && !accountRecords.IsManagedByCode(ctx) {
101-
return OwnerManagementStateUnlocked, nil
100+
for _, recordsByType := range recordsByMintAndType {
101+
for _, recordsList := range recordsByType {
102+
for _, records := range recordsList {
103+
if records.IsTimelock() && !records.IsManagedByCode(ctx) {
104+
return OwnerManagementStateUnlocked, nil
105+
}
102106
}
103107
}
104108
}
@@ -108,23 +112,25 @@ func GetOwnerManagementState(ctx context.Context, data code_data.Provider, owner
108112

109113
// GetLatestTokenAccountRecordsForOwner gets DB records for the latest set of
110114
// token accounts for an owner account.
111-
func GetLatestTokenAccountRecordsForOwner(ctx context.Context, data code_data.Provider, owner *Account) (map[commonpb.AccountType][]*AccountRecords, error) {
112-
res := make(map[commonpb.AccountType][]*AccountRecords)
115+
func GetLatestTokenAccountRecordsForOwner(ctx context.Context, data code_data.Provider, owner *Account) (map[string]map[commonpb.AccountType][]*AccountRecords, error) {
116+
res := make(map[string]map[commonpb.AccountType][]*AccountRecords)
113117

114-
infoRecordsByType, err := data.GetLatestAccountInfosByOwnerAddress(ctx, owner.publicKey.ToBase58())
118+
infoRecordsByMintAndType, err := data.GetLatestAccountInfosByOwnerAddress(ctx, owner.publicKey.ToBase58())
115119
if err != account.ErrAccountInfoNotFound && err != nil {
116120
return nil, err
117121
}
118122

119-
if len(infoRecordsByType) == 0 {
123+
if len(infoRecordsByMintAndType) == 0 {
120124
return res, nil
121125
}
122126

123127
var timelockAccounts []string
124-
for _, infoRecords := range infoRecordsByType {
125-
for _, infoRecord := range infoRecords {
126-
if infoRecord.IsTimelock() {
127-
timelockAccounts = append(timelockAccounts, infoRecord.TokenAccount)
128+
for _, infoRecordsByType := range infoRecordsByMintAndType {
129+
for _, infoRecords := range infoRecordsByType {
130+
for _, infoRecord := range infoRecords {
131+
if infoRecord.IsTimelock() {
132+
timelockAccounts = append(timelockAccounts, infoRecord.TokenAccount)
133+
}
128134
}
129135
}
130136
}
@@ -134,32 +140,38 @@ func GetLatestTokenAccountRecordsForOwner(ctx context.Context, data code_data.Pr
134140
return nil, err
135141
}
136142

137-
for _, generalRecords := range infoRecordsByType {
138-
for _, generalRecord := range generalRecords {
139-
var timelockRecord *timelock.Record
140-
var ok bool
141-
if generalRecord.IsTimelock() {
142-
timelockRecord, ok = timelockRecordsByVault[generalRecord.TokenAccount]
143-
if !ok {
144-
return nil, errors.New("timelock record unexpectedly doesn't exist")
143+
for _, infoRecordsByType := range infoRecordsByMintAndType {
144+
for _, infoRecords := range infoRecordsByType {
145+
for _, infoRecord := range infoRecords {
146+
var timelockRecord *timelock.Record
147+
var ok bool
148+
if infoRecord.IsTimelock() {
149+
timelockRecord, ok = timelockRecordsByVault[infoRecord.TokenAccount]
150+
if !ok {
151+
return nil, errors.New("timelock record unexpectedly doesn't exist")
152+
}
145153
}
146-
}
147154

148-
// Filter out account records for accounts that have completed their
149-
// full lifecycle
150-
//
151-
// todo: This needs tests
152-
switch generalRecord.AccountType {
153-
case commonpb.AccountType_POOL:
154-
if timelockRecord.IsClosed() {
155-
continue
155+
// Filter out account records for accounts that have completed their
156+
// full lifecycle
157+
//
158+
// todo: This needs tests
159+
switch infoRecord.AccountType {
160+
case commonpb.AccountType_POOL:
161+
if timelockRecord.IsClosed() {
162+
continue
163+
}
156164
}
157-
}
158165

159-
res[generalRecord.AccountType] = append(res[generalRecord.AccountType], &AccountRecords{
160-
General: generalRecord,
161-
Timelock: timelockRecord,
162-
})
166+
if _, ok := res[infoRecord.MintAccount]; !ok {
167+
res[infoRecord.MintAccount] = make(map[commonpb.AccountType][]*AccountRecords)
168+
}
169+
170+
res[infoRecord.MintAccount][infoRecord.AccountType] = append(res[infoRecord.MintAccount][infoRecord.AccountType], &AccountRecords{
171+
General: infoRecord,
172+
Timelock: timelockRecord,
173+
})
174+
}
163175
}
164176
}
165177

@@ -168,18 +180,24 @@ func GetLatestTokenAccountRecordsForOwner(ctx context.Context, data code_data.Pr
168180

169181
// GetLatestCodeTimelockAccountRecordsForOwner is a utility wrapper over GetLatestTokenAccountRecordsForOwner
170182
// that filters for Code Timelock accounts.
171-
func GetLatestCodeTimelockAccountRecordsForOwner(ctx context.Context, data code_data.Provider, owner *Account) (map[commonpb.AccountType][]*AccountRecords, error) {
172-
res := make(map[commonpb.AccountType][]*AccountRecords)
183+
func GetLatestCodeTimelockAccountRecordsForOwner(ctx context.Context, data code_data.Provider, owner *Account) (map[string]map[commonpb.AccountType][]*AccountRecords, error) {
184+
res := make(map[string]map[commonpb.AccountType][]*AccountRecords)
173185

174-
recordsByType, err := GetLatestTokenAccountRecordsForOwner(ctx, data, owner)
186+
recordsByMintAndType, err := GetLatestTokenAccountRecordsForOwner(ctx, data, owner)
175187
if err != nil {
176188
return nil, err
177189
}
178190

179-
for _, recordsList := range recordsByType {
180-
for _, records := range recordsList {
181-
if records.IsTimelock() {
182-
res[records.General.AccountType] = append(res[records.General.AccountType], records)
191+
for _, recordsByType := range recordsByMintAndType {
192+
for _, recordsList := range recordsByType {
193+
for _, records := range recordsList {
194+
if records.IsTimelock() {
195+
if _, ok := res[records.General.MintAccount]; !ok {
196+
res[records.General.MintAccount] = make(map[commonpb.AccountType][]*AccountRecords)
197+
}
198+
199+
res[records.General.MintAccount][records.General.AccountType] = append(res[records.General.MintAccount][records.General.AccountType], records)
200+
}
183201
}
184202
}
185203
}

0 commit comments

Comments
 (0)