Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Accept relayed tx v3 with sender account non-existent #6677

Merged
merged 3 commits into from
Dec 16, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
55 changes: 50 additions & 5 deletions integrationTests/chainSimulator/relayedTx/relayedTx_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package relayedTx

import (
"crypto/rand"
"encoding/hex"
"encoding/json"
"math/big"
Expand All @@ -20,7 +21,9 @@ import (
"github.com/multiversx/mx-chain-go/node/chainSimulator/dtos"
chainSimulatorProcess "github.com/multiversx/mx-chain-go/node/chainSimulator/process"
"github.com/multiversx/mx-chain-go/process"
"github.com/multiversx/mx-chain-go/sharding"
"github.com/multiversx/mx-chain-go/vm"
logger "github.com/multiversx/mx-chain-logger-go"
"github.com/stretchr/testify/require"
)

Expand Down Expand Up @@ -55,8 +58,10 @@ func TestRelayedV3WithChainSimulator(t *testing.T) {
t.Run("intra shard move balance, invalid gas", testRelayedV3MoveInvalidGasLimit(0, 0))
t.Run("cross shard move balance, invalid gas", testRelayedV3MoveInvalidGasLimit(0, 1))

t.Run("successful intra shard sc call with refunds", testRelayedV3ScCall(0, 0))
t.Run("successful cross shard sc call with refunds", testRelayedV3ScCall(0, 1))
t.Run("successful intra shard sc call with refunds, existing sender", testRelayedV3ScCall(0, 0, true))
t.Run("successful intra shard sc call with refunds, new sender", testRelayedV3ScCall(0, 0, false))
t.Run("successful cross shard sc call with refunds, existing sender", testRelayedV3ScCall(0, 1, true))
t.Run("successful cross shard sc call with refunds, new sender", testRelayedV3ScCall(0, 1, false))
t.Run("intra shard sc call, invalid gas", testRelayedV3ScCallInvalidGasLimit(0, 0))
t.Run("cross shard sc call, invalid gas", testRelayedV3ScCallInvalidGasLimit(0, 1))
t.Run("intra shard sc call, invalid method", testRelayedV3ScCallInvalidMethod(0, 0))
Expand Down Expand Up @@ -267,6 +272,7 @@ func testRelayedV3MoveInvalidGasLimit(
func testRelayedV3ScCall(
relayerShard uint32,
ownerShard uint32,
existingSenderWithBalance bool,
) func(t *testing.T) {
return func(t *testing.T) {
if testing.Short() {
Expand All @@ -286,8 +292,7 @@ func testRelayedV3ScCall(
relayer, err := cs.GenerateAndMintWalletAddress(relayerShard, initialBalance)
require.NoError(t, err)

sender, err := cs.GenerateAndMintWalletAddress(relayerShard, initialBalance)
require.NoError(t, err)
sender, senderInitialBalance := prepareSender(t, cs, existingSenderWithBalance, relayerShard, initialBalance)

owner, err := cs.GenerateAndMintWalletAddress(ownerShard, initialBalance)
require.NoError(t, err)
Expand Down Expand Up @@ -330,7 +335,7 @@ func testRelayedV3ScCall(

// check sender balance
senderBalanceAfter := getBalance(t, cs, sender)
require.Equal(t, initialBalance.String(), senderBalanceAfter.String())
require.Equal(t, senderInitialBalance.String(), senderBalanceAfter.String())

// check owner balance
_, feeDeploy, _ := computeTxGasAndFeeBasedOnRefund(resultDeploy, refundDeploy, false, false)
Expand All @@ -346,6 +351,46 @@ func testRelayedV3ScCall(
}
}

func prepareSender(
t *testing.T,
cs testsChainSimulator.ChainSimulator,
existingSenderWithBalance bool,
shard uint32,
initialBalance *big.Int,
) (dtos.WalletAddress, *big.Int) {
if existingSenderWithBalance {
sender, err := cs.GenerateAndMintWalletAddress(shard, initialBalance)
require.NoError(t, err)

return sender, initialBalance
}

shardC := cs.GetNodeHandler(shard).GetShardCoordinator()
pkConv := cs.GetNodeHandler(shard).GetCoreComponents().AddressPubKeyConverter()
newAddress := generateAddressInShard(shardC, pkConv.Len())
return dtos.WalletAddress{
Bech32: pkConv.SilentEncode(newAddress, logger.GetOrCreate("tmp")),
Bytes: newAddress,
}, big.NewInt(0)
}

func generateAddressInShard(shardCoordinator sharding.Coordinator, len int) []byte {
for {
buff := generateAddress(len)
shardID := shardCoordinator.ComputeId(buff)
if shardID == shardCoordinator.SelfId() {
return buff
}
}
}

func generateAddress(len int) []byte {
buff := make([]byte, len)
_, _ = rand.Read(buff)

return buff
}

func testRelayedV3ScCallInvalidGasLimit(
relayerShard uint32,
ownerShard uint32,
Expand Down
22 changes: 20 additions & 2 deletions process/dataValidators/txValidator.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package dataValidators

import (
"fmt"
"math/big"

"github.com/multiversx/mx-chain-core-go/core"
"github.com/multiversx/mx-chain-core-go/core/check"
Expand Down Expand Up @@ -76,14 +77,27 @@ func (txv *txValidator) CheckTxValidity(interceptedTx process.InterceptedTransac
return nil
}

// for relayed v3, we allow sender accounts that do not exist
isRelayedV3 := common.IsRelayedTxV3(interceptedTx.Transaction())
hasValue := hasTxValue(interceptedTx)
shouldAllowMissingSenderAccount := isRelayedV3 && !hasValue
accountHandler, err := txv.getSenderAccount(interceptedTx)
if err != nil {
if err != nil && !shouldAllowMissingSenderAccount {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Should we check for ErrAccountNotFound (explicitly)? Just a question.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I don't think it is necessary, as ErrAccountNotFound is the only one returned from getSenderAccount method

return err
}

return txv.checkAccount(interceptedTx, accountHandler)
}

func hasTxValue(interceptedTx process.InterceptedTransactionHandler) bool {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Indeed, we don't handle MultiESDTTransfer with EGLD in interceptor (we never did, but that is OK).

txValue := interceptedTx.Transaction().GetValue()
if check.IfNilReflect(txValue) {
return false
}

return big.NewInt(0).Cmp(txValue) < 0
Copy link
Collaborator

Choose a reason for hiding this comment

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

Maybe directly use Sign() method of txValue, without instantiating a new big int (zero)?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

pushed

}

func (txv *txValidator) checkAccount(
interceptedTx process.InterceptedTransactionHandler,
accountHandler vmcommon.AccountHandler,
Expand Down Expand Up @@ -149,7 +163,11 @@ func (txv *txValidator) checkBalance(interceptedTx process.InterceptedTransactio
}

func (txv *txValidator) checkNonce(interceptedTx process.InterceptedTransactionHandler, accountHandler vmcommon.AccountHandler) error {
accountNonce := accountHandler.GetNonce()
accountNonce := uint64(0)
if !check.IfNil(accountHandler) {
accountNonce = accountHandler.GetNonce()
}

txNonce := interceptedTx.Nonce()
lowerNonceInTx := txNonce < accountNonce
veryHighNonceInTx := txNonce > accountNonce+uint64(txv.maxNonceDeltaAllowed)
Expand Down
7 changes: 4 additions & 3 deletions process/dataValidators/txValidator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -324,11 +324,11 @@ func TestTxValidator_CheckTxValidityAccountBalanceIsLessThanTxTotalValueShouldRe
adb.GetExistingAccountCalled = func(address []byte) (handler vmcommon.AccountHandler, e error) {
cnt++
if cnt == 1 {
require.True(t, bytes.Equal(providedSenderAddress, address))
} else {
require.True(t, bytes.Equal(providedRelayerAddress, address))
return nil, errors.New("sender not found")
}

require.True(t, bytes.Equal(providedRelayerAddress, address))

acc, _ := accounts.NewUserAccount(address, &trie.DataTrieTrackerStub{}, &trie.TrieLeafParserStub{})
acc.Nonce = accountNonce
acc.Balance = accountBalance
Expand Down Expand Up @@ -358,6 +358,7 @@ func TestTxValidator_CheckTxValidityAccountBalanceIsLessThanTxTotalValueShouldRe
Signature: []byte("address sig"),
RelayerAddr: providedRelayerAddress,
RelayerSignature: []byte("relayer sig"),
Value: big.NewInt(0),
}
}
result := txValidator.CheckTxValidity(txValidatorHandler)
Expand Down
Loading