From a11d444f7a0b70a11efae0ff181f1caad11abdd1 Mon Sep 17 00:00:00 2001 From: Alfonso Acosta Date: Mon, 24 May 2021 01:32:11 +0200 Subject: [PATCH] services/horizon: Add Muxed Account details to effect responses (#3610) --- protocols/horizon/effects/main.go | 6 +- services/horizon/internal/db2/history/main.go | 2 + .../ingest/processors/effects_processor.go | 216 +++++++++--------- .../processors/effects_processor_test.go | 24 +- .../internal/resourceadapter/effects.go | 18 +- .../internal/resourceadapter/effects_test.go | 43 ++++ 6 files changed, 196 insertions(+), 113 deletions(-) diff --git a/protocols/horizon/effects/main.go b/protocols/horizon/effects/main.go index 1e5cb54590..7a83e6e5a8 100644 --- a/protocols/horizon/effects/main.go +++ b/protocols/horizon/effects/main.go @@ -2,11 +2,11 @@ package effects import ( "encoding/json" - "github.com/stellar/go/xdr" "time" "github.com/stellar/go/protocols/horizon/base" "github.com/stellar/go/support/render/hal" + "github.com/stellar/go/xdr" ) // Peter 30-04-2019: this is copied from the history package "github.com/stellar/go/services/horizon/internal/db2/history" @@ -249,6 +249,8 @@ type Base struct { ID string `json:"id"` PT string `json:"paging_token"` Account string `json:"account"` + AccountMuxed string `json:"account_muxed,omitempty"` + AccountMuxedID uint64 `json:"account_muxed_id,omitempty"` Type string `json:"type"` TypeI int32 `json:"type_i"` LedgerCloseTime time.Time `json:"created_at"` @@ -382,6 +384,8 @@ type TrustlineDeauthorized struct { type Trade struct { Base Seller string `json:"seller"` + SellerMuxed string `json:"seller_muxed,omitempty"` + SellerMuxedID uint64 `json:"seller_muxed_id,omitempty"` OfferID int64 `json:"offer_id,string"` SoldAmount string `json:"sold_amount"` SoldAssetType string `json:"sold_asset_type"` diff --git a/services/horizon/internal/db2/history/main.go b/services/horizon/internal/db2/history/main.go index 9f488f1cde..beb4cf5a1b 100644 --- a/services/horizon/internal/db2/history/main.go +++ b/services/horizon/internal/db2/history/main.go @@ -427,6 +427,8 @@ type Effect struct { // when the effect type is trade type TradeEffectDetails struct { Seller string `json:"seller"` + SellerMuxed string `json:"seller_muxed,omitempty"` + SellerMuxedID uint64 `json:"seller_muxed_id,omitempty"` OfferID int64 `json:"offer_id"` SoldAmount string `json:"sold_amount"` SoldAssetType string `json:"sold_asset_type"` diff --git a/services/horizon/internal/ingest/processors/effects_processor.go b/services/horizon/internal/ingest/processors/effects_processor.go index 17ed9ff876..0f421d7607 100644 --- a/services/horizon/internal/ingest/processors/effects_processor.go +++ b/services/horizon/internal/ingest/processors/effects_processor.go @@ -234,9 +234,9 @@ type effectsWrapper struct { operation *transactionOperationWrapper } -func (e *effectsWrapper) add(address string, effectType history.EffectType, details map[string]interface{}) { +func (e *effectsWrapper) add(address *xdr.AccountId, effectType history.EffectType, details map[string]interface{}) { e.effects = append(e.effects, effect{ - address: address, + address: address.Address(), operationID: e.operation.ID(), effectType: effectType, order: uint32(len(e.effects) + 1), @@ -244,6 +244,16 @@ func (e *effectsWrapper) add(address string, effectType history.EffectType, deta }) } +func (e *effectsWrapper) addMuxed(address *xdr.MuxedAccount, effectType history.EffectType, details map[string]interface{}) { + if address.Type == xdr.CryptoKeyTypeKeyTypeMuxedEd25519 { + // We abuse the details to inject muxed-account information without changing the DB schema + details["account_muxed"] = address.Address() + details["account_muxed_id"] = uint64(address.Med25519.Id) + } + accID := address.ToAccountId() + e.add(&accID, effectType, details) +} + var sponsoringEffectsTable = map[xdr.LedgerEntryType]struct { created, updated, removed history.EffectType }{ @@ -312,12 +322,12 @@ func (e *effectsWrapper) addSignerSponsorshipEffects(change ingest.Change) { details["sponsor"] = post.Address() details["signer"] = signer srcAccount := change.Post.Data.MustAccount().AccountId - e.add(srcAccount.Address(), history.EffectSignerSponsorshipCreated, details) + e.add(&srcAccount, history.EffectSignerSponsorshipCreated, details) case !foundPost && foundPre: details["former_sponsor"] = pre.Address() details["signer"] = signer srcAccount := change.Pre.Data.MustAccount().AccountId - e.add(srcAccount.Address(), history.EffectSignerSponsorshipRemoved, details) + e.add(&srcAccount, history.EffectSignerSponsorshipRemoved, details) case foundPre && foundPost: formerSponsor := pre.Address() newSponsor := post.Address() @@ -329,7 +339,7 @@ func (e *effectsWrapper) addSignerSponsorshipEffects(change ingest.Change) { details["new_sponsor"] = newSponsor details["signer"] = signer srcAccount := change.Post.Data.MustAccount().AccountId - e.add(srcAccount.Address(), history.EffectSignerSponsorshipUpdated, details) + e.add(&srcAccount, history.EffectSignerSponsorshipUpdated, details) } } } @@ -366,7 +376,11 @@ func (e *effectsWrapper) addLedgerEntrySponsorshipEffects(change ingest.Change) return nil } - var accountAddress string + var ( + accountID *xdr.AccountId + muxedAccount *xdr.MuxedAccount + ) + var data xdr.LedgerEntryData if change.Post != nil { data = change.Post.Data @@ -376,17 +390,17 @@ func (e *effectsWrapper) addLedgerEntrySponsorshipEffects(change ingest.Change) switch change.Type { case xdr.LedgerEntryTypeAccount: - aid := data.MustAccount().AccountId - accountAddress = aid.Address() + a := data.MustAccount().AccountId + accountID = &a case xdr.LedgerEntryTypeTrustline: - aid := data.MustTrustLine().AccountId - accountAddress = aid.Address() + a := data.MustTrustLine().AccountId + accountID = &a details["asset"] = data.MustTrustLine().Asset.StringCanonical() case xdr.LedgerEntryTypeData: - accountAddress = e.operation.SourceAccount().Address() + muxedAccount = e.operation.SourceAccount() details["data_name"] = data.MustData().DataName case xdr.LedgerEntryTypeClaimableBalance: - accountAddress = e.operation.SourceAccount().Address() + muxedAccount = e.operation.SourceAccount() var err error details["balance_id"], err = xdr.MarshalHex(data.MustClaimableBalance().BalanceId) if err != nil { @@ -396,7 +410,12 @@ func (e *effectsWrapper) addLedgerEntrySponsorshipEffects(change ingest.Change) return errors.Errorf("invalid sponsorship ledger entry type %v", change.Type.String()) } - e.add(accountAddress, effectType, details) + if accountID != nil { + e.add(accountID, effectType, details) + } else { + e.addMuxed(muxedAccount, effectType, details) + } + return nil } @@ -404,15 +423,14 @@ func (e *effectsWrapper) addAccountCreatedEffects() { op := e.operation.operation.Body.MustCreateAccountOp() e.add( - op.Destination.Address(), + &op.Destination, history.EffectAccountCreated, map[string]interface{}{ "starting_balance": amount.String(op.StartingBalance), }, ) - accId := e.operation.SourceAccount().ToAccountId() - e.add( - accId.Address(), + e.addMuxed( + e.operation.SourceAccount(), history.EffectAccountDebited, map[string]interface{}{ "asset_type": "native", @@ -420,7 +438,7 @@ func (e *effectsWrapper) addAccountCreatedEffects() { }, ) e.add( - op.Destination.Address(), + &op.Destination, history.EffectSignerCreated, map[string]interface{}{ "public_key": op.Destination.Address(), @@ -435,15 +453,13 @@ func (e *effectsWrapper) addPaymentEffects() { details := map[string]interface{}{"amount": amount.String(op.Amount)} addAssetDetails(details, op.Asset, "") - aid := op.Destination.ToAccountId() - e.add( - aid.Address(), + e.addMuxed( + &op.Destination, history.EffectAccountCredited, details, ) - source := e.operation.SourceAccount().ToAccountId() - e.add( - source.Address(), + e.addMuxed( + e.operation.SourceAccount(), history.EffectAccountDebited, details, ) @@ -452,14 +468,13 @@ func (e *effectsWrapper) addPaymentEffects() { func (e *effectsWrapper) pathPaymentStrictReceiveEffects() { op := e.operation.operation.Body.MustPathPaymentStrictReceiveOp() resultSuccess := e.operation.OperationResult().MustPathPaymentStrictReceiveResult().MustSuccess() - source := e.operation.SourceAccount().ToAccountId() + source := e.operation.SourceAccount() details := map[string]interface{}{"amount": amount.String(op.DestAmount)} addAssetDetails(details, op.DestAsset, "") - aid := op.Destination.ToAccountId() - e.add( - aid.Address(), + e.addMuxed( + &op.Destination, history.EffectAccountCredited, details, ) @@ -468,48 +483,47 @@ func (e *effectsWrapper) pathPaymentStrictReceiveEffects() { details = map[string]interface{}{"amount": amount.String(result.SendAmount())} addAssetDetails(details, op.SendAsset, "") - e.add( - source.Address(), + e.addMuxed( + source, history.EffectAccountDebited, details, ) - e.addIngestTradeEffects(source, resultSuccess.Offers) + e.addIngestTradeEffects(*source, resultSuccess.Offers) } func (e *effectsWrapper) addPathPaymentStrictSendEffects() { - source := e.operation.SourceAccount().ToAccountId() + source := e.operation.SourceAccount() op := e.operation.operation.Body.MustPathPaymentStrictSendOp() resultSuccess := e.operation.OperationResult().MustPathPaymentStrictSendResult().MustSuccess() result := e.operation.OperationResult().MustPathPaymentStrictSendResult() details := map[string]interface{}{"amount": amount.String(result.DestAmount())} addAssetDetails(details, op.DestAsset, "") - aid := op.Destination.ToAccountId() - e.add(aid.Address(), history.EffectAccountCredited, details) + e.addMuxed(&op.Destination, history.EffectAccountCredited, details) details = map[string]interface{}{"amount": amount.String(op.SendAmount)} addAssetDetails(details, op.SendAsset, "") - e.add(source.Address(), history.EffectAccountDebited, details) + e.addMuxed(source, history.EffectAccountDebited, details) - e.addIngestTradeEffects(source, resultSuccess.Offers) + e.addIngestTradeEffects(*source, resultSuccess.Offers) } func (e *effectsWrapper) addManageSellOfferEffects() { - source := e.operation.SourceAccount().ToAccountId() + source := e.operation.SourceAccount() result := e.operation.OperationResult().MustManageSellOfferResult().MustSuccess() - e.addIngestTradeEffects(source, result.OffersClaimed) + e.addIngestTradeEffects(*source, result.OffersClaimed) } func (e *effectsWrapper) addManageBuyOfferEffects() { - source := e.operation.SourceAccount().ToAccountId() + source := e.operation.SourceAccount() result := e.operation.OperationResult().MustManageBuyOfferResult().MustSuccess() - e.addIngestTradeEffects(source, result.OffersClaimed) + e.addIngestTradeEffects(*source, result.OffersClaimed) } func (e *effectsWrapper) addCreatePassiveSellOfferEffect() { result := e.operation.OperationResult() - source := e.operation.SourceAccount().ToAccountId() + source := e.operation.SourceAccount() var claims []xdr.ClaimOfferAtom @@ -521,15 +535,15 @@ func (e *effectsWrapper) addCreatePassiveSellOfferEffect() { claims = result.MustCreatePassiveSellOfferResult().MustSuccess().OffersClaimed } - e.addIngestTradeEffects(source, claims) + e.addIngestTradeEffects(*source, claims) } func (e *effectsWrapper) addSetOptionsEffects() error { - source := e.operation.SourceAccount().ToAccountId() + source := e.operation.SourceAccount() op := e.operation.operation.Body.MustSetOptionsOp() if op.HomeDomain != nil { - e.add(source.Address(), history.EffectAccountHomeDomainUpdated, + e.addMuxed(source, history.EffectAccountHomeDomainUpdated, map[string]interface{}{ "home_domain": string(*op.HomeDomain), }, @@ -551,7 +565,7 @@ func (e *effectsWrapper) addSetOptionsEffects() error { } if len(thresholdDetails) > 0 { - e.add(source.Address(), history.EffectAccountThresholdsUpdated, thresholdDetails) + e.addMuxed(source, history.EffectAccountThresholdsUpdated, thresholdDetails) } flagDetails := map[string]interface{}{} @@ -563,11 +577,11 @@ func (e *effectsWrapper) addSetOptionsEffects() error { } if len(flagDetails) > 0 { - e.add(source.Address(), history.EffectAccountFlagsUpdated, flagDetails) + e.addMuxed(source, history.EffectAccountFlagsUpdated, flagDetails) } if op.InflationDest != nil { - e.add(source.Address(), history.EffectAccountInflationDestinationUpdated, + e.addMuxed(source, history.EffectAccountInflationDestinationUpdated, map[string]interface{}{ "inflation_destination": op.InflationDest.Address(), }, @@ -603,14 +617,14 @@ func (e *effectsWrapper) addSetOptionsEffects() error { for _, addy := range beforeSortedSigners { weight, ok := after[addy] if !ok { - e.add(source.Address(), history.EffectSignerRemoved, map[string]interface{}{ + e.addMuxed(source, history.EffectSignerRemoved, map[string]interface{}{ "public_key": addy, }) continue } if weight != before[addy] { - e.add(source.Address(), history.EffectSignerUpdated, map[string]interface{}{ + e.addMuxed(source, history.EffectSignerUpdated, map[string]interface{}{ "public_key": addy, "weight": weight, }) @@ -632,7 +646,7 @@ func (e *effectsWrapper) addSetOptionsEffects() error { continue } - e.add(source.Address(), history.EffectSignerCreated, map[string]interface{}{ + e.addMuxed(source, history.EffectSignerCreated, map[string]interface{}{ "public_key": addy, "weight": weight, }) @@ -642,7 +656,7 @@ func (e *effectsWrapper) addSetOptionsEffects() error { } func (e *effectsWrapper) addChangeTrustEffects() error { - source := e.operation.SourceAccount().ToAccountId() + source := e.operation.SourceAccount() op := e.operation.operation.Body.MustChangeTrustOp() changes, err := e.operation.transaction.GetOperationChanges(e.operation.index) @@ -676,15 +690,15 @@ func (e *effectsWrapper) addChangeTrustEffects() error { break } - e.add(source.Address(), effect, details) + e.addMuxed(source, effect, details) } return nil } func (e *effectsWrapper) addAllowTrustEffects() { - source := e.operation.SourceAccount().ToAccountId() + source := e.operation.SourceAccount() op := e.operation.operation.Body.MustAllowTrustOp() - asset := op.Asset.ToAsset(source) + asset := op.Asset.ToAsset(source.ToAccountId()) details := map[string]interface{}{ "trustor": op.Trustor.Address(), } @@ -692,29 +706,29 @@ func (e *effectsWrapper) addAllowTrustEffects() { switch { case xdr.TrustLineFlags(op.Authorize).IsAuthorized(): - e.add(source.Address(), history.EffectTrustlineAuthorized, details) + e.addMuxed(source, history.EffectTrustlineAuthorized, details) // Forward compatibility setFlags := xdr.Uint32(xdr.TrustLineFlagsAuthorizedFlag) - e.addTrustLineFlagsEffect(&source, &op.Trustor, asset, &setFlags, nil) + e.addTrustLineFlagsEffect(source, &op.Trustor, asset, &setFlags, nil) case xdr.TrustLineFlags(op.Authorize).IsAuthorizedToMaintainLiabilitiesFlag(): - e.add( - source.Address(), + e.addMuxed( + source, history.EffectTrustlineAuthorizedToMaintainLiabilities, details, ) // Forward compatibility setFlags := xdr.Uint32(xdr.TrustLineFlagsAuthorizedToMaintainLiabilitiesFlag) - e.addTrustLineFlagsEffect(&source, &op.Trustor, asset, &setFlags, nil) + e.addTrustLineFlagsEffect(source, &op.Trustor, asset, &setFlags, nil) default: - e.add(source.Address(), history.EffectTrustlineDeauthorized, details) + e.addMuxed(source, history.EffectTrustlineDeauthorized, details) // Forward compatibility, show both as cleared clearFlags := xdr.Uint32(xdr.TrustLineFlagsAuthorizedFlag | xdr.TrustLineFlagsAuthorizedToMaintainLiabilitiesFlag) - e.addTrustLineFlagsEffect(&source, &op.Trustor, asset, nil, &clearFlags) + e.addTrustLineFlagsEffect(source, &op.Trustor, asset, nil, &clearFlags) } } func (e *effectsWrapper) addAccountMergeEffects() { - source := e.operation.SourceAccount().ToAccountId() + source := e.operation.SourceAccount() dest := e.operation.operation.Body.MustDestination() result := e.operation.OperationResult().MustAccountMergeResult() @@ -723,16 +737,15 @@ func (e *effectsWrapper) addAccountMergeEffects() { "asset_type": "native", } - e.add(source.Address(), history.EffectAccountDebited, details) - aid := dest.ToAccountId() - e.add(aid.Address(), history.EffectAccountCredited, details) - e.add(source.Address(), history.EffectAccountRemoved, map[string]interface{}{}) + e.addMuxed(source, history.EffectAccountDebited, details) + e.addMuxed(&dest, history.EffectAccountCredited, details) + e.addMuxed(source, history.EffectAccountRemoved, map[string]interface{}{}) } func (e *effectsWrapper) addInflationEffects() { payouts := e.operation.OperationResult().MustInflationResult().MustPayouts() for _, payout := range payouts { - e.add(payout.Destination.Address(), history.EffectAccountCredited, + e.add(&payout.Destination, history.EffectAccountCredited, map[string]interface{}{ "amount": amount.String(payout.Amount), "asset_type": "native", @@ -742,7 +755,7 @@ func (e *effectsWrapper) addInflationEffects() { } func (e *effectsWrapper) addManageDataEffects() error { - source := e.operation.SourceAccount().ToAccountId() + source := e.operation.SourceAccount() op := e.operation.operation.Body.MustManageDataOp() details := map[string]interface{}{"name": op.DataName} effect := history.EffectType(0) @@ -778,12 +791,12 @@ func (e *effectsWrapper) addManageDataEffects() error { break } - e.add(source.Address(), effect, details) + e.addMuxed(source, effect, details) return nil } func (e *effectsWrapper) addBumpSequenceEffects() error { - source := e.operation.SourceAccount().ToAccountId() + source := e.operation.SourceAccount() changes, err := e.operation.transaction.GetOperationChanges(e.operation.index) if err != nil { return err @@ -802,7 +815,7 @@ func (e *effectsWrapper) addBumpSequenceEffects() error { if beforeAccount.SeqNum != afterAccount.SeqNum { details := map[string]interface{}{"new_seq": afterAccount.SeqNum} - e.add(source.Address(), history.EffectSequenceBumped, details) + e.addMuxed(source, history.EffectSequenceBumped, details) } break } @@ -839,8 +852,8 @@ func (e *effectsWrapper) addCreateClaimableBalanceEffects(changes []ingest.Chang break } source := e.operation.SourceAccount() - e.add( - source.Address(), + e.addMuxed( + source, history.EffectClaimableBalanceCreated, details, ) @@ -848,7 +861,7 @@ func (e *effectsWrapper) addCreateClaimableBalanceEffects(changes []ingest.Chang for _, c := range op.Claimants { cv0 := c.MustV0() e.add( - cv0.Destination.Address(), + &cv0.Destination, history.EffectClaimableBalanceClaimantCreated, map[string]interface{}{ "balance_id": balanceID, @@ -863,8 +876,8 @@ func (e *effectsWrapper) addCreateClaimableBalanceEffects(changes []ingest.Chang "amount": amount.String(op.Amount), } addAssetDetails(details, op.Asset, "") - e.add( - source.Address(), + e.addMuxed( + source, history.EffectAccountDebited, details, ) @@ -911,9 +924,9 @@ func (e *effectsWrapper) addClaimClaimableBalanceEffects(changes []ingest.Change "asset": cBalance.Asset.StringCanonical(), } setClaimableBalanceFlagDetails(details, cBalance.Flags()) - source := e.operation.SourceAccount().ToAccountId() - e.add( - source.Address(), + source := e.operation.SourceAccount() + e.addMuxed( + source, history.EffectClaimableBalanceClaimed, details, ) @@ -922,8 +935,8 @@ func (e *effectsWrapper) addClaimClaimableBalanceEffects(changes []ingest.Change "amount": amount.String(cBalance.Amount), } addAssetDetails(details, cBalance.Asset, "") - e.add( - source.Address(), + e.addMuxed( + source, history.EffectAccountCredited, details, ) @@ -931,7 +944,7 @@ func (e *effectsWrapper) addClaimClaimableBalanceEffects(changes []ingest.Change return nil } -func (e *effectsWrapper) addIngestTradeEffects(buyer xdr.AccountId, claims []xdr.ClaimOfferAtom) { +func (e *effectsWrapper) addIngestTradeEffects(buyer xdr.MuxedAccount, claims []xdr.ClaimOfferAtom) { for _, claim := range claims { if claim.AmountSold == 0 && claim.AmountBought == 0 { continue @@ -940,14 +953,14 @@ func (e *effectsWrapper) addIngestTradeEffects(buyer xdr.AccountId, claims []xdr seller := claim.SellerId bd, sd := tradeDetails(buyer, seller, claim) - e.add( - buyer.Address(), + e.addMuxed( + &buyer, history.EffectTrade, bd, ) e.add( - seller.Address(), + &seller, history.EffectTrade, sd, ) @@ -959,19 +972,18 @@ func (e *effectsWrapper) addClawbackEffects() error { details := map[string]interface{}{ "amount": amount.String(op.Amount), } - source := e.operation.SourceAccount().ToAccountId() + source := e.operation.SourceAccount() addAssetDetails(details, op.Asset, "") // The funds will be burned, but even with that, we generated an account credited effect - e.add( - source.Address(), + e.addMuxed( + source, history.EffectAccountCredited, details, ) - from := op.From.ToAccountId() - e.add( - from.Address(), + e.addMuxed( + &op.From, history.EffectAccountDebited, details, ) @@ -988,9 +1000,9 @@ func (e *effectsWrapper) addClawbackClaimableBalanceEffects(changes []ingest.Cha details := map[string]interface{}{ "balance_id": balanceId, } - source := e.operation.SourceAccount().ToAccountId() - e.add( - source.Address(), + source := e.operation.SourceAccount() + e.addMuxed( + source, history.EffectClaimableBalanceClawedBack, details, ) @@ -1001,8 +1013,8 @@ func (e *effectsWrapper) addClawbackClaimableBalanceEffects(changes []ingest.Cha cb := c.Pre.Data.ClaimableBalance details = map[string]interface{}{"amount": amount.String(cb.Amount)} addAssetDetails(details, cb.Asset, "") - e.add( - source.Address(), + e.addMuxed( + source, history.EffectAccountCredited, details, ) @@ -1014,14 +1026,14 @@ func (e *effectsWrapper) addClawbackClaimableBalanceEffects(changes []ingest.Cha } func (e *effectsWrapper) addSetTrustLineFlagsEffects() error { - source := e.operation.SourceAccount().ToAccountId() + source := e.operation.SourceAccount() op := e.operation.operation.Body.MustSetTrustLineFlagsOp() - e.addTrustLineFlagsEffect(&source, &op.Trustor, op.Asset, &op.SetFlags, &op.ClearFlags) + e.addTrustLineFlagsEffect(source, &op.Trustor, op.Asset, &op.SetFlags, &op.ClearFlags) return nil } func (e *effectsWrapper) addTrustLineFlagsEffect( - account *xdr.AccountId, + account *xdr.MuxedAccount, trustor *xdr.AccountId, asset xdr.Asset, setFlags *xdr.Uint32, @@ -1042,7 +1054,7 @@ func (e *effectsWrapper) addTrustLineFlagsEffect( } if flagDetailsAdded { - e.add(account.Address(), history.EffectTrustlineFlagsUpdated, details) + e.addMuxed(account, history.EffectTrustlineFlagsUpdated, details) } } @@ -1073,7 +1085,7 @@ func setAuthFlagDetails(flagDetails map[string]interface{}, flags xdr.AccountFla } } -func tradeDetails(buyer, seller xdr.AccountId, claim xdr.ClaimOfferAtom) (bd map[string]interface{}, sd map[string]interface{}) { +func tradeDetails(buyer xdr.MuxedAccount, seller xdr.AccountId, claim xdr.ClaimOfferAtom) (bd map[string]interface{}, sd map[string]interface{}) { bd = map[string]interface{}{ "offer_id": claim.OfferId, "seller": seller.Address(), @@ -1085,10 +1097,10 @@ func tradeDetails(buyer, seller xdr.AccountId, claim xdr.ClaimOfferAtom) (bd map sd = map[string]interface{}{ "offer_id": claim.OfferId, - "seller": buyer.Address(), "bought_amount": amount.String(claim.AmountBought), "sold_amount": amount.String(claim.AmountSold), } + addAccountAndMuxedAccountDetails(sd, buyer, "seller") addAssetDetails(sd, claim.AssetBought, "bought_") addAssetDetails(sd, claim.AssetSold, "sold_") diff --git a/services/horizon/internal/ingest/processors/effects_processor_test.go b/services/horizon/internal/ingest/processors/effects_processor_test.go index 0b0da1049f..3d2916a129 100644 --- a/services/horizon/internal/ingest/processors/effects_processor_test.go +++ b/services/horizon/internal/ingest/processors/effects_processor_test.go @@ -946,10 +946,12 @@ func TestOperationEffects(t *testing.T) { { address: "GDEOVUDLCYTO46D6GD6WH7BFESPBV5RACC6F6NUFCIRU7PL2XONQHVGJ", details: map[string]interface{}{ - "amount": "1.0000000", - "asset_code": "ARS", - "asset_type": "credit_alphanum4", - "asset_issuer": "GCXI6Q73J7F6EUSBZTPW4G4OUGVDHABPYF2U4KO7MVEX52OH5VMVUCRF", + "account_muxed": "MDEOVUDLCYTO46D6GD6WH7BFESPBV5RACC6F6NUFCIRU7PL2XONQGAAAAAAMV7V2X24II", + "account_muxed_id": uint64(0xcafebabe), + "amount": "1.0000000", + "asset_code": "ARS", + "asset_type": "credit_alphanum4", + "asset_issuer": "GCXI6Q73J7F6EUSBZTPW4G4OUGVDHABPYF2U4KO7MVEX52OH5VMVUCRF", }, effectType: history.EffectAccountCredited, operationID: int64(85899350017), @@ -958,10 +960,12 @@ func TestOperationEffects(t *testing.T) { { address: "GD3MMHD2YZWL5RAUWG6O3RMA5HTZYM7S3JLSZ2Z35JNJAWTDIKXY737V", details: map[string]interface{}{ - "amount": "0.0300000", - "asset_code": "BRL", - "asset_type": "credit_alphanum4", - "asset_issuer": "GCXI6Q73J7F6EUSBZTPW4G4OUGVDHABPYF2U4KO7MVEX52OH5VMVUCRF", + "account_muxed": "MD3MMHD2YZWL5RAUWG6O3RMA5HTZYM7S3JLSZ2Z35JNJAWTDIKXY6AAAAAAMV7V2XZY4C", + "account_muxed_id": uint64(0xcafebabe), + "amount": "0.0300000", + "asset_code": "BRL", + "asset_type": "credit_alphanum4", + "asset_issuer": "GCXI6Q73J7F6EUSBZTPW4G4OUGVDHABPYF2U4KO7MVEX52OH5VMVUCRF", }, effectType: history.EffectAccountDebited, operationID: int64(85899350017), @@ -970,6 +974,8 @@ func TestOperationEffects(t *testing.T) { { address: "GD3MMHD2YZWL5RAUWG6O3RMA5HTZYM7S3JLSZ2Z35JNJAWTDIKXY737V", details: map[string]interface{}{ + "account_muxed": "MD3MMHD2YZWL5RAUWG6O3RMA5HTZYM7S3JLSZ2Z35JNJAWTDIKXY6AAAAAAMV7V2XZY4C", + "account_muxed_id": uint64(0xcafebabe), "seller": "GDEOVUDLCYTO46D6GD6WH7BFESPBV5RACC6F6NUFCIRU7PL2XONQHVGJ", "offer_id": xdr.Int64(10072128), "sold_amount": "0.0300000", @@ -989,6 +995,8 @@ func TestOperationEffects(t *testing.T) { address: "GDEOVUDLCYTO46D6GD6WH7BFESPBV5RACC6F6NUFCIRU7PL2XONQHVGJ", details: map[string]interface{}{ "seller": "GD3MMHD2YZWL5RAUWG6O3RMA5HTZYM7S3JLSZ2Z35JNJAWTDIKXY737V", + "seller_muxed": "MD3MMHD2YZWL5RAUWG6O3RMA5HTZYM7S3JLSZ2Z35JNJAWTDIKXY6AAAAAAMV7V2XZY4C", + "seller_muxed_id": uint64(0xcafebabe), "offer_id": xdr.Int64(10072128), "sold_amount": "1.0000000", "bought_amount": "0.0300000", diff --git a/services/horizon/internal/resourceadapter/effects.go b/services/horizon/internal/resourceadapter/effects.go index ab9fdc9867..7789372f09 100644 --- a/services/horizon/internal/resourceadapter/effects.go +++ b/services/horizon/internal/resourceadapter/effects.go @@ -59,6 +59,11 @@ var EffectTypeNames = map[history.EffectType]string{ history.EffectClaimableBalanceClawedBack: "claimable_balance_clawed_back", } +type muxedAccount struct { + AccountMuxed string `json:"account_muxed"` + AccountMuxedID uint64 `json:"account_muxed_id"` +} + // NewEffect creates a new effect resource from the provided database representation // of the effect. func NewEffect( @@ -68,7 +73,12 @@ func NewEffect( ) (result hal.Pageable, err error) { basev := effects.Base{} - PopulateBaseEffect(ctx, &basev, row, ledger) + var mAccount muxedAccount + // We abuse the details to inject muxed-account information without changing the DB schema + if err = row.UnmarshalDetails(&mAccount); err != nil { + return + } + PopulateBaseEffect(ctx, &basev, mAccount, row, ledger) switch row.Type { case history.EffectAccountCreated: @@ -141,6 +151,8 @@ func NewEffect( err = row.UnmarshalDetails(&tradeDetails) if err == nil { e.Seller = tradeDetails.Seller + e.SellerMuxed = tradeDetails.SellerMuxed + e.SellerMuxedID = tradeDetails.SellerMuxedID e.OfferID = tradeDetails.OfferID e.SoldAmount = tradeDetails.SoldAmount e.SoldAssetType = tradeDetails.SoldAssetType @@ -269,10 +281,12 @@ func NewEffect( } // Populate loads this resource from `row` -func PopulateBaseEffect(ctx context.Context, this *effects.Base, row history.Effect, ledger history.Ledger) { +func PopulateBaseEffect(ctx context.Context, this *effects.Base, account muxedAccount, row history.Effect, ledger history.Ledger) { this.ID = row.ID() this.PT = row.PagingToken() this.Account = row.Account + this.AccountMuxed = account.AccountMuxed + this.AccountMuxedID = account.AccountMuxedID populateEffectType(this, row) this.LedgerCloseTime = ledger.ClosedAt diff --git a/services/horizon/internal/resourceadapter/effects_test.go b/services/horizon/internal/resourceadapter/effects_test.go index 3e95a329bd..1793507c4d 100644 --- a/services/horizon/internal/resourceadapter/effects_test.go +++ b/services/horizon/internal/resourceadapter/effects_test.go @@ -88,3 +88,46 @@ func TestNewEffect_EffectTrustlineAuthorizedToMaintainLiabilities(t *testing.T) tt.Len(page.Embedded.Records, 1) tt.Equal(effect, page.Embedded.Records[0].(effects.TrustlineAuthorizedToMaintainLiabilities)) } + +func TestNewEffect_EffectTrade_Muxed(t *testing.T) { + tt := assert.New(t) + ctx, _ := test.ContextWithLogBuffer() + + details := `{ + "seller": "GAQAA5L65LSYH7CQ3VTJ7F3HHLGCL3DSLAR2Y47263D56MNNGHSQSTVY", + "seller_muxed": "MAQAA5L65LSYH7CQ3VTJ7F3HHLGCL3DSLAR2Y47263D56MNNGHSQSAAAAAAAAAAE2LP26", + "seller_muxed_id": 1234, + "account_muxed": "MA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJUAAAAAAAAAAAACJUQ" + }` + + hEffect := history.Effect{ + Account: "GA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJVSGZ", + HistoryOperationID: 1, + Order: 1, + Type: history.EffectTrade, + DetailsString: null.StringFrom(details), + } + resource, err := NewEffect(ctx, hEffect, history.Ledger{}) + tt.NoError(err) + + var resourcePage hal.Page + resourcePage.Add(resource) + + effect, ok := resource.(effects.Trade) + tt.True(ok) + tt.Equal("trade", effect.Type) + + binary, err := json.Marshal(resourcePage) + tt.NoError(err) + + var page effects.EffectsPage + tt.NoError(json.Unmarshal(binary, &page)) + tt.Len(page.Embedded.Records, 1) + tt.Equal(effect, page.Embedded.Records[0].(effects.Trade)) + tt.Equal("GA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJVSGZ", effect.Account) + tt.Equal("MA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJUAAAAAAAAAAAACJUQ", effect.AccountMuxed) + tt.Equal(uint64(0), effect.AccountMuxedID) + tt.Equal("GAQAA5L65LSYH7CQ3VTJ7F3HHLGCL3DSLAR2Y47263D56MNNGHSQSTVY", effect.Seller) + tt.Equal("MAQAA5L65LSYH7CQ3VTJ7F3HHLGCL3DSLAR2Y47263D56MNNGHSQSAAAAAAAAAAE2LP26", effect.SellerMuxed) + tt.Equal(uint64(1234), effect.SellerMuxedID) +}