Skip to content

Commit

Permalink
Merge pull request #98 from multiversx/spica-21-1
Browse files Browse the repository at this point in the history
Improve handling of claim developer rewards
  • Loading branch information
andreibancioiu authored Aug 21, 2024
2 parents b6829d9 + 9bcda27 commit 05fed49
Show file tree
Hide file tree
Showing 18 changed files with 289 additions and 21 deletions.
12 changes: 12 additions & 0 deletions cmd/rosetta/cli.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package main

import (
"math"

logger "github.com/multiversx/mx-chain-logger-go"
"github.com/urfave/cli"
)
Expand Down Expand Up @@ -166,6 +168,13 @@ VERSION:
Usage: "Specifies the configuration file for custom currencies.",
Required: false,
}

cliFlagActivationEpochSpica = cli.UintFlag{
Name: "activation-epoch-spica",
Usage: "Specifies the activation epoch for Spica release.",
Required: false,
Value: math.MaxUint32,
}
)

func getAllCliFlags() []cli.Flag {
Expand Down Expand Up @@ -194,6 +203,7 @@ func getAllCliFlags() []cli.Flag {
cliFlagNumHistoricalEpochs,
cliFlagShouldHandleContracts,
cliFlagConfigFileCustomCurrencies,
cliFlagActivationEpochSpica,
}
}

Expand Down Expand Up @@ -223,6 +233,7 @@ type parsedCliFlags struct {
numHistoricalEpochs uint32
shouldHandleContracts bool
configFileCustomCurrencies string
activationEpochSpica uint32
}

func getParsedCliFlags(ctx *cli.Context) parsedCliFlags {
Expand Down Expand Up @@ -252,5 +263,6 @@ func getParsedCliFlags(ctx *cli.Context) parsedCliFlags {
numHistoricalEpochs: uint32(ctx.GlobalUint(cliFlagNumHistoricalEpochs.Name)),
shouldHandleContracts: ctx.GlobalBool(cliFlagShouldHandleContracts.Name),
configFileCustomCurrencies: ctx.GlobalString(cliFlagConfigFileCustomCurrencies.Name),
activationEpochSpica: uint32(ctx.GlobalUint(cliFlagActivationEpochSpica.Name)),
}
}
1 change: 1 addition & 0 deletions cmd/rosetta/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ func startRosetta(ctx *cli.Context) error {
FirstHistoricalEpoch: cliFlags.firstHistoricalEpoch,
NumHistoricalEpochs: cliFlags.numHistoricalEpochs,
ShouldHandleContracts: cliFlags.shouldHandleContracts,
ActivationEpochSpica: cliFlags.activationEpochSpica,
})
if err != nil {
return err
Expand Down
1 change: 1 addition & 0 deletions server/factory/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,5 +35,6 @@ type NetworkProvider interface {
ComputeReceiptHash(apiReceipt *transaction.ApiReceipt) (string, error)
ComputeTransactionFeeForMoveBalance(tx *transaction.ApiTransactionResult) *big.Int
GetMempoolTransactionByHash(hash string) (*transaction.ApiTransactionResult, error)
IsReleaseSpicaActive(epoch uint32) bool
LogDescription()
}
2 changes: 2 additions & 0 deletions server/factory/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ type ArgsCreateNetworkProvider struct {
FirstHistoricalEpoch uint32
NumHistoricalEpochs uint32
ShouldHandleContracts bool
ActivationEpochSpica uint32
}

// CreateNetworkProvider creates a network provider
Expand Down Expand Up @@ -140,6 +141,7 @@ func CreateNetworkProvider(args ArgsCreateNetworkProvider) (NetworkProvider, err
FirstHistoricalEpoch: args.FirstHistoricalEpoch,
NumHistoricalEpochs: args.NumHistoricalEpochs,
ShouldHandleContracts: args.ShouldHandleContracts,
ActivationEpochSpica: args.ActivationEpochSpica,

ObserverFacade: &components.ObserverFacade{
Processor: baseProcessor,
Expand Down
10 changes: 9 additions & 1 deletion server/provider/networkProvider.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ type ArgsNewNetworkProvider struct {
FirstHistoricalEpoch uint32
NumHistoricalEpochs uint32
ShouldHandleContracts bool
ActivationEpochSpica uint32

ObserverFacade observerFacade

Expand All @@ -64,6 +65,7 @@ type networkProvider struct {
firstHistoricalEpoch uint32
numHistoricalEpochs uint32
shouldHandleContracts bool
activationEpochSpica uint32

observerFacade observerFacade

Expand Down Expand Up @@ -104,6 +106,7 @@ func NewNetworkProvider(args ArgsNewNetworkProvider) (*networkProvider, error) {
firstHistoricalEpoch: args.FirstHistoricalEpoch,
numHistoricalEpochs: args.NumHistoricalEpochs,
shouldHandleContracts: args.ShouldHandleContracts,
activationEpochSpica: args.ActivationEpochSpica,

observerFacade: args.ObserverFacade,

Expand Down Expand Up @@ -413,7 +416,7 @@ func (provider *networkProvider) GetMempoolTransactionByHash(hash string) (*tran
return nil, nil
}

// ComputeTransactionFeeForMoveBalance computes the fee for a move-balance transaction.
// ComputeTransactionFeeForMoveBalance computes the fee for a move-balance transaction
func (provider *networkProvider) ComputeTransactionFeeForMoveBalance(tx *transaction.ApiTransactionResult) *big.Int {
minGasLimit := provider.networkConfig.MinGasLimit
extraGasLimitGuardedTx := provider.networkConfig.ExtraGasLimitGuardedTx
Expand All @@ -429,6 +432,11 @@ func (provider *networkProvider) ComputeTransactionFeeForMoveBalance(tx *transac
return fee
}

// IsReleaseSpicaActive returns whether the Spica release is active in the provided epoch
func (provider *networkProvider) IsReleaseSpicaActive(epoch uint32) bool {
return epoch >= provider.activationEpochSpica
}

// LogDescription writes a description of the network provider in the log output
func (provider *networkProvider) LogDescription() {
log.Info("Description of network provider",
Expand Down
1 change: 1 addition & 0 deletions server/services/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,4 +55,5 @@ var (
numTopicsOfEventESDTNFTBurn = 3
numTopicsOfEventESDTNFTAddQuantity = 3
numTopicsOfEventSCDeployBeforeSirius = 2
numTopicsOfEventClaimDeveloperRewards = 2
)
1 change: 1 addition & 0 deletions server/services/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,5 @@ type NetworkProvider interface {
ComputeReceiptHash(apiReceipt *transaction.ApiReceipt) (string, error)
ComputeTransactionFeeForMoveBalance(tx *transaction.ApiTransactionResult) *big.Int
GetMempoolTransactionByHash(hash string) (*transaction.ApiTransactionResult, error)
IsReleaseSpicaActive(epoch uint32) bool
}
2 changes: 2 additions & 0 deletions server/services/operations.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ const (
opScResult = "SmartContractResult"
opFeeRefundAsScResult = "FeeRefundAsSmartContractResult"
opDeveloperRewardsAsScResult = "DeveloperRewardsAsSmartContractResult"
opDeveloperRewards = "DeveloperRewards"
opFeeOfInvalidTx = "FeeOfInvalidTransaction"
opFeeRefund = "FeeRefund"
opCustomTransfer = "CustomTransfer"
Expand All @@ -27,6 +28,7 @@ var (
opScResult,
opFeeRefundAsScResult,
opDeveloperRewardsAsScResult,
opDeveloperRewards,
opFeeOfInvalidTx,
opFeeRefund,
opCustomTransfer,
Expand Down
77 changes: 77 additions & 0 deletions server/services/testdata/blocks_with_claim_developer_rewards.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
[
{
"comment": "block with claim developer rewards",
"miniBlocks": [
{
"transactions": [
{
"type": "normal",
"processingTypeOnSource": "BuiltInFunctionCall",
"processingTypeOnDestination": "BuiltInFunctionCall",
"hash": "96b1a0533ff17df3d1777889117023d0b178cc80fa72535d1b8ec1a13bcf3a75",
"epoch": 20,
"value": "0",
"receiver": "erd1qqqqqqqqqqqqqpgqagjekf5mxv86hy5c62vvtug5vc6jmgcsq6uq8reras",
"sender": "erd1tn62hjp72rznp8vq0lplva5csav6rccpqqdungpxtqz0g2hcq6uq9k4cc6",
"data": "Q2xhaW1EZXZlbG9wZXJSZXdhcmRz",
"signature": "132aa54ec093c21e2d0d447bf9a9b1da5c33d4120da66fb53dbc78d1d3d007e2314fa06348302f503e96a91b697dd943189df0ad4c3750416a704de2ac007e06",
"sourceShard": 0,
"destinationShard": 0,
"logs": {
"address": "erd1qqqqqqqqqqqqqpgqagjekf5mxv86hy5c62vvtug5vc6jmgcsq6uq8reras",
"events": [
{
"address": "erd1qqqqqqqqqqqqqpgqagjekf5mxv86hy5c62vvtug5vc6jmgcsq6uq8reras",
"identifier": "completedTxEvent",
"topics": [
"lrGgUz/xffPRd3iJEXAj0LF4zID6clNdG47BoTvPOnU="
],
"data": null,
"additionalData": null
}
]
},
"operation": "ClaimDeveloperRewards",
"initiallyPaidFee": "160685000000000"
}
]
},
{
"transactions": [
{
"type": "unsigned",
"processingTypeOnSource": "MoveBalance",
"processingTypeOnDestination": "MoveBalance",
"hash": "d05c5f65f564d740aa1e81f7a96581d739783a43c232a6c86112afa1e6c318c4",
"epoch": 20,
"value": "1774725000000",
"receiver": "erd1tn62hjp72rznp8vq0lplva5csav6rccpqqdungpxtqz0g2hcq6uq9k4cc6",
"sender": "erd1tn62hjp72rznp8vq0lplva5csav6rccpqqdungpxtqz0g2hcq6uq9k4cc6",
"previousTransactionHash": "96b1a0533ff17df3d1777889117023d0b178cc80fa72535d1b8ec1a13bcf3a75",
"originalTransactionHash": "96b1a0533ff17df3d1777889117023d0b178cc80fa72535d1b8ec1a13bcf3a75",
"originalSender": "erd1tn62hjp72rznp8vq0lplva5csav6rccpqqdungpxtqz0g2hcq6uq9k4cc6",
"sourceShard": 0,
"destinationShard": 0
},
{
"type": "unsigned",
"processingTypeOnSource": "MoveBalance",
"processingTypeOnDestination": "MoveBalance",
"hash": "bc89442d5e77113f0b4e7383e5d078776fc6724690ba9f98d1704202c324e090",
"epoch": 20,
"value": "29185000000000",
"receiver": "erd1tn62hjp72rznp8vq0lplva5csav6rccpqqdungpxtqz0g2hcq6uq9k4cc6",
"sender": "erd1qqqqqqqqqqqqqpgqagjekf5mxv86hy5c62vvtug5vc6jmgcsq6uq8reras",
"previousTransactionHash": "96b1a0533ff17df3d1777889117023d0b178cc80fa72535d1b8ec1a13bcf3a75",
"originalTransactionHash": "96b1a0533ff17df3d1777889117023d0b178cc80fa72535d1b8ec1a13bcf3a75",
"sourceShard": 0,
"destinationShard": 0,
"nonce": 29,
"data": "QDZmNmI=",
"isRefund": true
}
]
}
]
}
]
26 changes: 26 additions & 0 deletions server/services/transactionEventsController.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package services

import (
"fmt"
"math/big"
"strings"

"github.com/multiversx/mx-chain-core-go/data/transaction"
Expand Down Expand Up @@ -263,6 +264,31 @@ func (controller *transactionEventsController) extractEventsESDTNFTAddQuantity(t
return typedEvents, nil
}

func (controller *transactionEventsController) extractEventsClaimDeveloperRewards(tx *transaction.ApiTransactionResult) ([]*eventClaimDeveloperRewards, error) {
rawEvents := controller.findManyEventsByIdentifier(tx, transactionEventClaimDeveloperRewards)
typedEvents := make([]*eventClaimDeveloperRewards, 0, len(rawEvents))

for _, event := range rawEvents {
numTopics := len(event.Topics)
if numTopics != numTopicsOfEventClaimDeveloperRewards {
return nil, fmt.Errorf("%w: bad number of topics for %s event = %d", errCannotRecognizeEvent, transactionEventClaimDeveloperRewards, numTopics)
}

valueBytes := event.Topics[0]
receiverPubkey := event.Topics[1]

value := big.NewInt(0).SetBytes(valueBytes)
receiver := controller.provider.ConvertPubKeyToAddress(receiverPubkey)

typedEvents = append(typedEvents, &eventClaimDeveloperRewards{
value: value.String(),
receiverAddress: receiver,
})
}

return typedEvents, nil
}

func (controller *transactionEventsController) findManyEventsByIdentifier(tx *transaction.ApiTransactionResult, identifier string) []*transaction.Events {
events := make([]*transaction.Events, 0)

Expand Down
25 changes: 25 additions & 0 deletions server/services/transactionEventsController_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -281,4 +281,29 @@ func TestTransactionEventsController_ExtractEvents(t *testing.T) {
require.Equal(t, []byte{0x2a}, events[0].nonceAsBytes)
require.Equal(t, "100", events[0].value)
})

t.Run("ClaimDeveloperRewards", func(t *testing.T) {
topic0 := []byte{0x64}
topic1, _ := hex.DecodeString("5cf4abc83e50c5309d807fc3f676988759a1e301001bc9a0265804f42af806b8")

tx := &transaction.ApiTransactionResult{
Logs: &transaction.ApiLogs{
Events: []*transaction.Events{
{
Identifier: "ClaimDeveloperRewards",
Topics: [][]byte{
topic0,
topic1,
},
},
},
},
}

events, err := controller.extractEventsClaimDeveloperRewards(tx)
require.NoError(t, err)
require.Len(t, events, 1)
require.Equal(t, "100", events[0].value)
require.Equal(t, "erd1tn62hjp72rznp8vq0lplva5csav6rccpqqdungpxtqz0g2hcq6uq9k4cc6", events[0].receiverAddress)
})
}
34 changes: 23 additions & 11 deletions server/services/transactionsFeaturesDetector.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package services

import (
"bytes"

"github.com/multiversx/mx-chain-core-go/data/transaction"
)

Expand All @@ -23,23 +21,37 @@ func (detector *transactionsFeaturesDetector) doesContractResultHoldRewardsOfCla
contractResult *transaction.ApiTransactionResult,
allTransactionsInBlock []*transaction.ApiTransactionResult,
) bool {
claimDeveloperRewardsTxs := make(map[string]struct{})
hasData := len(contractResult.Data) > 0
hasNonZeroNonce := contractResult.Nonce > 0
if hasData || hasNonZeroNonce {
return false
}

for _, tx := range allTransactionsInBlock {
matchesTypeOnSource := tx.ProcessingTypeOnSource == transactionProcessingTypeBuiltInFunctionCall
if !matchesTypeOnSource {
continue
}

matchesTypeOnDestination := tx.ProcessingTypeOnDestination == transactionProcessingTypeBuiltInFunctionCall
matchesData := bytes.Equal(tx.Data, []byte(builtInFunctionClaimDeveloperRewards))
if !matchesTypeOnDestination {
continue
}

if matchesTypeOnSource && matchesTypeOnDestination && matchesData {
claimDeveloperRewardsTxs[tx.Hash] = struct{}{}
matchesOperation := tx.Operation == builtInFunctionClaimDeveloperRewards
if !matchesOperation {
continue
}
}

_, isResultOfClaimDeveloperRewards := claimDeveloperRewardsTxs[contractResult.OriginalTransactionHash]
hasNoData := len(contractResult.Data) == 0
hasZeroNonce := contractResult.Nonce == 0
matchesOriginalTransactionHash := tx.Hash == contractResult.OriginalTransactionHash
if !matchesOriginalTransactionHash {
continue
}

return true
}

return isResultOfClaimDeveloperRewards && hasNoData && hasZeroNonce
return false
}

// isInvalidTransactionOfTypeMoveBalanceThatOnlyConsumesDataMovementGas detects (intra-shard) invalid transactions
Expand Down
Loading

0 comments on commit 05fed49

Please sign in to comment.