Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions server/services/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"time"

"github.com/multiversx/mx-chain-core-go/core"
vmcommon "github.com/multiversx/mx-chain-vm-common-go"
)

var (
Expand Down Expand Up @@ -48,9 +49,15 @@ const (

transactionEventDataExecuteOnDestContext = "ExecuteOnDestContext"
transactionEventDataAsyncCall = "AsyncCall"
transactionEventDataAsyncCallback = "AsyncCallback"
transactionEventDataTransferAndExecute = "TransferAndExecute"
)

const (
errorCodeUserError = int(vmcommon.UserError)
numElementsInAdditionalDataAsyncCallbackWithError = 4
)

const (
numTopicsOfEventESDTTransfer = 4
numTopicsPerTransferOfEventMultiESDTNFTTransfer = 3
Expand Down
229 changes: 229 additions & 0 deletions server/services/testdata/blocks_with_esdt_transfer_and_error.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,229 @@
[
{
"comment": "block with ESDT transfer (fungible) and error",
"miniBlocks": [
{
"hash": "25906b7e92179c39a494a680ae771aae9db6bb60f489edde5ce158e71ed72046",
"type": "TxBlock",
"processingType": "Normal",
"constructionState": "Final",
"sourceShard": 1,
"destinationShard": 1,
"transactions": [
{
"type": "normal",
"processingTypeOnSource": "BuiltInFunctionCall",
"processingTypeOnDestination": "SCInvoking",
"hash": "dd59dbfb06682d18a8a8571dd7039d388ee0f44ba6438022426ba4f0a6abf319",
"nonce": 1051,
"round": 29791109,
"epoch": 2068,
"value": "0",
"receiver": "erd1qqqqqqqqqqqqqpgq4eehfw7kfnc8x9cf9nfejgmtknuz6kygx7tsvhn3uc",
"sender": "erd1g4sw9ylunfgtj03vt8kvjc0kxg8m6cue32pcwh6nsyvqqnlkx7ts272l67",
"gasPrice": 1000000000,
"gasLimit": 25000000,
"data": "RVNEVFRyYW5zZmVyQDU3NDU0NzRjNDQyZDYyNjQzNDY0MzczOUA4YWM3MjMwNDg5ZTgwMDAwQDY1Nzg2NTYzNzU3NDY1NDE3MjYyNjk3NDcyNjE2NzY1QDdmZDNiZGQyMDI0MjdjMDBANTg0NTQ3NGM0NDJkNjUzNDMxMzM2NTY0",
"signature": "523b11c9ad97873ca5ad8201322af26a065feac5368ab3011f74647469f5edb720e993d181fd9abca18c183b4d88793c4d395e30551fd173005a6fe419b0240c",
"sourceShard": 1,
"destinationShard": 1,
"miniblockType": "TxBlock",
"miniblockHash": "25906b7e92179c39a494a680ae771aae9db6bb60f489edde5ce158e71ed72046",
"logs": {
"address": "erd1qqqqqqqqqqqqqpgq4eehfw7kfnc8x9cf9nfejgmtknuz6kygx7tsvhn3uc",
"events": [
{
"address": "erd1g4sw9ylunfgtj03vt8kvjc0kxg8m6cue32pcwh6nsyvqqnlkx7ts272l67",
"identifier": "ESDTTransfer",
"topics": [
"V0VHTEQtYmQ0ZDc5",
"",
"iscjBInoAAA=",
"AAAAAAAAAAAFAK5zdLvWTPBzFwks05kja7T4LViIN5c="
],
"data": null,
"additionalData": [
"",
"RVNEVFRyYW5zZmVy",
"V0VHTEQtYmQ0ZDc5",
"iscjBInoAAA=",
"ZXhlY3V0ZUFyYml0cmFnZQ==",
"f9O90gJCfAA=",
"WEVHTEQtZTQxM2Vk"
]
},
{
"address": "erd1qqqqqqqqqqqqqpgq4eehfw7kfnc8x9cf9nfejgmtknuz6kygx7tsvhn3uc",
"identifier": "ESDTTransfer",
"topics": [
"V0VHTEQtYmQ0ZDc5",
"",
"iscjBInoAAA=",
"AAAAAAAAAAAFAGyiHzN/2mg3jFVMfE9AtTqQDqGRVIM="
],
"data": "QXN5bmNDYWxs",
"additionalData": [
"QXN5bmNDYWxs",
"RVNEVFRyYW5zZmVy",
"V0VHTEQtYmQ0ZDc5",
"iscjBInoAAA=",
"c3dhcFRva2Vuc0ZpeGVkSW5wdXQ=",
"WEVHTEQtZTQxM2Vk",
"f9O90gJCfAA="
]
},
{
"address": "erd1qqqqqqqqqqqqqpgqdj3p7vmlmf5r0rz4f37y7s9482gqagv32jpsj8g69g",
"identifier": "transferValueOnly",
"topics": [
"",
"AAAAAAAAAAAFAK5zdLvWTPBzFwks05kja7T4LViIN5c="
],
"data": "QXN5bmNDYWxsYmFjaw==",
"additionalData": [
"QXN5bmNDYWxsYmFjaw==",
"Y2FsbEJhY2s=",
"BA==",
"U2xpcHBhZ2UgZXhjZWVkZWQ="
]
},
{
"address": "erd1g4sw9ylunfgtj03vt8kvjc0kxg8m6cue32pcwh6nsyvqqnlkx7ts272l67",
"identifier": "internalVMErrors",
"topics": [
"AAAAAAAAAAAFAK5zdLvWTPBzFwks05kja7T4LViIN5c=",
"ZXhlY3V0ZUFyYml0cmFnZQ=="
],
"data": "CglydW50aW1lLmdvOjg0NCBbZXJyb3Igc2lnbmFsbGVkIGJ5IHNtYXJ0Y29udHJhY3RdIFtzd2FwVG9rZW5zRml4ZWRJbnB1dF0KCXJ1bnRpbWUuZ286ODQ0IFtlcnJvciBzaWduYWxsZWQgYnkgc21hcnRjb250cmFjdF0gW3N3YXBUb2tlbnNGaXhlZElucHV0XQoJcnVudGltZS5nbzo4NDQgW2Vycm9yIHNpZ25hbGxlZCBieSBzbWFydGNvbnRyYWN0XSBbc3dhcFRva2Vuc0ZpeGVkSW5wdXRdCglydW50aW1lLmdvOjg0MSBbU2xpcHBhZ2UgZXhjZWVkZWRd",
"additionalData": [
"CglydW50aW1lLmdvOjg0NCBbZXJyb3Igc2lnbmFsbGVkIGJ5IHNtYXJ0Y29udHJhY3RdIFtzd2FwVG9rZW5zRml4ZWRJbnB1dF0KCXJ1bnRpbWUuZ286ODQ0IFtlcnJvciBzaWduYWxsZWQgYnkgc21hcnRjb250cmFjdF0gW3N3YXBUb2tlbnNGaXhlZElucHV0XQoJcnVudGltZS5nbzo4NDQgW2Vycm9yIHNpZ25hbGxlZCBieSBzbWFydGNvbnRyYWN0XSBbc3dhcFRva2Vuc0ZpeGVkSW5wdXRdCglydW50aW1lLmdvOjg0MSBbU2xpcHBhZ2UgZXhjZWVkZWRd"
]
},
{
"address": "erd1qqqqqqqqqqqqqpgq4eehfw7kfnc8x9cf9nfejgmtknuz6kygx7tsvhn3uc",
"identifier": "completedTxEvent",
"topics": [
"3Vnb+wZoLRioqFcd1wOdOI7g9EumQ4AiQmuk8Kar8xk="
],
"data": null,
"additionalData": null
}
]
},
"status": "success",
"tokens": [
"WEGLD-bd4d79"
],
"esdtValues": [
"10000000000000000000"
],
"operation": "ESDTTransfer",
"function": "executeArbitrage",
"initiallyPaidFee": "491065000000000",
"chainID": "1",
"version": 2,
"options": 0
}
],
"indexOfFirstTxProcessed": 0,
"indexOfLastTxProcessed": 39
},
{
"hash": "9ffbaf706ac92b240eecc2934a8f7449093a5472db6b8010dfb48821028557f1",
"type": "SmartContractResultBlock",
"processingType": "Normal",
"isFromReceiptsStorage": true,
"sourceShard": 1,
"destinationShard": 1,
"transactions": [
{
"type": "unsigned",
"processingTypeOnSource": "SCInvoking",
"processingTypeOnDestination": "SCInvoking",
"hash": "0be42df46e8908ad15431c7c88367c751534d95a9e2002c8572f2776a278e43d",
"nonce": 0,
"round": 29791109,
"epoch": 2068,
"value": "0",
"receiver": "erd1qqqqqqqqqqqqqpgq4eehfw7kfnc8x9cf9nfejgmtknuz6kygx7tsvhn3uc",
"sender": "erd1g4sw9ylunfgtj03vt8kvjc0kxg8m6cue32pcwh6nsyvqqnlkx7ts272l67",
"gasPrice": 1000000000,
"gasLimit": 24556500,
"data": "ZXhlY3V0ZUFyYml0cmFnZUA3ZmQzYmRkMjAyNDI3YzAwQDU4NDU0NzRjNDQyZDY1MzQzMTMzNjU2NA==",
"previousTransactionHash": "dd59dbfb06682d18a8a8571dd7039d388ee0f44ba6438022426ba4f0a6abf319",
"originalTransactionHash": "dd59dbfb06682d18a8a8571dd7039d388ee0f44ba6438022426ba4f0a6abf319",
"originalSender": "erd1g4sw9ylunfgtj03vt8kvjc0kxg8m6cue32pcwh6nsyvqqnlkx7ts272l67",
"sourceShard": 1,
"destinationShard": 1,
"miniblockType": "SmartContractResultBlock",
"miniblockHash": "9ffbaf706ac92b240eecc2934a8f7449093a5472db6b8010dfb48821028557f1",
"status": "success",
"operation": "transfer",
"function": "executeArbitrage",
"callType": "directCall",
"options": 0
},
{
"type": "unsigned",
"processingTypeOnSource": "BuiltInFunctionCall",
"processingTypeOnDestination": "SCInvoking",
"hash": "751e080418ec1284a0372883c97f0a6f20f422ddbf69b52db9e75930dc03fdf4",
"nonce": 0,
"round": 29791109,
"epoch": 2068,
"value": "0",
"receiver": "erd1qqqqqqqqqqqqqpgqdj3p7vmlmf5r0rz4f37y7s9482gqagv32jpsj8g69g",
"sender": "erd1qqqqqqqqqqqqqpgq4eehfw7kfnc8x9cf9nfejgmtknuz6kygx7tsvhn3uc",
"gasPrice": 1000000000,
"data": "RVNEVFRyYW5zZmVyQDU3NDU0NzRjNDQyZDYyNjQzNDY0MzczOUA4YWM3MjMwNDg5ZTgwMDAwQDczNzc2MTcwNTQ2ZjZiNjU2ZTczNDY2OTc4NjU2NDQ5NmU3MDc1NzRANTg0NTQ3NGM0NDJkNjUzNDMxMzM2NTY0QDdmZDNiZGQyMDI0MjdjMDBAMzZjOGRhZTk0Yzc0NjNmYzk4ZjRhNTYxMzExNDBlZDI1ODFkNWJiMjcwNzgwNGQ2MGNkZGVkODE1YjhjYjUyM0BkZDU5ZGJmYjA2NjgyZDE4YThhODU3MWRkNzAzOWQzODhlZTBmNDRiYTY0MzgwMjI0MjZiYTRmMGE2YWJmMzE5",
"previousTransactionHash": "dd59dbfb06682d18a8a8571dd7039d388ee0f44ba6438022426ba4f0a6abf319",
"originalTransactionHash": "dd59dbfb06682d18a8a8571dd7039d388ee0f44ba6438022426ba4f0a6abf319",
"originalSender": "erd1g4sw9ylunfgtj03vt8kvjc0kxg8m6cue32pcwh6nsyvqqnlkx7ts272l67",
"sourceShard": 1,
"destinationShard": 1,
"miniblockType": "SmartContractResultBlock",
"miniblockHash": "9ffbaf706ac92b240eecc2934a8f7449093a5472db6b8010dfb48821028557f1",
"status": "success",
"tokens": [
"WEGLD-bd4d79"
],
"esdtValues": [
"10000000000000000000"
],
"operation": "ESDTTransfer",
"function": "swapTokensFixedInput",
"callType": "asynchronousCall",
"options": 0
},
{
"type": "unsigned",
"processingTypeOnSource": "MoveBalance",
"processingTypeOnDestination": "MoveBalance",
"hash": "ed0412c3ae465216c50d60c30fb37cdfa61520ff773193fee457405f68c4a07a",
"nonce": 1052,
"round": 29791109,
"epoch": 2068,
"value": "29655420000000",
"receiver": "erd1g4sw9ylunfgtj03vt8kvjc0kxg8m6cue32pcwh6nsyvqqnlkx7ts272l67",
"sender": "erd1qqqqqqqqqqqqqpgq4eehfw7kfnc8x9cf9nfejgmtknuz6kygx7tsvhn3uc",
"gasPrice": 1000000000,
"data": "QDZmNmI=",
"previousTransactionHash": "dd59dbfb06682d18a8a8571dd7039d388ee0f44ba6438022426ba4f0a6abf319",
"originalTransactionHash": "dd59dbfb06682d18a8a8571dd7039d388ee0f44ba6438022426ba4f0a6abf319",
"sourceShard": 1,
"destinationShard": 1,
"miniblockType": "SmartContractResultBlock",
"miniblockHash": "9ffbaf706ac92b240eecc2934a8f7449093a5472db6b8010dfb48821028557f1",
"status": "success",
"operation": "transfer",
"isRefund": true,
"callType": "directCall",
"options": 0
}
],
"indexOfFirstTxProcessed": 0,
"indexOfLastTxProcessed": 0
}
]
}
]
8 changes: 5 additions & 3 deletions server/services/transactionEvents.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@ import (
)

type eventTransferValueOnly struct {
sender string
receiver string
value string
sender string
receiver string
value string
asyncCallbackWithError bool

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Name can have prefix is.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

}

type eventESDT struct {
Expand All @@ -18,6 +19,7 @@ type eventESDT struct {
identifier string
nonceAsBytes []byte
value string
asyncCall bool

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Name can have prefix is.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

}

// newEventESDTFromBasicTopics creates an eventESDT from the given topics. The following topics are expected:
Expand Down
63 changes: 60 additions & 3 deletions server/services/transactionEventsController.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,22 @@ func (controller *transactionEventsController) extractEventSCDeploy(tx *transact
}

func (controller *transactionEventsController) extractEventTransferValueOnly(tx *transaction.ApiTransactionResult) ([]*eventTransferValueOnly, error) {
return controller.extractEventTransferValueWithDecideFunction(tx, controller.decideEffectiveEventTransferValueOnlyAfterSirius)
}

func (controller *transactionEventsController) extractEventTransferValueWithAsyncCallbackUserError(tx *transaction.ApiTransactionResult) ([]*eventTransferValueOnly, error) {
return controller.extractEventTransferValueWithDecideFunction(tx, controller.decideEffectiveEventTransferValueWithAsyncCallbackAndUserError)
}

func (controller *transactionEventsController) extractEventTransferValueWithDecideFunction(
tx *transaction.ApiTransactionResult,
decide func(event *transaction.Events) (*eventTransferValueOnly, error),
) ([]*eventTransferValueOnly, error) {
rawEvents := controller.findManyEventsByIdentifier(tx, transactionEventTransferValueOnly)
typedEvents := make([]*eventTransferValueOnly, 0)

for _, event := range rawEvents {
typedEvent, err := controller.decideEffectiveEventTransferValueOnlyAfterSirius(event)
typedEvent, err := decide(event)
if err != nil {
return nil, err
}
Expand All @@ -62,6 +73,48 @@ func (controller *transactionEventsController) extractEventTransferValueOnly(tx
return typedEvents, nil
}

func (controller *transactionEventsController) decideEffectiveEventTransferValueWithAsyncCallbackAndUserError(event *transaction.Events) (*eventTransferValueOnly, error) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Opinion: detectEventTransferValueWithAsyncCallbackAndUserError.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

numTopics := len(event.Topics)
if numTopics != numTopicsOfEventTransferValueOnlyAfterSirius {
return nil, fmt.Errorf("%w: bad number of topics for 'transferValueOnly' = %d", errCannotRecognizeEvent, numTopics)
}

receiverPubKey := event.Topics[1]
eventData := string(event.Data)
if eventData != transactionEventDataAsyncCallback {
// Ineffective event, since is not an AsyncCallback

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe the word "ineffective" is a bit ambiguous here. Maybe "not of interest"?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

return nil, nil
}

numElementsAdditionalData := len(event.AdditionalData)
if numElementsAdditionalData != numElementsInAdditionalDataAsyncCallbackWithError {
return nil, nil
}

userErrorCode := int(new(big.Int).SetBytes(event.AdditionalData[2]).Int64())
if userErrorCode != errorCodeUserError {
return nil, nil
}

sender := event.Address
senderPubKey, err := controller.provider.ConvertAddressToPubKey(sender)
if err != nil {
return nil, err
}
isIntraShard := controller.provider.ComputeShardIdOfPubKey(senderPubKey) == controller.provider.ComputeShardIdOfPubKey(receiverPubKey)
if !isIntraShard {
// Ineffective event, the issue with this type of event is intra shard
return nil, nil
}

receiver := controller.provider.ConvertPubKeyToAddress(receiverPubKey)
return &eventTransferValueOnly{
sender: sender,
receiver: receiver,
asyncCallbackWithError: true,
}, nil
}

// See: https://github.com/multiversx/mx-specs/blob/main/releases/protocol/release-specs-v1.6.0-Sirius.md#17-logs--events-changes-5490
func (controller *transactionEventsController) decideEffectiveEventTransferValueOnlyAfterSirius(event *transaction.Events) (*eventTransferValueOnly, error) {
numTopics := len(event.Topics)
Expand Down Expand Up @@ -89,8 +142,8 @@ func (controller *transactionEventsController) decideEffectiveEventTransferValue
return nil, err
}

isIntrashard := controller.provider.ComputeShardIdOfPubKey(senderPubKey) == controller.provider.ComputeShardIdOfPubKey(receiverPubKey)
if !isIntrashard {
isIntraShard := controller.provider.ComputeShardIdOfPubKey(senderPubKey) == controller.provider.ComputeShardIdOfPubKey(receiverPubKey)
if !isIntraShard {
// Ineffective event, since the balance change is already captured by a SCR.
return nil, nil
}
Expand Down Expand Up @@ -157,6 +210,10 @@ func (controller *transactionEventsController) extractEventsESDTOrESDTNFTTransfe
return nil, err
}

if string(event.Data) == transactionEventDataAsyncCall {
typedEvent.asyncCall = true
}

receiverPubkey := event.Topics[3]
typedEvent.receiverAddress = controller.provider.ConvertPubKeyToAddress(receiverPubkey)
typedEvent.senderAddress = event.Address
Expand Down
Loading
Loading