Skip to content

Commit

Permalink
Handle & dismiss ineffective refunds.
Browse files Browse the repository at this point in the history
  • Loading branch information
andreibancioiu committed Aug 22, 2024
1 parent c97a67a commit d527015
Show file tree
Hide file tree
Showing 6 changed files with 111 additions and 53 deletions.
4 changes: 4 additions & 0 deletions server/services/networkProviderExtension.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,10 @@ func (extension *networkProviderExtension) getGenesisBlockIdentifier() *types.Bl
return blockSummaryToIdentifier(summary)
}

func (extension *networkProviderExtension) isContractAddress(address string) bool {
return !extension.isUserAddress(address)
}

func (extension *networkProviderExtension) isUserAddress(address string) bool {
pubKey, err := extension.provider.ConvertAddressToPubKey(address)
if err != nil {
Expand Down
16 changes: 12 additions & 4 deletions server/services/transactionsFeaturesDetector.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,16 @@ import (
)

type transactionsFeaturesDetector struct {
networkProvider NetworkProvider
eventsController *transactionEventsController
networkProvider NetworkProvider
networkProviderExtension *networkProviderExtension
eventsController *transactionEventsController
}

func newTransactionsFeaturesDetector(provider NetworkProvider) *transactionsFeaturesDetector {
return &transactionsFeaturesDetector{
networkProvider: provider,
eventsController: newTransactionEventsController(provider),
networkProvider: provider,
networkProviderExtension: newNetworkProviderExtension(provider),
eventsController: newTransactionEventsController(provider),
}
}

Expand Down Expand Up @@ -106,3 +108,9 @@ func (detector *transactionsFeaturesDetector) isContractCallWithSignalError(tx *
func (detector *transactionsFeaturesDetector) isIntrashard(tx *transaction.ApiTransactionResult) bool {
return tx.SourceShard == tx.DestinationShard
}

// isSmartContractResultIneffectiveRefund detects smart contract results that are ineffective refunds.
// Also see: https://console.cloud.google.com/bigquery?sq=667383445384:de7a5f3f172f4b50a9aaed353ef79839
func (detector *transactionsFeaturesDetector) isSmartContractResultIneffectiveRefund(scr *transaction.ApiTransactionResult) bool {
return scr.IsRefund && scr.Sender == scr.Receiver && detector.networkProviderExtension.isContractAddress(scr.Sender)
}
23 changes: 23 additions & 0 deletions server/services/transactionsFeaturesDetector_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -235,3 +235,26 @@ func TestTransactionsFeaturesDetector_isIntrashard(t *testing.T) {
DestinationShard: 1,
}))
}

func TestTransactionsFeaturesDetector_isSmartContractResultIneffectiveRefund(t *testing.T) {
networkProvider := testscommon.NewNetworkProviderMock()
detector := newTransactionsFeaturesDetector(networkProvider)

require.True(t, detector.isSmartContractResultIneffectiveRefund(&transaction.ApiTransactionResult{
Sender: testscommon.TestAddressOfContract,
Receiver: testscommon.TestAddressOfContract,
IsRefund: true,
}))

require.False(t, detector.isSmartContractResultIneffectiveRefund(&transaction.ApiTransactionResult{
Sender: testscommon.TestAddressOfContract,
Receiver: testscommon.TestAddressOfContract,
IsRefund: false,
}))

require.False(t, detector.isSmartContractResultIneffectiveRefund(&transaction.ApiTransactionResult{
Sender: testscommon.TestAddressOfContract,
Receiver: testscommon.TestAddressAlice,
IsRefund: false,
}))
}
14 changes: 7 additions & 7 deletions server/services/transactionsTransformer.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,16 +116,16 @@ func (transformer *transactionsTransformer) unsignedTxToRosettaTx(
scr *transaction.ApiTransactionResult,
txsInBlock []*transaction.ApiTransactionResult,
) *types.Transaction {
if scr.IsRefund {
if scr.Sender == scr.Receiver && !transformer.extension.isUserAddress(scr.Sender) {
log.Info("unsignedTxToRosettaTx: dismissed refund", "hash", scr.Hash, "originalTxHash", scr.OriginalTransactionHash)
if transformer.featuresDetector.isSmartContractResultIneffectiveRefund(scr) {
log.Info("unsignedTxToRosettaTx: ineffective refund", "hash", scr.Hash)

return &types.Transaction{
TransactionIdentifier: hashToTransactionIdentifier(scr.Hash),
Operations: []*types.Operation{},
}
return &types.Transaction{
TransactionIdentifier: hashToTransactionIdentifier(scr.Hash),
Operations: []*types.Operation{},
}
}

if scr.IsRefund {
return &types.Transaction{
TransactionIdentifier: hashToTransactionIdentifier(scr.Hash),
Operations: []*types.Operation{
Expand Down
106 changes: 64 additions & 42 deletions server/services/transactionsTransformer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -239,55 +239,77 @@ func TestTransactionsTransformer_UnsignedTxToRosettaTx(t *testing.T) {
extension := newNetworkProviderExtension(networkProvider)
transformer := newTransactionsTransformer(networkProvider)

refundTx := &transaction.ApiTransactionResult{
Hash: "aaaa",
Sender: testscommon.TestAddressOfContract,
Receiver: testscommon.TestAddressAlice,
Value: "1234",
IsRefund: true,
}
t.Run("refund SCR", func(t *testing.T) {
tx := &transaction.ApiTransactionResult{
Hash: "aaaa",
Sender: testscommon.TestAddressOfContract,
Receiver: testscommon.TestAddressAlice,
Value: "1234",
IsRefund: true,
}

expectedRefundTx := &types.Transaction{
TransactionIdentifier: hashToTransactionIdentifier("aaaa"),
Operations: []*types.Operation{
{
Type: opFeeRefundAsScResult,
Account: addressToAccountIdentifier(testscommon.TestAddressAlice),
Amount: extension.valueToNativeAmount("1234"),
expectedTx := &types.Transaction{
TransactionIdentifier: hashToTransactionIdentifier("aaaa"),
Operations: []*types.Operation{
{
Type: opFeeRefundAsScResult,
Account: addressToAccountIdentifier(testscommon.TestAddressAlice),
Amount: extension.valueToNativeAmount("1234"),
},
},
},
}
}

moveBalanceTx := &transaction.ApiTransactionResult{
Hash: "aaaa",
Sender: testscommon.TestAddressOfContract,
Receiver: testscommon.TestAddressAlice,
Value: "1234",
}
rosettaTx := transformer.unsignedTxToRosettaTx(tx, nil)
require.Equal(t, expectedTx, rosettaTx)
})

expectedMoveBalanceTx := &types.Transaction{
TransactionIdentifier: hashToTransactionIdentifier("aaaa"),
Operations: []*types.Operation{
{
Type: opScResult,
Account: addressToAccountIdentifier(testscommon.TestAddressOfContract),
Amount: extension.valueToNativeAmount("-1234"),
},
{
Type: opScResult,
Account: addressToAccountIdentifier(testscommon.TestAddressAlice),
Amount: extension.valueToNativeAmount("1234"),
t.Run("move balance SCR", func(t *testing.T) {
tx := &transaction.ApiTransactionResult{
Hash: "aaaa",
Sender: testscommon.TestAddressOfContract,
Receiver: testscommon.TestAddressAlice,
Value: "1234",
}

expectedTx := &types.Transaction{
TransactionIdentifier: hashToTransactionIdentifier("aaaa"),
Operations: []*types.Operation{
{
Type: opScResult,
Account: addressToAccountIdentifier(testscommon.TestAddressOfContract),
Amount: extension.valueToNativeAmount("-1234"),
},
{
Type: opScResult,
Account: addressToAccountIdentifier(testscommon.TestAddressAlice),
Amount: extension.valueToNativeAmount("1234"),
},
},
},
Metadata: extractTransactionMetadata(moveBalanceTx),
}
Metadata: extractTransactionMetadata(tx),
}

rosettaTx := transformer.unsignedTxToRosettaTx(tx, []*transaction.ApiTransactionResult{tx})
require.Equal(t, expectedTx, rosettaTx)
})

txsInBlock := []*transaction.ApiTransactionResult{refundTx, moveBalanceTx}
t.Run("ineffective refund SCR", func(t *testing.T) {
tx := &transaction.ApiTransactionResult{
Hash: "aaaa",
Sender: testscommon.TestAddressOfContract,
Receiver: testscommon.TestAddressOfContract,
Value: "1234",
IsRefund: true,
}

rosettaRefundTx := transformer.unsignedTxToRosettaTx(refundTx, txsInBlock)
rosettaMoveBalanceTx := transformer.unsignedTxToRosettaTx(moveBalanceTx, txsInBlock)
require.Equal(t, expectedRefundTx, rosettaRefundTx)
require.Equal(t, expectedMoveBalanceTx, rosettaMoveBalanceTx)
expectedTx := &types.Transaction{
TransactionIdentifier: hashToTransactionIdentifier("aaaa"),
Operations: []*types.Operation{},
Metadata: nil,
}

rosettaTx := transformer.unsignedTxToRosettaTx(tx, []*transaction.ApiTransactionResult{tx})
require.Equal(t, expectedTx, rosettaTx)
})
}

func TestTransactionsTransformer_InvalidTxToRosettaTx(t *testing.T) {
Expand Down
1 change: 1 addition & 0 deletions systemtests/check_with_mesh_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ def run_rosetta(configuration: Configuration):
f"--observer-actual-shard={configuration.network_shard}",
f"--network-id={configuration.network_id}",
f"--network-name={configuration.network_name}",
f"--handle-contracts",
f"--native-currency={configuration.native_currency}",
f"--config-custom-currencies={configuration.config_file_custom_currencies}",
f"--first-historical-epoch={current_epoch}",
Expand Down

0 comments on commit d527015

Please sign in to comment.