-
Notifications
You must be signed in to change notification settings - Fork 198
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
Exchanges integration: return invalid transactions as well, refactor status #2237
Conversation
data/transaction/status.go
Outdated
// TxStatusExecuted = received and executed | ||
TxStatusExecuted TxStatus = "executed" | ||
// TxStatusNotExecuted = received and executed with error | ||
// Question for review: not executed means "executed with error", correct? |
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.
yes for transaction that are indexed in elasticseach 'not executed' is status for transaction executed with error.
data/transaction/status.go
Outdated
|
||
// ComputeStatusWhenInStorageKnowingMiniblock computes the transaction status for a historical transaction | ||
func (params *StatusComputer) ComputeStatusWhenInStorageKnowingMiniblock() TxStatus { | ||
if params.MiniblockType == block.InvalidBlock { |
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 you can add a method isMiniblockInvalid
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.
tx.MiniBlockType = miniblock.Type | ||
tx.MiniBlockHash = hex.EncodeToString([]byte(miniblockHash)) | ||
|
||
tx.Status = (&transaction.StatusComputer{ |
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.
nice approach
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.
Thanks!
node/errors.go
Outdated
// ErrTransactionNotFound signals that a transaction was not found | ||
var ErrTransactionNotFound = errors.New("transaction not found") | ||
|
||
// ErrCannotRetrieveTransaction signals that a transaction was not found |
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.
update comment
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.
Fixed.
} | ||
|
||
// merge data about transaction from history storer and transaction storer | ||
tx = putHistoryFieldsInTransaction(tx, miniblockMetadata) | ||
putHistoryFieldsInTransaction(tx, miniblockMetadata) |
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 you can add this method inside structure ApiTransactionResult
func (ats *ApiTransactionResult) PutHistoryFieldsInTransaction(miniblockMetadata *fullHistory.MiniblockMetadata)
just a suggestion
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 a good suggestion, indeed, to encapsulate this logic in ApiTransactionResult
. The issue is, though, that ApiTransactionResult
is defined in transaction
package, while miniblockMetadata
in fullHistory
package - and that would require an additional interface - we can do in the future.
data/transaction/status.go
Outdated
// TxStatusExecuted = received and executed | ||
TxStatusExecuted TxStatus = "executed" | ||
// TxStatusNotExecuted = received and executed with error | ||
// Question for review: not executed means "executed with error", correct? |
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.
not-executed is confusing. Not-executed would be those transaction which really do not get included in block (lower nonce for example - user sending two transactions with same nonce and only 1 getting executed).
Than we have the scenario when the transaction's status in invalid - in that case the gas was consumed from the account, and the nonce increased.
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.
Currently, also Explorer displays not executed
for executed transactions (but, say, with user error). Do we keep it like this for the moment or do we change 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.
we should change that as well.
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.
Only now I see that TxStatusNotExecuted
is only used in the context of the transactions simulator:
node/txsimulator/txSimulator.go, line 63
And seems to be used well there.
The other occurrence, completely unrelated, is in the indexer component (which, actually, defines a separate set of statuses): txStatusNotExecuted = "Not Executed"
.
I don't want to change the indexer status in this PR (a bit risky), but we can do that in another PR.
Ok?
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.
Ok. that is in another PR changing in the indexer.
|
||
// ComputeStatusWhenInPool computes the transaction status when transaction is in pool | ||
func (params *StatusComputer) ComputeStatusWhenInPool() TxStatus { | ||
if params.isContractDeploy() { |
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 is this check 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.
params.isDestinationMe() && params.isCrossShard()
would be evaluated to true
for deployments, but still we don't want to return TxStatusPartiallyExecuted
in that case (seen in previous PR with the status for deployments).
Does it make sense?
Fixed (moved condition).
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.
isCrossShard should return false in case of deployment.
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.
Currently, isCrossShard()
is implemented as follows:
func (params *StatusComputer) isCrossShard() bool {
return params.SourceShard != params.DestinationShard
}
While ComputeStatusWhenInPool()
is fed the parameters as follows - in a generic manner, not knowing anything special about the Zero address:
SourceShard: n.shardCoordinator.ComputeId(tx.Tx.GetSndAddr()),
DestinationShard: n.shardCoordinator.ComputeId(tx.Tx.GetRcvAddr()),
Receiver: tx.Tx.GetRcvAddr(),
TransactionData: tx.Data,
SelfShard: n.shardCoordinator.SelfId(),
Thus, the isContractDeploy()
has to be checked first (because the check isDestinationMe() && isCrossShard()
will be fooled otherwise).
We could change isCrossShard()
to call isContractDeploy()
, but perhaps that would be a bit harder to reason about in the future.
Fixed to be more explicit, as before. Is it all right?
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.
in this case shardCoordinator computeID should have returned selfID. for the empty address.
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.
in computestatuswheninPool you might use another function a wrapper on top of computeID where you add the empty check.
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.
Let's keep compute ID completely out of the statusComputer
, please.
Previous location, previous PR (reviewed):
https://github.com/ElrondNetwork/elrond-go/pull/2234/files
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.
Sometimes it happens that these things get approved by a PR and the next one requests changes in the same zone. It would be better to have correct shardId computation at the base. In this case shard coordinator, or computestatus
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.
Left as it is, as discussed separately.
// Question for review: here we cannot know if the transaction is, actually, "invalid". | ||
// However, when "fullHistory" indexing is enabled, this function is not used. | ||
|
||
if params.isDestinationMe() || params.isContractDeploy() { |
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 attach the receipt / smart contract result to the transaction - as we have in elastic search - than it it simple to decide the status of the transaction. It is not a trivial task, this can stay as it is.
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.
delete the comments question for review
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.
Fixed comment, moved above function.
node/blockAPI/baseBlock.go
Outdated
case block.SmartContractResultBlock: | ||
return bap.getTxsFromMiniblock(miniBlock, epoch, "unsigned", dataRetriever.UnsignedTransactionUnit) | ||
return bap.getTxsFromMiniblock(miniBlock, miniblockHash, epoch, "unsigned", dataRetriever.UnsignedTransactionUnit) |
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.
make some constants for magic strings
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.
Fixed.
data/transaction/status.go
Outdated
// TxStatusExecuted = received and executed | ||
TxStatusExecuted TxStatus = "executed" | ||
// TxStatusNotExecuted = received and executed with error | ||
// Question for review: not executed means "executed with error", correct? |
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 change that as well.
// Question for review: here we cannot know if the transaction is, actually, "invalid". | ||
// However, when "fullHistory" indexing is enabled, this function is not used. | ||
|
||
if params.isDestinationMe() || params.isContractDeploy() { |
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.
delete the comments question for review
|
||
// ComputeStatusWhenInPool computes the transaction status when transaction is in pool | ||
func (params *StatusComputer) ComputeStatusWhenInPool() TxStatus { | ||
if params.isContractDeploy() { |
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.
in computestatuswheninPool you might use another function a wrapper on top of computeID where you add the empty check.
node/errors.go
Outdated
@@ -195,3 +190,16 @@ var ErrNilTxSimulatorProcessor = errors.New("nil transaction simulator processor | |||
|
|||
// ErrNilIntermediateProcessorContainer signals that intermediate processors container is nil | |||
var ErrNilIntermediateProcessorContainer = errors.New("intermediate processor container is nil") | |||
|
|||
// NewErrTransactionNotFound creates an error which signals that a transaction was not found | |||
func NewErrTransactionNotFound(originalErr error) 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.
do we really need these ?
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.
Let's have them, please.
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.
Fixed.
node/nodeTransactions.go
Outdated
} | ||
|
||
txBytes, txType, found := n.getTxBytesFromStorageByEpoch(hash, miniblockMetadata.Epoch) | ||
if !found { | ||
log.Warn("getFullHistoryTransaction(): unexpected condition, cannot find transaction in storage") | ||
return nil, ErrCannotRetrieveTransaction | ||
return nil, NewErrCannotRetrieveTransaction(err) |
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.
error wrapping can happen directly here.
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.
Let's use the wrappers defined in errors.go
, please (a bit cleaner).
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.
Fixed.
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.
System tests passed.
refactor computation of transaction status (encapsulate in
StatusComputer
)add more tests, refactor tests
include invalid transactions in response of
/block?withTxs
deprecated field
Status
inMiniblockMetadata
storage - will not be used anymore. Though, now,miniblock Type
is required to compute status - thus, a breaking change for theblockAPI
- but since we will implement replay & index rebuild, this is a non-issue.added new field
Type
inMiniblockMetadata
storage (see above)also return
miniblock hash
in transaction response, where possibleHow to test:
hyperblock
wrt. tohyperblockNonce
from step aboveminiblock type
is correctly set onget transaction
responsesminiblock hash
,source shard
,destination shard
are present onget transaction
responsesGet transaction route:
http://proxy:8080/transaction/abracadabra
Get hyperblock route:
http://proxy:8080/hyperblock/by-nonce/42