-
Notifications
You must be signed in to change notification settings - Fork 204
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
Relayed v3 with multiple transactions #6118
Conversation
…actions + fixes on handling fee
…_txs Extra tests and coverage for relayed v3 with multiple inner transactions
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## feat/relayedv3 #6118 +/- ##
==================================================
+ Coverage 78.77% 78.78% +0.01%
==================================================
Files 752 753 +1
Lines 98137 98341 +204
==================================================
+ Hits 77308 77481 +173
- Misses 15604 15626 +22
- Partials 5225 5234 +9 ☔ View full report in Codecov by Sentry. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
review still in works.
@@ -14,7 +14,7 @@ import ( | |||
) | |||
|
|||
// CreateGeneralSetupForRelayTxTest will create the general setup for relayed transactions | |||
func CreateGeneralSetupForRelayTxTest() ([]*integrationTests.TestProcessorNode, []int, []*integrationTests.TestWalletAccount, *integrationTests.TestWalletAccount) { | |||
func CreateGeneralSetupForRelayTxTest(relayedV3Test bool) ([]*integrationTests.TestProcessorNode, []int, []*integrationTests.TestWalletAccount, *integrationTests.TestWalletAccount) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is not a good practice. Make a separate function for CreateGeneralSetupForRelayedV3. which calls the common code.
This can be done without the bool.
process/transaction/baseProcess.go
Outdated
txFee = txProc.economicsFee.ComputeTxFee(tx) | ||
moveBalanceGasLimit := txProc.economicsFee.ComputeGasLimit(tx) | ||
gasToUse := tx.GetGasLimit() - moveBalanceGasLimit | ||
moveBalanceUserFee := txProc.economicsFee.ComputeMoveBalanceFee(tx) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this will further increase the cost of relayed txs as they are now.
It can stay, but for relayed v1 and v2 the txData is computed twice. Once in the relayer and once when processing the underlying tx.
process/transaction/shardProcess.go
Outdated
@@ -298,7 +304,14 @@ func (txProc *txProcessor) executingFailedTransaction( | |||
return nil | |||
} | |||
|
|||
txFee := txProc.economicsFee.ComputeTxFee(tx) | |||
txFee := txProc.economicsFee.ComputeFeeForProcessing(tx, tx.GasLimit) | |||
if txProc.enableEpochsHandler.IsFlagEnabled(common.FixRelayedMoveBalanceFlag) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
move the common code and use a common function. This is the exactly same lines of codes as in baseProcess.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
move more code into that new function. activation flags as well.
process/transaction/shardProcess.go
Outdated
@@ -391,7 +404,11 @@ func (txProc *txProcessor) processTxFee( | |||
if isUserTxOfRelayed { | |||
totalCost := txProc.economicsFee.ComputeFeeForProcessing(tx, tx.GasLimit) | |||
if txProc.enableEpochsHandler.IsFlagEnabled(common.FixRelayedMoveBalanceFlag) { | |||
totalCost = txProc.economicsFee.ComputeTxFee(tx) | |||
moveBalanceGasLimit := txProc.economicsFee.ComputeGasLimit(tx) | |||
gasToUse := tx.GetGasLimit() - moveBalanceGasLimit |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
duplicated code again.
} | ||
|
||
txProc.txFeeHandler.ProcessTransactionFee(relayerFee, big.NewInt(0), txHash) | ||
} | ||
|
||
return txHash, nil | ||
return nil |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
txHash was returned in order to not calculate that too many times. Actually we should create a task where we calculate txHash only once in the lifetime of a tx.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
created new task MX-15423
api/groups/transactionGroup.go
Outdated
|
||
newInnerTx, _, err := tg.createTransaction(innerTx, nil) | ||
if err != nil { | ||
// if one of the inner txs is invalid, break the loop and move to the next transaction received |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why would you send the tx further if the inner tx is wrong? Why not error?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
right, updated
@@ -176,6 +176,16 @@ func (txProc *baseTxProcessor) checkTxValues( | |||
return nil | |||
} | |||
|
|||
func (txProc *baseTxProcessor) computeTxFeeAfterMoveBalanceFix(tx *transaction.Transaction) *big.Int { | |||
moveBalanceGasLimit := txProc.economicsFee.ComputeGasLimit(tx) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think flag check and old computation can be moved inside this new function as well. It will look better. As in all the cases you have compute old way if flag is not activated.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
updated
process/transaction/shardProcess.go
Outdated
@@ -298,7 +304,14 @@ func (txProc *txProcessor) executingFailedTransaction( | |||
return nil | |||
} | |||
|
|||
txFee := txProc.economicsFee.ComputeTxFee(tx) | |||
txFee := txProc.economicsFee.ComputeFeeForProcessing(tx, tx.GasLimit) | |||
if txProc.enableEpochsHandler.IsFlagEnabled(common.FixRelayedMoveBalanceFlag) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
move more code into that new function. activation flags as well.
process/transaction/shardProcess.go
Outdated
|
||
allUserTxsSucceeded := len(executedUserTxs) == len(innerTxs) && innerTxErr == nil && innerTxRetCode == vmcommon.Ok | ||
if !allUserTxsSucceeded { | ||
log.Debug("failed to execute all inner transactions", "total", len(innerTxs), "executed transactions", len(executedUserTxs)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we do not need information like this in log.Debug - maybe in trace.
process/transaction/shardProcess.go
Outdated
) (*smartContractResult.SmartContractResult, error) { | ||
scrValue := tx.Value | ||
if isRevertSCR { | ||
scrValue = big.NewInt(0).Neg(tx.Value) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we have never created SCR with negative value. Why do you need this ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is not needed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
indeed not needed, I forgot to remove it after the last discussion
process/transaction/shardProcess.go
Outdated
for acnt, prevBalance := range snapshot { | ||
currentBalance := acnt.GetBalance() | ||
diff := big.NewInt(0).Sub(currentBalance, prevBalance) | ||
err := acnt.SubFromBalance(diff) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is not good.
user accounts.RevertToSnapshot. it will resolve the issue. No need to manually do this.
process/transaction/shardProcess.go
Outdated
|
||
uniqueSendersMap := txProc.relayedTxV3Processor.GetUniqueSendersRequiredFeesMap(tx.InnerTransactions) | ||
uniqueSendersSlice := mapToSlice(uniqueSendersMap) | ||
sendersBalancesSnapshot := make(map[state.UserAccountHandler]*big.Int, len(uniqueSendersMap)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you do not need to get the accounts balance like this - no need. revert should be done with accounts.RevertToSnapshot function. after taking the fees out from the relayer, you make a snapshot. accounts.Snapshot() -> will give you an ID. and in case of errors you return to that and all is good.
if userTx.GasLimit != remainingGasLimit { | ||
return vmcommon.UserError, txProc.executingFailedTransaction(tx, relayerAcnt, process.ErrRelayedTxV3GasLimitMismatch) | ||
|
||
if check.IfNil(acntSnd) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we have discussed that acntSnd has to be in the same shard. If it is not, you should return error. it is a failed inner tx.
At the interceptor level we can simply stop these kind of txs. there is no reason at all to accept them to the network.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
added return error as suggested
this check is already done at interceptor level, so this if should never ever be true
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
that is true. But it is ok to check here as well and return error.
relayerMoveBalanceFee := proc.economicsFee.ComputeMoveBalanceFee(tx) | ||
uniqueSenders := proc.GetUniqueSendersRequiredFeesMap(tx.InnerTransactions) | ||
|
||
relayerFee := big.NewInt(0).Mul(relayerMoveBalanceFee, big.NewInt(int64(len(uniqueSenders)))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I do not think this should be by unique senders. every inner tx is a separate tx with separate move balance fee. independent if the sender is the same.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
considered this a cost optimization, although it makes more sense to keep each tx independent including the move balance fee.. updated as suggested
|
||
const minTransactionsAllowed = 1 | ||
|
||
type ArgRelayedTxV3Processor struct { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
add comment
process/transaction/shardProcess.go
Outdated
var innerTxErr error | ||
executedUserTxs := make([]*transaction.Transaction, 0) | ||
for _, innerTx := range innerTxs { | ||
innerTxRetCode, innerTxErr = txProc.finishExecutionOfInnerTx(tx, innerTx) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe a better name is processInnerTx
process/transaction/shardProcess.go
Outdated
} | ||
|
||
return txProc.finishExecutionOfRelayedTx(relayerAcnt, acntDst, tx, userTx) | ||
txFee := txProc.computeTxFee(innerTx) | ||
err = txProc.addFeeAndValueToDest(acntSnd, tx, txFee) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is tx.value == big.NewInt(0) ? I think it would be better to have a localTX here, where we have value at 0 clearly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we do have an early check for the tx value to be 0, but the suggestion from the next comment with the specific parameter should clarify.. applied it
process/transaction/shardProcess.go
Outdated
} | ||
|
||
return txProc.finishExecutionOfRelayedTx(relayerAcnt, acntDst, tx, userTx) | ||
txFee := txProc.computeTxFee(innerTx) | ||
err = txProc.addFeeAndValueToDest(acntSnd, tx, txFee) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you can change the addFeeAndValueToDest function and have 2 bigInts to be received there. it is much more clear. and here you could have big.newint(0), txFee.
process/transaction/shardProcess.go
Outdated
} | ||
|
||
return txProc.finishExecutionOfRelayedTx(relayerAcnt, acntDst, tx, userTx) | ||
txFee := txProc.computeTxFee(innerTx) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we need another check - inveriant check Sum of TXFee == ComputeRelayedFee. you can sum all the txFees you have here, and at the end of processing to check it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
added check as discussed 🙏
for _, innerTx := range innerTxs { | ||
innerTxRetCode, innerTxErr = txProc.finishExecutionOfInnerTx(tx, innerTx) | ||
if innerTxErr != nil || innerTxRetCode != vmcommon.Ok { | ||
continue |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we should create a logEvent for failed innerTX, for those cases which is not caught by processUserTX - I think when the code reaches processUserTX a logEvent is done at least for that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
that's true, when the code reaches processUserTX it generates a logEvent.. will add one in case the processing fails before that point
continue | ||
} | ||
|
||
executedUserTxs = append(executedUserTxs, innerTx) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we have to check whether an additional logEvent would be needed here - I think it is better to have that innerTX was executed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we do have a SCR. do we also a logEvent?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
now I understand.. it would make sense to also have events for the succeeded inner txs
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
added in the next pr 🙏
…in-go into multiple_inner_transactions # Conflicts: # errors/errors.go # factory/interface.go # factory/mock/processComponentsStub.go # factory/processing/export_test.go # factory/processing/processComponents.go # factory/processing/processComponentsHandler.go # factory/processing/processComponentsHandler_test.go # go.mod # go.sum # integrationTests/mock/processComponentsStub.go # integrationTests/multiShard/relayedTx/common.go # node/chainSimulator/components/processComponents.go # node/chainSimulator/components/processComponents_test.go
if txProc.enableEpochsHandler.IsFlagEnabled(common.FixRelayedMoveBalanceFlag) { | ||
totalFee = txProc.economicsFee.ComputeTxFee(userTx) | ||
moveBalanceUserFee := txProc.economicsFee.ComputeMoveBalanceFee(userTx) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can't you reuse the common code for this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
some of the above variables are used in further ifs
} | ||
|
||
return txProc.finishExecutionOfRelayedTx(relayerAcnt, acntDst, tx, userTx) | ||
err = txProc.addFeeAndValueToDest(acntSnd, big.NewInt(0), txFee) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe as an optimization, we can skip the addition of fee to the destination account if we are anyway going to remove it afterwards.
- can be done on a different PR, as we need to check also with v1 & v2, and see if everything is backwards compatible (should be).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
added TODO
@@ -832,20 +935,14 @@ func (txProc *txProcessor) processUserTx( | |||
userTx *transaction.Transaction, | |||
relayedTxValue *big.Int, | |||
relayedNonce uint64, | |||
txHash []byte, | |||
originalTxHash []byte, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if implementing the optimization with the fee, then line 950 would simply need to remove the value from user.
@@ -832,20 +935,14 @@ func (txProc *txProcessor) processUserTx( | |||
userTx *transaction.Transaction, | |||
relayedTxValue *big.Int, | |||
relayedNonce uint64, | |||
txHash []byte, | |||
originalTxHash []byte, | |||
) (vmcommon.ReturnCode, error) { | |||
|
|||
acntSnd, acntDst, err := txProc.getAccounts(userTx.SndAddr, userTx.RcvAddr) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is it possible that during the execution of relayed tx we reach this point and we can get an error here?
if so we need extra cleanup.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
handled the situation. should not happen though
Reasoning behind the pull request
Proposed changes
Testing procedure
Pre-requisites
Based on the Contributing Guidelines the PR author and the reviewers must check the following requirements are met:
feat
branch created?feat
branch merging, do all satellite projects have a proper tag insidego.mod
?