diff --git a/state/factory/factory.go b/state/factory/factory.go index 67878d01c8..e7af08fc57 100644 --- a/state/factory/factory.go +++ b/state/factory/factory.go @@ -413,16 +413,7 @@ func (sf *factory) SimulateExecution( if err != nil { return nil, nil, errors.Wrap(err, "failed to obtain working set from state factory") } - cfg := &protocol.SimulateOptionConfig{} - for _, opt := range opts { - opt(cfg) - } - if cfg.PreOpt != nil { - if err := cfg.PreOpt(ws); err != nil { - return nil, nil, err - } - } - return evm.SimulateExecution(ctx, ws, caller, elp) + return simulateExecution(ctx, ws, caller, elp, opts...) } // ReadContractStorage reads contract's storage @@ -438,9 +429,7 @@ func (sf *factory) ReadContractStorage(ctx context.Context, contract address.Add // PutBlock persists all changes in RunActions() into the DB func (sf *factory) PutBlock(ctx context.Context, blk *block.Block) error { - sf.mutex.Lock() timer := sf.timerFactory.NewTimer("Commit") - sf.mutex.Unlock() defer timer.End() producer := blk.PublicKey().Address() if producer == nil { diff --git a/state/factory/factory_withheight.go b/state/factory/factory_withheight.go index da78761b12..46bea4c387 100644 --- a/state/factory/factory_withheight.go +++ b/state/factory/factory_withheight.go @@ -11,7 +11,11 @@ import ( "github.com/pkg/errors" + "github.com/iotexproject/iotex-address/address" + "github.com/iotexproject/iotex-core/v2/action" "github.com/iotexproject/iotex-core/v2/action/protocol" + "github.com/iotexproject/iotex-core/v2/action/protocol/execution/evm" + "github.com/iotexproject/iotex-core/v2/pkg/tracer" "github.com/iotexproject/iotex-core/v2/state" ) @@ -21,8 +25,6 @@ type factoryWithHeight struct { } func (sf *factoryWithHeight) State(s interface{}, opts ...protocol.StateOption) (uint64, error) { - sf.mutex.RLock() - defer sf.mutex.RUnlock() cfg, err := processOptions(opts...) if err != nil { return 0, err @@ -30,8 +32,11 @@ func (sf *factoryWithHeight) State(s interface{}, opts ...protocol.StateOption) if cfg.Keys != nil { return 0, errors.Wrap(ErrNotSupported, "Read state with keys option has not been implemented yet") } - if sf.height > sf.currentChainHeight { - return 0, errors.Errorf("query height %d is higher than tip height %d", sf.height, sf.currentChainHeight) + sf.mutex.RLock() + tipHeight := sf.currentChainHeight + sf.mutex.RUnlock() + if sf.height > tipHeight { + return 0, errors.Errorf("query height %d is higher than tip height %d", sf.height, tipHeight) } return sf.height, sf.stateAtHeight(sf.height, cfg.Namespace, cfg.Key, s) } @@ -58,9 +63,10 @@ func (sf *factoryWithHeight) stateAtHeight(height uint64, ns string, key []byte, func (sf *factoryWithHeight) States(opts ...protocol.StateOption) (uint64, state.Iterator, error) { sf.mutex.RLock() - defer sf.mutex.RUnlock() - if sf.height > sf.currentChainHeight { - return 0, nil, errors.Errorf("query height %d is higher than tip height %d", sf.height, sf.currentChainHeight) + tipHeight := sf.currentChainHeight + sf.mutex.RUnlock() + if sf.height > tipHeight { + return 0, nil, errors.Errorf("query height %d is higher than tip height %d", sf.height, tipHeight) } cfg, err := processOptions(opts...) if err != nil { @@ -87,3 +93,26 @@ func (sf *factoryWithHeight) States(opts ...protocol.StateOption) (uint64, state } return sf.height, iter, err } + +func (sf *factoryWithHeight) SimulateExecution( + ctx context.Context, + caller address.Address, + elp action.Envelope, + opts ...protocol.SimulateOption, +) ([]byte, *action.Receipt, error) { + ctx, span := tracer.NewSpan(ctx, "factoryWithHeight.SimulateExecution") + defer span.End() + ws, err := sf.newWorkingSet(ctx, sf.height) + if err != nil { + return nil, nil, errors.Wrap(err, "failed to obtain working set from state factory") + } + return simulateExecution(ctx, ws, caller, elp) +} + +func (sf *factoryWithHeight) ReadContractStorage(ctx context.Context, contract address.Address, key []byte) ([]byte, error) { + ws, err := sf.newWorkingSet(ctx, sf.height) + if err != nil { + return nil, errors.Wrap(err, "failed to generate working set from state factory") + } + return evm.ReadContractStorage(ctx, ws, contract, key) +} diff --git a/state/factory/util.go b/state/factory/util.go index 9e25bff81c..d955a4f931 100644 --- a/state/factory/util.go +++ b/state/factory/util.go @@ -11,10 +11,12 @@ import ( "github.com/iotexproject/go-pkgs/bloom" "github.com/iotexproject/go-pkgs/crypto" "github.com/iotexproject/go-pkgs/hash" + "github.com/iotexproject/iotex-address/address" "github.com/pkg/errors" "github.com/iotexproject/iotex-core/v2/action" "github.com/iotexproject/iotex-core/v2/action/protocol" + "github.com/iotexproject/iotex-core/v2/action/protocol/execution/evm" "github.com/iotexproject/iotex-core/v2/blockchain/block" "github.com/iotexproject/iotex-core/v2/blockchain/genesis" "github.com/iotexproject/iotex-core/v2/db" @@ -223,3 +225,22 @@ func newTwoLayerTrie(ns string, dao db.KVStore, rootKey string, create bool) (tr } return mptrie.NewTwoLayerTrie(dbForTrie, rootKey), nil } + +func simulateExecution( + ctx context.Context, + ws *workingSet, + caller address.Address, + elp action.Envelope, + opts ...protocol.SimulateOption, +) ([]byte, *action.Receipt, error) { + cfg := &protocol.SimulateOptionConfig{} + for _, opt := range opts { + opt(cfg) + } + if cfg.PreOpt != nil { + if err := cfg.PreOpt(ws); err != nil { + return nil, nil, err + } + } + return evm.SimulateExecution(ctx, ws, caller, elp) +}