Skip to content

Commit

Permalink
services/horizon: Fix claimable balance query (#5200)
Browse files Browse the repository at this point in the history
* services/horizon: Fix claimable balance query
* Fix Soroban RPC image incompatibility
  • Loading branch information
urvisavla authored Feb 8, 2024
1 parent 098e686 commit 4ef82e9
Show file tree
Hide file tree
Showing 3 changed files with 187 additions and 5 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/horizon.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ jobs:
HORIZON_INTEGRATION_TESTS_CORE_MAX_SUPPORTED_PROTOCOL: ${{ matrix.protocol-version }}
PROTOCOL_20_CORE_DEBIAN_PKG_VERSION: 20.1.0-1656.114b833e7.focal
PROTOCOL_20_CORE_DOCKER_IMG: stellar/unsafe-stellar-core:20.1.0-1656.114b833e7.focal
PROTOCOL_20_SOROBAN_RPC_DOCKER_IMG: stellar/soroban-rpc:20.2.0
PROTOCOL_20_SOROBAN_RPC_DOCKER_IMG: stellar/soroban-rpc:20.2.0@sha256:2b1237a6ca43ea5768031d9ab442e4895d0ce5437b38cbfee4c8ab9237f231ae
PROTOCOL_19_CORE_DEBIAN_PKG_VERSION: 19.14.0-1500.5664eff4e.focal
PROTOCOL_19_CORE_DOCKER_IMG: stellar/stellar-core:19.14.0-1500.5664eff4e.focal
PGHOST: localhost
Expand Down
8 changes: 4 additions & 4 deletions services/horizon/internal/db2/history/claimable_balances.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,17 +67,17 @@ func applyClaimableBalancesQueriesCursor(sql sq.SelectBuilder, lCursor int64, rC
case db2.OrderAscending:
if hasPagedLimit {
sql = sql.
Where(sq.Expr("(last_modified_ledger, id) > (?, ?)", lCursor, rCursor))
Where(sq.Expr("(cb.last_modified_ledger, cb.id) > (?, ?)", lCursor, rCursor))

}
sql = sql.OrderBy("last_modified_ledger asc, id asc")
sql = sql.OrderBy("cb.last_modified_ledger asc, cb.id asc")
case db2.OrderDescending:
if hasPagedLimit {
sql = sql.
Where(sq.Expr("(last_modified_ledger, id) < (?, ?)", lCursor, rCursor))
Where(sq.Expr("(cb.last_modified_ledger, cb.id) < (?, ?)", lCursor, rCursor))
}

sql = sql.OrderBy("last_modified_ledger desc, id desc")
sql = sql.OrderBy("cb.last_modified_ledger desc, cb.id desc")
default:
return sql, errors.Errorf("invalid order: %s", order)
}
Expand Down
182 changes: 182 additions & 0 deletions services/horizon/internal/db2/history/claimable_balances_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,188 @@ func TestFindClaimableBalancesByDestination(t *testing.T) {
tt.Assert.Len(cbs, 1)
}

func TestFindClaimableBalancesByCursor(t *testing.T) {
tt := test.Start(t)
defer tt.Finish()
test.ResetHorizonDB(t, tt.HorizonDB)
q := &Q{tt.HorizonSession()}

tt.Assert.NoError(q.BeginTx(tt.Ctx, &sql.TxOptions{}))
defer func() {
_ = q.Rollback()
}()

balanceInsertBuilder := q.NewClaimableBalanceBatchInsertBuilder()
claimantsInsertBuilder := q.NewClaimableBalanceClaimantBatchInsertBuilder()

dest1 := "GC3C4AKRBQLHOJ45U4XG35ESVWRDECWO5XLDGYADO6DPR3L7KIDVUMML"
dest2 := "GBRPYHIL2CI3FNQ4BXLFMNDLFJUNPU2HY3ZMFSHONUCEOASW7QC7OX2H"

sponsor1 := "GA25GQLHJU3LPEJXEIAXK23AWEA5GWDUGRSHTQHDFT6HXHVMRULSQJUJ"
sponsor2 := "GBRPYHIL2CI3FNQ4BXLFMNDLFJUNPU2HY3ZMFSHONUCEOASW7QC7OX2H"

asset := xdr.MustNewCreditAsset("USD", dest1)
balanceID := xdr.ClaimableBalanceId{
Type: xdr.ClaimableBalanceIdTypeClaimableBalanceIdTypeV0,
V0: &xdr.Hash{1, 2, 3},
}
id, err := xdr.MarshalHex(balanceID)
tt.Assert.NoError(err)
cBalance := ClaimableBalance{
BalanceID: id,
Claimants: []Claimant{
{
Destination: dest1,
Predicate: xdr.ClaimPredicate{
Type: xdr.ClaimPredicateTypeClaimPredicateUnconditional,
},
},
},
Asset: asset,
LastModifiedLedger: 123,
Amount: 10,
Sponsor: null.StringFrom(sponsor1),
}

tt.Assert.NoError(balanceInsertBuilder.Add(cBalance))
tt.Assert.NoError(insertClaimants(claimantsInsertBuilder, cBalance))

balanceID = xdr.ClaimableBalanceId{
Type: xdr.ClaimableBalanceIdTypeClaimableBalanceIdTypeV0,
V0: &xdr.Hash{3, 2, 1},
}
id, err = xdr.MarshalHex(balanceID)
tt.Assert.NoError(err)
cBalance = ClaimableBalance{
BalanceID: id,
Claimants: []Claimant{
{
Destination: dest1,
Predicate: xdr.ClaimPredicate{
Type: xdr.ClaimPredicateTypeClaimPredicateUnconditional,
},
},
{
Destination: dest2,
Predicate: xdr.ClaimPredicate{
Type: xdr.ClaimPredicateTypeClaimPredicateUnconditional,
},
},
},
Asset: asset,
LastModifiedLedger: 300,
Amount: 10,
Sponsor: null.StringFrom(sponsor2),
}

tt.Assert.NoError(balanceInsertBuilder.Add(cBalance))
tt.Assert.NoError(insertClaimants(claimantsInsertBuilder, cBalance))

tt.Assert.NoError(claimantsInsertBuilder.Exec(tt.Ctx))
tt.Assert.NoError(balanceInsertBuilder.Exec(tt.Ctx))

query := ClaimableBalancesQuery{
PageQuery: db2.MustPageQuery("", false, "", 10),
}

cbs, err := q.GetClaimableBalances(tt.Ctx, query)
tt.Assert.NoError(err)
tt.Assert.Len(cbs, 2)

order := "" // default is "asc"
// this validates the cb query with claimant and cb.id/ledger cursor parameters
query.PageQuery = db2.MustPageQuery(fmt.Sprintf("%v-%s", 150, cbs[0].BalanceID), false, order, 10)
query.Claimant = xdr.MustAddressPtr(dest1)
cbs, err = q.GetClaimableBalances(tt.Ctx, query)
tt.Assert.NoError(err)
tt.Assert.Len(cbs, 1)
tt.Assert.Equal(dest2, cbs[0].Claimants[1].Destination)

// this validates the cb query with claimant, asset, sponsor and cb.id/ledger cursor parameters
query.PageQuery = db2.MustPageQuery(fmt.Sprintf("%v-%s", 150, cbs[0].BalanceID), false, order, 10)
query.Claimant = xdr.MustAddressPtr(dest1)
query.Asset = &asset
query.Sponsor = xdr.MustAddressPtr(sponsor2)

cbs, err = q.GetClaimableBalances(tt.Ctx, query)
tt.Assert.NoError(err)
tt.Assert.Len(cbs, 1)
tt.Assert.Equal(dest2, cbs[0].Claimants[1].Destination)

// this validates the cb query with no claimant, asset, sponsor and cb.id/ledger cursor parameters
query.PageQuery = db2.MustPageQuery(fmt.Sprintf("%v-%s", 150, cbs[0].BalanceID), false, order, 10)
query.Claimant = nil
query.Asset = &asset
query.Sponsor = xdr.MustAddressPtr(sponsor2)

cbs, err = q.GetClaimableBalances(tt.Ctx, query)
tt.Assert.NoError(err)
tt.Assert.Len(cbs, 1)
tt.Assert.Equal(dest2, cbs[0].Claimants[1].Destination)

order = "desc"
// claimant and cb.id/ledger cursor parameters
query.PageQuery = db2.MustPageQuery(fmt.Sprintf("%v-%s", 301, cbs[0].BalanceID), false, order, 10)
query.Claimant = xdr.MustAddressPtr(dest1)
cbs, err = q.GetClaimableBalances(tt.Ctx, query)
tt.Assert.NoError(err)
tt.Assert.Len(cbs, 1)
tt.Assert.Equal(dest2, cbs[0].Claimants[1].Destination)

// claimant, asset, sponsor and cb.id/ledger cursor parameters
query.PageQuery = db2.MustPageQuery(fmt.Sprintf("%v-%s", 301, cbs[0].BalanceID), false, order, 10)
query.Claimant = xdr.MustAddressPtr(dest1)
query.Asset = &asset
query.Sponsor = xdr.MustAddressPtr(sponsor2)

cbs, err = q.GetClaimableBalances(tt.Ctx, query)
tt.Assert.NoError(err)
tt.Assert.Len(cbs, 1)
tt.Assert.Equal(dest2, cbs[0].Claimants[1].Destination)

// no claimant, asset, sponsor and cb.id/ledger cursor parameters
query.PageQuery = db2.MustPageQuery(fmt.Sprintf("%v-%s", 301, cbs[0].BalanceID), false, order, 10)
query.Claimant = nil
query.Asset = &asset
query.Sponsor = xdr.MustAddressPtr(sponsor2)

cbs, err = q.GetClaimableBalances(tt.Ctx, query)
tt.Assert.NoError(err)
tt.Assert.Len(cbs, 1)
tt.Assert.Equal(dest2, cbs[0].Claimants[1].Destination)

order = "asc"
// claimant and cb.id/ledger cursor parameters
query.PageQuery = db2.MustPageQuery(fmt.Sprintf("%v-%s", 150, cbs[0].BalanceID), false, order, 10)
query.Claimant = xdr.MustAddressPtr(dest1)
cbs, err = q.GetClaimableBalances(tt.Ctx, query)
tt.Assert.NoError(err)
tt.Assert.Len(cbs, 1)
tt.Assert.Equal(dest2, cbs[0].Claimants[1].Destination)

// claimant, asset, sponsor and cb.id/ledger cursor parameters
query.PageQuery = db2.MustPageQuery(fmt.Sprintf("%v-%s", 150, cbs[0].BalanceID), false, order, 10)
query.Claimant = xdr.MustAddressPtr(dest1)
query.Asset = &asset
query.Sponsor = xdr.MustAddressPtr(sponsor2)

cbs, err = q.GetClaimableBalances(tt.Ctx, query)
tt.Assert.NoError(err)
tt.Assert.Len(cbs, 1)
tt.Assert.Equal(dest2, cbs[0].Claimants[1].Destination)

// no claimant, asset, sponsor and cb.id/ledger cursor parameters
query.PageQuery = db2.MustPageQuery(fmt.Sprintf("%v-%s", 150, cbs[0].BalanceID), false, order, 10)
query.Claimant = nil
query.Asset = &asset
query.Sponsor = xdr.MustAddressPtr(sponsor2)

cbs, err = q.GetClaimableBalances(tt.Ctx, query)
tt.Assert.NoError(err)
tt.Assert.Len(cbs, 1)
tt.Assert.Equal(dest2, cbs[0].Claimants[1].Destination)
}

func insertClaimants(claimantsInsertBuilder ClaimableBalanceClaimantBatchInsertBuilder, cBalance ClaimableBalance) error {
for _, claimant := range cBalance.Claimants {
claimant := ClaimableBalanceClaimant{
Expand Down

0 comments on commit 4ef82e9

Please sign in to comment.