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

On Transaction API, add "initially paid fee" and "is refund" #4108

Merged
merged 17 commits into from
May 27, 2022

Conversation

andreibancioiu
Copy link
Collaborator

@andreibancioiu andreibancioiu commented May 24, 2022

On Transaction API, add:

  • InitiallyPaidFee (computed wrt. the epoch of the transaction)
  • IsRefund

@andreibancioiu andreibancioiu self-assigned this May 24, 2022
@andreibancioiu andreibancioiu marked this pull request as ready for review May 24, 2022 13:27
@bogdan-rosianu bogdan-rosianu self-requested a review May 24, 2022 13:30
@andreibancioiu andreibancioiu marked this pull request as draft May 24, 2022 13:41
@andreibancioiu andreibancioiu marked this pull request as ready for review May 25, 2022 10:52
@codecov-commenter
Copy link

codecov-commenter commented May 25, 2022

Codecov Report

❗ No coverage uploaded for pull request base (feat/rosetta@18ebd42). Click here to learn what that means.
The diff coverage is n/a.

❗ Current head 34a6b6f differs from pull request most recent head 71d054c. Consider uploading reports for the commit 71d054c to get more accurate results

@@               Coverage Diff               @@
##             feat/rosetta    #4108   +/-   ##
===============================================
  Coverage                ?   75.30%           
===============================================
  Files                   ?      621           
  Lines                   ?    82490           
  Branches                ?        0           
===============================================
  Hits                    ?    62119           
  Misses                  ?    15671           
  Partials                ?     4700           

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 18ebd42...71d054c. Read the comment docs.

go.sum Outdated
@@ -33,6 +33,10 @@ github.com/ElrondNetwork/elrond-go-core v1.1.15 h1:CMGtJMsK+fBHsSrh5b3N/okYMywbf
github.com/ElrondNetwork/elrond-go-core v1.1.15/go.mod h1:Yz8JK5sGBctw7+gU8j2mZHbzQ09Ek4XHJ4Uinq1N6nM=
github.com/ElrondNetwork/elrond-go-core v1.1.16-0.20220520142226-1f321f3d1726 h1:f8UmoIKktGHrYvjXBquoJiejuzxJtJBQJBtEDe/yftk=
github.com/ElrondNetwork/elrond-go-core v1.1.16-0.20220520142226-1f321f3d1726/go.mod h1:Yz8JK5sGBctw7+gU8j2mZHbzQ09Ek4XHJ4Uinq1N6nM=
github.com/ElrondNetwork/elrond-go-core v1.1.16-0.20220523135140-7d93ca7217ce h1:KtcRP5g71Br1rOCvIuKyzjw+6jwqBWSB0ZaA3WuUMlM=
Copy link
Contributor

Choose a reason for hiding this comment

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

go mod tidy

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Done.

node/external/timemachine/fee/feeComputer.go Show resolved Hide resolved
node/external/timemachine/fee/feeComputer.go Show resolved Hide resolved
}

// Also see: https://github.com/ElrondNetwork/elastic-indexer-go/blob/master/process/transactions/scrsDataToTransactions.go
func (detector *refundDetector) isRefund(result refundDetectorInput) bool {
Copy link
Contributor

Choose a reason for hiding this comment

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

maybe can rename the result variable in something more specific like input or scrInput

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Renamed to input.

@iulianpascalau iulianpascalau self-requested a review May 25, 2022 17:22
node/external/timemachine/fee/args.go Show resolved Hide resolved
node/external/timemachine/fee/args.go Outdated Show resolved Hide resolved
node/external/timemachine/fee/feeComputer.go Show resolved Hide resolved
return nil, err
}

computer.economicsInstances[epoch] = newInstance
Copy link
Contributor

Choose a reason for hiding this comment

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

can we get OOMs because of using maps that do not get cleared?
Why not using a cacher instead of the map?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Using a cache is indeed desirable. Currently, our LRU / time-based caches are non-generic. Though we can work around their functionality and use them in this context (e.g. using a string representation of the epoch as a key), do you think it's OK to postpone until upgrading the go version & support generics (added a TODO)?

However, also added a test for analyzing the memory footprint of the fee computer: ~12 MB for 10 000 epochs.

Copy link
Contributor

Choose a reason for hiding this comment

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

Ok, will keep the TODO for now

checkComputedFee(t, "50000000000000", computer, 0, 80000, 1000000000, "", nil)
checkComputedFee(t, "57500000000000", computer, 0, 80000, 1000000000, "hello", nil)
checkComputedFee(t, "57500000000000", computer, 0, 1000000, 1000000000, "hello", contract)
// (for review) >>> the following scenarios pass, as well. Is this all right?
Copy link
Contributor

Choose a reason for hiding this comment

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

The penalize too much gas feature is just to protect against malicious actors that try to "keep for themselves" the whole blockchain by issuing transactions with large values for the gas limit field. These types of transactions will have the fees computed in the same way as any other transactions except that, if a provided fee exceeds 10x the gas consumed when executing, the blockchain will not refund the extra gas provided. The fee is computed the same because of this scenario:
suppose that shard 0 sends a SC call towards shard 1 with a gas limit of 600 million. The fee is completely subtracted from the shard 0 account as that shard does not know what is the actual cost of the call. The tx ends up executing on shard 1 but consumes only 10 million. The resulting SCR towards the shard 0 will have a refund value of 0 because the penalize too much gas feature is on.

node/external/timemachine/fee/feeComputer_test.go Outdated Show resolved Hide resolved
initiallyPaidFee, err := atp.feeComputer.ComputeTransactionFee(tx.Tx, int(tx.Epoch))
if err != nil {
log.Warn("populateInitiallyPaidFee(): unexpected condition, cannot compute fee", "tx", tx.Hash)
return
Copy link
Contributor

Choose a reason for hiding this comment

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

so in this case the tx.InitiallyPaidFee is empty as "no fee"?
The return is no different as of the return on L133. How can we know something went wrong other than looking in the logs?

The error is propagated from this call:
feeComputer.createEconomicsInstance(epoch int) which was kind of tested in the constructor already in order to not hit "late construction errors due to programming errors"
Wondering if we can get rid of the error parameter and ease the handling results as seen in this component

Copy link
Contributor

Choose a reason for hiding this comment

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

outdated log message? should have been populateComputedFieldInitiallyPaidFee() instead of populateInitiallyPaidFee()

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Good catch & simplification.
Fixed to not return an error in ComputeTransactionFee, indeed.

Also fixed the outdated log message.


isZero := initiallyPaidFee.Cmp(big.NewInt(0)) == 0
if isZero {
return
Copy link
Contributor

Choose a reason for hiding this comment

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

why not setting tx.InitiallyPaidFee to "0" and then return? Will be more consistent when consuming the request.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Previously, I wanted to not have the field in the response if that's zero ("0" will not be omitted by the serializer). However, on a second thought, changed to:

func (atp *apiTransactionProcessor) populateComputedFieldInitiallyPaidFee(tx *transaction.ApiTransactionResult) {
	// Only user-initiated transactions will present an initially paid fee.
	if tx.Type == string(transaction.TxTypeNormal) || tx.Type == string(transaction.TxTypeInvalid) {
		fee := atp.feeComputer.ComputeTransactionFee(tx.Tx, int(tx.Epoch))
		tx.InitiallyPaidFee = fee.String()
	}
}

@iulianpascalau, @bogdan-rosianu, @miiu96, is this all right?

Copy link
Contributor

Choose a reason for hiding this comment

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

actually, for 0 it will still return "" because it's a big.Int 🤦‍♂️

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Will handle this in next PR 🙏

return &refundDetector{}
}

// Also see: https://github.com/ElrondNetwork/elastic-indexer-go/blob/master/process/transactions/scrsDataToTransactions.go
Copy link
Contributor

Choose a reason for hiding this comment

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

wondering how we can remove all these code duplicates

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

One option would be to create a new repository (and go package), such as transaction-decoder or transaction-classifier, independent of any other package. Then, we would reference this package in elrond-go and elastic-indexer-go.

The newly created repository / package would be quite stable in practice.

E.g. @tanghel created this repository for the JS ecosystem. Similarly, we can create extra, small and stable packages (and with no dependencies) for go.

Copy link
Contributor

Choose a reason for hiding this comment

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

yup
I think we can easily place this in elrond-go-core since it is a business core-logic function

initiallyPaidFee, err := atp.feeComputer.ComputeTransactionFee(tx.Tx, int(tx.Epoch))
if err != nil {
log.Warn("populateInitiallyPaidFee(): unexpected condition, cannot compute fee", "tx", tx.Hash)
return
Copy link
Contributor

Choose a reason for hiding this comment

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

outdated log message? should have been populateComputedFieldInitiallyPaidFee() instead of populateInitiallyPaidFee()

node/external/transactionAPI/refundDetector.go Outdated Show resolved Hide resolved
node/external/transactionAPI/refundDetector.go Outdated Show resolved Hide resolved
node/external/transactionAPI/refundDetector.go Outdated Show resolved Hide resolved
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants