Skip to content

Commit

Permalink
services/horizon: Fix operations participants logic to include Invoke…
Browse files Browse the repository at this point in the history
…HostFunction operations
  • Loading branch information
urvisavla committed Jan 16, 2025
1 parent 2999e29 commit cc4fe9c
Show file tree
Hide file tree
Showing 6 changed files with 97 additions and 7 deletions.
2 changes: 1 addition & 1 deletion services/horizon/internal/ingest/processor_runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ func (s *ProcessorRunner) buildTransactionProcessor(ledgersProcessor *processors
processors.NewOperationProcessor(s.historyQ.NewOperationBatchInsertBuilder(), s.config.NetworkPassphrase),
tradeProcessor,
processors.NewParticipantsProcessor(accountLoader,
s.historyQ.NewTransactionParticipantsBatchInsertBuilder(), s.historyQ.NewOperationParticipantBatchInsertBuilder()),
s.historyQ.NewTransactionParticipantsBatchInsertBuilder(), s.historyQ.NewOperationParticipantBatchInsertBuilder(), s.config.NetworkPassphrase),
processors.NewTransactionProcessor(s.historyQ.NewTransactionBatchInsertBuilder(), s.config.SkipTxmeta),
processors.NewClaimableBalancesTransactionProcessor(cbLoader,
s.historyQ.NewTransactionClaimableBalanceBatchInsertBuilder(), s.historyQ.NewOperationClaimableBalanceBatchInsertBuilder()),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1047,7 +1047,68 @@ func (operation *transactionOperationWrapper) Participants() ([]xdr.AccountId, e
case xdr.OperationTypeLiquidityPoolWithdraw:
// the only direct participant is the source_account
case xdr.OperationTypeInvokeHostFunction:
// the only direct participant is the source_account
changes, err := operation.transaction.GetOperationChanges(operation.index)
if err != nil {
return participants, err
}

for _, change := range changes {
if change.Type == xdr.LedgerEntryTypeAccount || change.Type == xdr.LedgerEntryTypeTrustline {
var data xdr.LedgerEntryData
switch {
case change.Post != nil:
data = change.Post.Data
case change.Pre != nil:
data = change.Pre.Data
default:
log.Errorf("Change Type %s with no pre or post", change.Type.String())
continue
}

switch change.Type {
case xdr.LedgerEntryTypeAccount:
participants = append(participants, data.MustAccount().AccountId)
case xdr.LedgerEntryTypeTrustline:
participants = append(participants, data.MustTrustLine().AccountId)
}
}
}

diagnosticEvents, err := operation.transaction.GetDiagnosticEvents()
if err != nil {
return participants, err
}

for _, contractEvent := range filterEvents(diagnosticEvents) {
if sacEvent, err := contractevents.NewStellarAssetContractEvent(&contractEvent, operation.network); err == nil {
switch sacEvent.GetType() {
case contractevents.EventTypeTransfer:
transferEvt := sacEvent.(*contractevents.TransferEvent)
if from, err := xdr.AddressToAccountId(transferEvt.From); err == nil {
participants = append(participants, from)
}
if to, err := xdr.AddressToAccountId(transferEvt.To); err == nil {
participants = append(participants, to)
}
case contractevents.EventTypeMint:
mintEvt := sacEvent.(*contractevents.MintEvent)
if to, err := xdr.AddressToAccountId(mintEvt.To); err == nil {
participants = append(participants, to)
}
case contractevents.EventTypeClawback:
clawbackEvt := sacEvent.(*contractevents.ClawbackEvent)
if from, err := xdr.AddressToAccountId(clawbackEvt.From); err == nil {
participants = append(participants, from)
}
case contractevents.EventTypeBurn:
burnEvt := sacEvent.(*contractevents.BurnEvent)
if from, err := xdr.AddressToAccountId(burnEvt.From); err == nil {
participants = append(participants, from)
}
}
}
}

case xdr.OperationTypeExtendFootprintTtl:
// the only direct participant is the source_account
case xdr.OperationTypeRestoreFootprint:
Expand Down Expand Up @@ -1090,7 +1151,7 @@ func dedupeParticipants(in []xdr.AccountId) []xdr.AccountId {
}

// OperationsParticipants returns a map with all participants per operation
func operationsParticipants(transaction ingest.LedgerTransaction, sequence uint32) (map[int64][]xdr.AccountId, error) {
func operationsParticipants(transaction ingest.LedgerTransaction, sequence uint32, network string) (map[int64][]xdr.AccountId, error) {
participants := map[int64][]xdr.AccountId{}

for opi, op := range transaction.Envelope.Operations() {
Expand All @@ -1099,6 +1160,7 @@ func operationsParticipants(transaction ingest.LedgerTransaction, sequence uint3
transaction: transaction,
operation: op,
ledgerSequence: sequence,
network: network,
}

p, err := operation.Participants()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,21 @@ type ParticipantsProcessor struct {
accountLoader *history.AccountLoader
txBatch history.TransactionParticipantsBatchInsertBuilder
opBatch history.OperationParticipantBatchInsertBuilder
network string
}

func NewParticipantsProcessor(
accountLoader *history.AccountLoader,
txBatch history.TransactionParticipantsBatchInsertBuilder,
opBatch history.OperationParticipantBatchInsertBuilder,
network string,

) *ParticipantsProcessor {
return &ParticipantsProcessor{
accountLoader: accountLoader,
txBatch: txBatch,
opBatch: opBatch,
network: network,
}
}

Expand Down Expand Up @@ -129,7 +133,7 @@ func (p *ParticipantsProcessor) addOperationsParticipants(
sequence uint32,
transaction ingest.LedgerTransaction,
) error {
participants, err := operationsParticipants(transaction, sequence)
participants, err := operationsParticipants(transaction, sequence, p.network)
if err != nil {
return errors.Wrap(err, "could not determine operation participants")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ func (s *ParticipantsProcessorTestSuiteLedger) SetupTest() {
s.accountLoader,
s.mockBatchInsertBuilder,
s.mockOperationsBatchInsertBuilder,
networkPassphrase,
)

s.txs = []ingest.LedgerTransaction{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1104,7 +1104,7 @@ func TestOperationParticipants(t *testing.T) {
xdr.MustAddress("GDRW375MAYR46ODGF2WGANQC2RRZL7O246DYHHCGWTV2RE7IHE2QUQLD"),
xdr.MustAddress("GACAR2AEYEKITE2LKI5RMXF5MIVZ6Q7XILROGDT22O7JX4DSWFS7FDDP"),
}
participantsMap, err := operationsParticipants(transaction, sequence)
participantsMap, err := operationsParticipants(transaction, sequence, networkPassphrase)
tt.NoError(err)
tt.Len(participantsMap, 1)
for k, v := range participantsMap {
Expand Down
27 changes: 25 additions & 2 deletions services/horizon/internal/integration/sac_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ func TestContractMintToAccount(t *testing.T) {
itest.Master(),
mint(itest, issuer, asset, "20", accountAddressParam(recipient.GetAccountID())),
)

assertAccountInvokeHostFunctionOperation(itest, recipientKp.Address(), "", recipientKp.Address(), "20.0000000")
assertContainsBalance(itest, recipientKp, issuer, code, amount.MustParse("20"))
assertAssetStats(itest, assetStats{
code: code,
Expand Down Expand Up @@ -91,6 +91,7 @@ func TestContractMintToAccount(t *testing.T) {
itest.Master(),
transfer(itest, issuer, asset, "30", accountAddressParam(otherRecipient.GetAccountID())),
)
assertAccountInvokeHostFunctionOperation(itest, otherRecipientKp.Address(), issuer, otherRecipientKp.Address(), "30.0000000")
assertContainsBalance(itest, recipientKp, issuer, code, amount.MustParse("20"))
assertContainsBalance(itest, otherRecipientKp, issuer, code, amount.MustParse("30"))

Expand Down Expand Up @@ -548,7 +549,8 @@ func TestContractTransferBetweenAccounts(t *testing.T) {
recipientKp,
transfer(itest, recipientKp.Address(), asset, "30", accountAddressParam(otherRecipient.GetAccountID())),
)

assertAccountInvokeHostFunctionOperation(itest, recipientKp.Address(), recipientKp.Address(), otherRecipientKp.Address(), "30.0000000")
assertAccountInvokeHostFunctionOperation(itest, otherRecipientKp.Address(), recipientKp.Address(), otherRecipientKp.Address(), "30.0000000")
assertContainsBalance(itest, recipientKp, issuer, code, amount.MustParse("970"))
assertContainsBalance(itest, otherRecipientKp, issuer, code, amount.MustParse("30"))

Expand Down Expand Up @@ -641,6 +643,7 @@ func TestContractTransferBetweenAccountAndContract(t *testing.T) {
recipientKp,
transfer(itest, recipientKp.Address(), asset, "30", contractAddressParam(recipientContractID)),
)
assertAccountInvokeHostFunctionOperation(itest, recipientKp.Address(), recipientKp.Address(), strkeyRecipientContractID, "30.0000000")
assertContainsBalance(itest, recipientKp, issuer, code, amount.MustParse("970"))
assertContainsEffect(t, getTxEffects(itest, transferTx, asset),
effects.EffectAccountDebited, effects.EffectContractCredited)
Expand All @@ -663,6 +666,7 @@ func TestContractTransferBetweenAccountAndContract(t *testing.T) {
recipientKp,
transferFromContract(itest, recipientKp.Address(), asset, recipientContractID, recipientContractHash, "500", accountAddressParam(recipient.GetAccountID())),
)
assertAccountInvokeHostFunctionOperation(itest, recipientKp.Address(), strkeyRecipientContractID, recipientKp.Address(), "500.0000000")
assertContainsEffect(t, getTxEffects(itest, transferTx, asset),
effects.EffectContractDebited, effects.EffectAccountCredited)
assertContainsBalance(itest, recipientKp, issuer, code, amount.MustParse("1470"))
Expand Down Expand Up @@ -820,6 +824,7 @@ func TestContractBurnFromAccount(t *testing.T) {
recipientKp,
burn(itest, recipientKp.Address(), asset, "500"),
)
assertAccountInvokeHostFunctionOperation(itest, recipientKp.Address(), recipientKp.Address(), "", "500.0000000")

fx := getTxEffects(itest, burnTx, asset)
require.Len(t, fx, 1)
Expand Down Expand Up @@ -972,6 +977,7 @@ func TestContractClawbackFromAccount(t *testing.T) {
itest.Master(),
clawback(itest, issuer, asset, "1000", accountAddressParam(recipientKp.Address())),
)
assertAccountInvokeHostFunctionOperation(itest, recipientKp.Address(), recipientKp.Address(), "", "1000.0000000")

assertContainsEffect(t, getTxEffects(itest, clawTx, asset), effects.EffectAccountDebited)
assertContainsBalance(itest, recipientKp, issuer, code, 0)
Expand Down Expand Up @@ -1154,6 +1160,23 @@ func getTxEffects(itest *integration.Test, txHash string, asset xdr.Asset) []eff
return result
}

func assertAccountInvokeHostFunctionOperation(itest *integration.Test, account string, from string, to string, amount string) {
ops, err := itest.Client().Operations(horizonclient.OperationRequest{
ForAccount: account,
Limit: 1,
Order: "desc",
})

assert.NoError(itest.CurrentTest(), err)
result := ops.Embedded.Records[0]
assert.Equal(itest.CurrentTest(), result.GetType(), operations.TypeNames[xdr.OperationTypeInvokeHostFunction])
invokeHostFn := result.(operations.InvokeHostFunction)
assert.Equal(itest.CurrentTest(), invokeHostFn.Function, "HostFunctionTypeHostFunctionTypeInvokeContract")
assert.Equal(itest.CurrentTest(), to, invokeHostFn.AssetBalanceChanges[0].To)
assert.Equal(itest.CurrentTest(), from, invokeHostFn.AssetBalanceChanges[0].From)
assert.Equal(itest.CurrentTest(), amount, invokeHostFn.AssetBalanceChanges[0].Amount)
}

func assertEventPayments(itest *integration.Test, txHash string, asset xdr.Asset, from string, to string, evtType string, amount string) {
ops, err := itest.Client().Operations(horizonclient.OperationRequest{
ForTransaction: txHash,
Expand Down

0 comments on commit cc4fe9c

Please sign in to comment.