-
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
Block coordinates on vm query #5447
Block coordinates on vm query #5447
Conversation
Codecov Report
Additional details and impacted files@@ Coverage Diff @@
## feat/vmquery_with_block_coordinates #5447 +/- ##
======================================================================
Coverage ? 80.07%
======================================================================
Files ? 706
Lines ? 93619
Branches ? 0
======================================================================
Hits ? 74965
Misses ? 13303
Partials ? 5351 ☔ 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.
small comments. tested it, works well 👍
|
||
// GetCurrentBlockRootHash returns the current block root hash from the main chain handler, if no local root hash is set | ||
// if there is a local root hash, it will be returned until its reset | ||
func (abc *apiBlockchain) GetCurrentBlockRootHash() []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.
in a normal VM Query, is SetCurrentBlockHeaderAndRootHash
called each time? Otherwise, a gateway user might send a request for a block from yesterday and the next request (from another user, without coordinates) will use the root hash from yesterday instead of the current one
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.
tried to cover all the cases when executeScCall
would early exit, in order to properly reset the root hash and avoid this situation
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 it need to reset at exit?
I would instead, from the API call prepare the apiBlockchain with either the main blockchain current data, or with the preferred blockchain data given by the developer, and then do the sc query/etc.
In that case there should be no edge cases that need to be taken care of, and will be more straight forward as you will always set the block coordinates you are working with on each of the calls.
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.
implemented the suggestion
return process.ErrNilHistoryRepository | ||
} | ||
if check.IfNil(arg.ScheduledTxsExecutionHandler) { | ||
return process.ErrNilScheduledTxsExecutionHandler |
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 sure, but I think that for genesis, a disabled scheduled txs execution handler would have been enough
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.
exactly, I do not see the reason for injecting this on the genesis processor
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.
removed
pcf.txLogsProcessor = txLogsProcessor | ||
genesisBlocks, initialTxs, err := pcf.generateGenesisHeadersAndApplyInitialBalances() | ||
genesisBlocks, initialTxs, err := pcf.generateGenesisHeadersAndApplyInitialBalances(scheduledTxsExecutionHandler) |
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 this change? Why do we need to inject the scheduledTxsExecutionHandler as a parameter?
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.
agree, I don't see where this will be needed for the VM query
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.
removed it
return process.ErrNilHistoryRepository | ||
} | ||
if check.IfNil(arg.ScheduledTxsExecutionHandler) { | ||
return process.ErrNilScheduledTxsExecutionHandler |
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.
exactly, I do not see the reason for injecting this on the genesis processor
} | ||
|
||
return smartContract.NewSCQueryService(argsNewSCQueryService) | ||
} | ||
|
||
func createNewAccountsAdapterApi(args *scQueryElementArgs, chainHandler data.ChainHandler) (state.AccountsAdapterAPI, 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.
so we will create a new trie for each SC query service instance.
I think we have this, in one form or another, when we create the AccountsDBApi instance. We just need to create more of those instances and pass them to each SC query service element.
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.
AccountsDBApi is indeed called below, what we were missing in the original create accounts adapter was a separate merkle trie instance for each of the sc query instances, and a separate chain handler.
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 more AccountsDBApi instances as it is easier to manage the inner trie instances that way. AccountsDB is just a wrapper over the trie.
query = prepareScQuery(query) | ||
vmInput := service.createVMCallInput(query, gasPrice) | ||
vmOutput, err := vm.RunSmartContractCall(vmInput) | ||
service.wasmVMChangeLocker.RUnlock() | ||
if err != nil { | ||
// Cleaning the current root hash so the real one would be returned further | ||
_ = service.blockChain.SetCurrentBlockHeaderAndRootHash(nil, 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.
can call this on a defer function after L207
|
||
// GetCurrentBlockRootHash returns the current block root hash from the main chain handler, if no local root hash is set | ||
// if there is a local root hash, it will be returned until its reset | ||
func (abc *apiBlockchain) GetCurrentBlockRootHash() []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.
Why would it need to reset at exit?
I would instead, from the API call prepare the apiBlockchain with either the main blockchain current data, or with the preferred blockchain data given by the developer, and then do the sc query/etc.
In that case there should be no edge cases that need to be taken care of, and will be more straight forward as you will always set the block coordinates you are working with on each of the calls.
index: 0, | ||
processingMode: args.processingMode, |
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.
what is this for?
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.
it is used for ArgsAccountsDB
} | ||
|
||
return smartContract.NewSCQueryService(argsNewSCQueryService) | ||
} | ||
|
||
func createNewAccountsAdapterApi(args *scQueryElementArgs, chainHandler data.ChainHandler) (state.AccountsAdapterAPI, 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.
AccountsDBApi is indeed called below, what we were missing in the original create accounts adapter was a separate merkle trie instance for each of the sc query instances, and a separate chain handler.
pcf.txLogsProcessor = txLogsProcessor | ||
genesisBlocks, initialTxs, err := pcf.generateGenesisHeadersAndApplyInitialBalances() | ||
genesisBlocks, initialTxs, err := pcf.generateGenesisHeadersAndApplyInitialBalances(scheduledTxsExecutionHandler) |
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.
agree, I don't see where this will be needed for the VM query
} | ||
|
||
func (service *SCQueryService) getBlockRootHash(headerHash []byte, header data.HeaderHandler) []byte { | ||
blockRootHash, err := service.scheduledTxsExecutionHandler.GetScheduledRootHashForHeaderWithEpoch( |
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 I see why you added the scheduled execution handler, but you can use instead getBlockHeaderByNonce and request the header.Nonce+1 and check on that the scheduledRootHash.
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 can discuss as well, I see that this is similar to how it is done for on nodeBlocks.go
This code appears duplicated, maybe it would be better to extract a component and reuse it in both places instead.
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 a TODO for the duplicated code
StorageService: arg.Data.StorageService(), | ||
Marshaller: arg.Core.InternalMarshalizer(), | ||
Hasher: arg.Core.Hasher(), | ||
Uint64ByteSliceConverter: arg.Core.Uint64ByteSliceConverter(), | ||
} | ||
queryService, err := smartContract.NewSCQueryService(argsNewSCQueryService) |
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 really necessary to have a real sc query service on the genesis block creator? @iulianpascalau
I see we execute the genesis node staking transactions and then we use the sc query system to verify that the node is indeed staked via sc query.
Also for the DNS contracts we use it to check the version.
Maybe we should discuss if we really 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.
At the time it was the easiest way to verify that the genesis was constructed correctly. As seen, during testing, without these checks we can have a malformed genesis state if we got some genesis parameters wrong (like the initial number of staked nodes). I strongly encourage to keep them as they are now in order to safeguard the genesis state creation.
} | ||
|
||
header := service.getBlockHeader(blockHeader) | ||
return header, header.GetRootHash(), 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.
I see that you extract the roothash from the following block after the 'block by hash'
I think the header to return is exactly the block by hash, but the rootHash to return here should be the ScheduledRootHash from the following block after the block by hash
return blockHeader, header.GetScheduledRootHash, 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.
updated
} | ||
|
||
func (service *SCQueryService) getBlockHeader(currentHeader data.HeaderHandler) data.HeaderHandler { | ||
header, _, err := service.getBlockHeaderByNonce(currentHeader.GetNonce() + 1) |
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 nonce +1 here?
Maybe rename the caller method to getNextBlockHeader?
also I don't think we need this method, as we already have getBlockByNonce (current header nonce +1), and an error on this get should not use the current header, but propagate the 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.
removed the method and updated as suggested
} | ||
|
||
func (service *SCQueryService) checkForRootHashChanges(rootHashBefore []byte) error { | ||
rootHashAfter := service.blockChain.GetCurrentBlockRootHash() | ||
rootHashAfter := service.mainBlockChain.GetCurrentBlockRootHash() |
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.
shouldn't it verify this against the api blockchain block roothash?
I would only use the mainBlockChain to set the apiBlockChain data when the API is called without block parameters (so for current)
return ErrOperationNotPermitted | ||
// RecreateTrie is used to reload the trie based on an existing rootHash | ||
func (accountsDB *accountsDBApi) RecreateTrie(rootHash []byte) error { | ||
_, err := accountsDB.doRecreateTrieWithBlockInfo(holders.NewBlockInfo([]byte{}, 0, rootHash)) |
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 you afterwards use the blockInfo set on the accountsDBApi?
if yes, the maybe use instead
accountsDB.innerAccountsAdapter.RecreateTrie(rootHash)
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.
reused doRecreateTrieWithBlockInfo
method because the resulted blockInfo is then returned on GetAccountWithBlockInfo
and RootHash
if err != nil { | ||
return nil, nil, err | ||
} | ||
|
||
header := service.getBlockHeader(blockHeader) | ||
return header, header.GetRootHash(), nil | ||
blockHeader, _, err := service.getBlockHeaderByNonce(currentHeader.GetNonce() + 1) |
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 looks similar to lines 268-278, can you maybe extract a method (getRootHashForBlock)?
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.
pushed
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
?