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

Optimized trie re-creation for VM Queries, adjust some logs #5977

Merged
merged 14 commits into from
Feb 23, 2024
51 changes: 31 additions & 20 deletions process/smartContract/scQueryService.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,18 @@ import (
"github.com/multiversx/mx-chain-go/process"
"github.com/multiversx/mx-chain-go/process/smartContract/scrCommon"
"github.com/multiversx/mx-chain-go/sharding"
logger "github.com/multiversx/mx-chain-logger-go"
vmcommon "github.com/multiversx/mx-chain-vm-common-go"
"github.com/multiversx/mx-chain-vm-common-go/parsers"
)

var _ process.SCQueryService = (*SCQueryService)(nil)

var logQueryService = logger.GetOrCreate("process/smartcontract.queryService")

// MaxGasLimitPerQuery - each unit is the equivalent of 1 nanosecond processing time
const MaxGasLimitPerQuery = 300_000_000_000
const epochDifferenceToConsiderHistory = 2

// SCQueryService can execute Get functions over SC to fetch stored values
type SCQueryService struct {
Expand All @@ -39,7 +43,6 @@ type SCQueryService struct {
blockChainHook process.BlockChainHookWithAccountsAdapter
mainBlockChain data.ChainHandler
apiBlockChain data.ChainHandler
numQueries int
gasForQuery uint64
wasmVMChangeLocker common.Locker
bootstrapper process.Bootstrapper
Expand Down Expand Up @@ -179,8 +182,7 @@ func (service *SCQueryService) shouldAllowQueriesExecution() bool {
}

func (service *SCQueryService) executeScCall(query *process.SCQuery, gasPrice uint64) (*vmcommon.VMOutput, common.BlockInfo, error) {
log.Trace("executeScCall", "function", query.FuncName, "numQueries", service.numQueries)
service.numQueries++
logQueryService.Trace("executeScCall", "address", query.ScAddress, "function", query.FuncName, "blockNonce", query.BlockNonce.Value, "blockHash", query.BlockHash)
Copy link
Contributor

Choose a reason for hiding this comment

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

Debate-able if L184 and L197 should be at debug level.


shouldEarlyExitBecauseOfSyncState := query.ShouldBeSynced && service.bootstrapper.GetNodeState() == common.NsNotSynchronized
if shouldEarlyExitBecauseOfSyncState {
Expand All @@ -198,10 +200,7 @@ func (service *SCQueryService) executeScCall(query *process.SCQuery, gasPrice ui
return nil, nil, err
}

accountsAdapter := service.blockChainHook.GetAccountsAdapter()

holder := holders.NewRootHashHolder(blockRootHash, core.OptionalUint32{Value: blockHeader.GetEpoch(), HasValue: true})
err = accountsAdapter.RecreateTrieFromEpoch(holder)
err = service.recreateTrie(blockRootHash, blockHeader)
if err != nil {
return nil, nil, err
}
Expand Down Expand Up @@ -230,15 +229,6 @@ func (service *SCQueryService) executeScCall(query *process.SCQuery, gasPrice ui
return nil, nil, err
}

if service.hasRetriableExecutionError(vmOutput) {
log.Error("Retriable execution error detected. Will retry (once) executeScCall()", "returnCode", vmOutput.ReturnCode, "returnMessage", vmOutput.ReturnMessage)

vmOutput, err = vm.RunSmartContractCall(vmInput)
if err != nil {
return nil, nil, err
}
}

if query.SameScState {
err = service.checkForRootHashChanges(rootHashBeforeExecution)
if err != nil {
Expand All @@ -259,6 +249,31 @@ func (service *SCQueryService) executeScCall(query *process.SCQuery, gasPrice ui
return vmOutput, blockInfo, nil
}

func (service *SCQueryService) recreateTrie(blockRootHash []byte, blockHeader data.HeaderHandler) error {
if check.IfNil(blockHeader) {
return process.ErrNilBlockHeader
}

accountsAdapter := service.blockChainHook.GetAccountsAdapter()
if blockHeader.GetEpoch()+epochDifferenceToConsiderHistory >= service.getCurrentEpoch() {
logQueryService.Trace("calling RecreateTrie, for recent history", "block", blockHeader.GetNonce(), "rootHash", blockRootHash)
return accountsAdapter.RecreateTrie(blockRootHash)
}

logQueryService.Trace("calling RecreateTrieFromEpoch, for older history", "block", blockHeader.GetNonce(), "rootHash", blockRootHash)
holder := holders.NewRootHashHolder(blockRootHash, core.OptionalUint32{Value: blockHeader.GetEpoch(), HasValue: true})
return accountsAdapter.RecreateTrieFromEpoch(holder)
bogdan-rosianu marked this conversation as resolved.
Show resolved Hide resolved
}

func (service *SCQueryService) getCurrentEpoch() uint32 {
header := service.mainBlockChain.GetCurrentBlockHeader()
if check.IfNil(header) {
return 0
}

return header.GetEpoch()
}

// TODO: extract duplicated code with nodeBlocks.go
func (service *SCQueryService) extractBlockHeaderAndRootHash(query *process.SCQuery) (data.HeaderHandler, []byte, error) {
if len(query.BlockHash) > 0 {
Expand Down Expand Up @@ -417,10 +432,6 @@ func (service *SCQueryService) createVMCallInput(query *process.SCQuery, gasPric
return vmContractCallInput
}

func (service *SCQueryService) hasRetriableExecutionError(vmOutput *vmcommon.VMOutput) bool {
return vmOutput.ReturnMessage == "allocation error"
}

// ComputeScCallGasLimit will estimate how many gas a transaction will consume
func (service *SCQueryService) ComputeScCallGasLimit(tx *transaction.Transaction) (uint64, error) {
argParser := parsers.NewCallArgsParser()
Expand Down
2 changes: 1 addition & 1 deletion process/smartContract/scQueryServiceDispatcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ func (sqsd *scQueryServiceDispatcher) Close() error {
for _, scQueryService := range sqsd.list {
err := scQueryService.Close()
if err != nil {
log.Error("error while closing inner SC query service in scQueryServiceDispatcher.Close", "error", err)
logQueryService.Error("error while closing inner SC query service in scQueryServiceDispatcher.Close", "error", err)
errFound = err
}
}
Expand Down
Loading
Loading