github.com/iotexproject/iotex-core@v1.14.1-rc1/state/factory/workingset.go (about)

     1  // Copyright (c) 2022 IoTeX Foundation
     2  // This source code is provided 'as is' and no warranties are given as to title or non-infringement, merchantability
     3  // or fitness for purpose and, to the extent permitted by law, all liability for your use of the code is disclaimed.
     4  // This source code is governed by Apache License 2.0 that can be found in the LICENSE file.
     5  
     6  package factory
     7  
     8  import (
     9  	"context"
    10  	"sort"
    11  
    12  	"github.com/iotexproject/go-pkgs/hash"
    13  	"github.com/iotexproject/iotex-proto/golang/iotextypes"
    14  	"github.com/pkg/errors"
    15  	"github.com/prometheus/client_golang/prometheus"
    16  	"go.uber.org/zap"
    17  
    18  	"github.com/iotexproject/iotex-address/address"
    19  
    20  	"github.com/iotexproject/iotex-core/action"
    21  	"github.com/iotexproject/iotex-core/action/protocol"
    22  	accountutil "github.com/iotexproject/iotex-core/action/protocol/account/util"
    23  	"github.com/iotexproject/iotex-core/actpool"
    24  	"github.com/iotexproject/iotex-core/actpool/actioniterator"
    25  	"github.com/iotexproject/iotex-core/blockchain/block"
    26  	"github.com/iotexproject/iotex-core/blockchain/genesis"
    27  	"github.com/iotexproject/iotex-core/pkg/log"
    28  	"github.com/iotexproject/iotex-core/state"
    29  )
    30  
    31  var (
    32  	_stateDBMtc = prometheus.NewCounterVec(
    33  		prometheus.CounterOpts{
    34  			Name: "iotex_state_db",
    35  			Help: "IoTeX State DB",
    36  		},
    37  		[]string{"type"},
    38  	)
    39  
    40  	errInvalidSystemActionLayout = errors.New("system action layout is invalid")
    41  )
    42  
    43  func init() {
    44  	prometheus.MustRegister(_stateDBMtc)
    45  }
    46  
    47  type (
    48  	workingSet struct {
    49  		height    uint64
    50  		store     workingSetStore
    51  		finalized bool
    52  		dock      protocol.Dock
    53  		receipts  []*action.Receipt
    54  	}
    55  )
    56  
    57  func newWorkingSet(height uint64, store workingSetStore) *workingSet {
    58  	return &workingSet{
    59  		height: height,
    60  		store:  store,
    61  		dock:   protocol.NewDock(),
    62  	}
    63  }
    64  
    65  func (ws *workingSet) digest() (hash.Hash256, error) {
    66  	if !ws.finalized {
    67  		return hash.ZeroHash256, errors.New("workingset has not been finalized yet")
    68  	}
    69  	return ws.store.Digest(), nil
    70  }
    71  
    72  func (ws *workingSet) Receipts() ([]*action.Receipt, error) {
    73  	if !ws.finalized {
    74  		return nil, errors.New("workingset has not been finalized yet")
    75  	}
    76  	return ws.receipts, nil
    77  }
    78  
    79  // Height returns the Height of the block being worked on
    80  func (ws *workingSet) Height() (uint64, error) {
    81  	return ws.height, nil
    82  }
    83  
    84  func (ws *workingSet) validate(ctx context.Context) error {
    85  	if ws.finalized {
    86  		return errors.Errorf("cannot run action on a finalized working set")
    87  	}
    88  	blkCtx := protocol.MustGetBlockCtx(ctx)
    89  	if blkCtx.BlockHeight != ws.height {
    90  		return errors.Errorf(
    91  			"invalid block height %d, %d expected",
    92  			blkCtx.BlockHeight,
    93  			ws.height,
    94  		)
    95  	}
    96  	return nil
    97  }
    98  
    99  func (ws *workingSet) runActions(
   100  	ctx context.Context,
   101  	elps []*action.SealedEnvelope,
   102  ) ([]*action.Receipt, error) {
   103  	// Handle actions
   104  	receipts := make([]*action.Receipt, 0)
   105  	for _, elp := range elps {
   106  		ctxWithActionContext, err := withActionCtx(ctx, elp)
   107  		if err != nil {
   108  			return nil, err
   109  		}
   110  		receipt, err := ws.runAction(ctxWithActionContext, elp)
   111  		if err != nil {
   112  			return nil, errors.Wrap(err, "error when run action")
   113  		}
   114  		receipts = append(receipts, receipt)
   115  	}
   116  	if protocol.MustGetFeatureCtx(ctx).CorrectTxLogIndex {
   117  		updateReceiptIndex(receipts)
   118  	}
   119  	return receipts, nil
   120  }
   121  
   122  func withActionCtx(ctx context.Context, selp *action.SealedEnvelope) (context.Context, error) {
   123  	var actionCtx protocol.ActionCtx
   124  	var err error
   125  	caller := selp.SenderAddress()
   126  	if caller == nil {
   127  		return nil, errors.New("failed to get address")
   128  	}
   129  	actionCtx.Caller = caller
   130  	actionCtx.ActionHash, err = selp.Hash()
   131  	if err != nil {
   132  		return nil, err
   133  	}
   134  	actionCtx.GasPrice = selp.GasPrice()
   135  	intrinsicGas, err := selp.IntrinsicGas()
   136  	if err != nil {
   137  		return nil, err
   138  	}
   139  	actionCtx.IntrinsicGas = intrinsicGas
   140  	actionCtx.Nonce = selp.Nonce()
   141  
   142  	return protocol.WithActionCtx(ctx, actionCtx), nil
   143  }
   144  
   145  func (ws *workingSet) runAction(
   146  	ctx context.Context,
   147  	selp *action.SealedEnvelope,
   148  ) (*action.Receipt, error) {
   149  	actCtx := protocol.MustGetActionCtx(ctx)
   150  	if protocol.MustGetBlockCtx(ctx).GasLimit < actCtx.IntrinsicGas {
   151  		return nil, action.ErrGasLimit
   152  	}
   153  	// Reject execution of chainID not equal the node's chainID
   154  	if !action.IsSystemAction(selp) {
   155  		if err := validateChainID(ctx, selp.ChainID()); err != nil {
   156  			return nil, err
   157  		}
   158  	}
   159  	// for replay tx, check against deployer whitelist
   160  	g := genesis.MustExtractGenesisContext(ctx)
   161  	if selp.Encoding() == uint32(iotextypes.Encoding_ETHEREUM_UNPROTECTED) && !g.IsDeployerWhitelisted(selp.SenderAddress()) {
   162  		return nil, errors.Errorf("replay deployer %v not whitelisted", selp.SenderAddress().String())
   163  	}
   164  	// Handle action
   165  	reg, ok := protocol.GetRegistry(ctx)
   166  	if !ok {
   167  		return nil, errors.New("protocol is empty")
   168  	}
   169  	selpHash, err := selp.Hash()
   170  	if err != nil {
   171  		return nil, errors.Wrapf(err, "Failed to get hash")
   172  	}
   173  	defer ws.ResetSnapshots()
   174  	if err := ws.freshAccountConversion(ctx, &actCtx); err != nil {
   175  		return nil, err
   176  	}
   177  	for _, actionHandler := range reg.All() {
   178  		receipt, err := actionHandler.Handle(ctx, selp.Action(), ws)
   179  		if err != nil {
   180  			return nil, errors.Wrapf(
   181  				err,
   182  				"error when action %x mutates states",
   183  				selpHash,
   184  			)
   185  		}
   186  		if receipt != nil {
   187  			return receipt, nil
   188  		}
   189  	}
   190  	return nil, errors.New("receipt is empty")
   191  }
   192  
   193  func validateChainID(ctx context.Context, chainID uint32) error {
   194  	blkChainCtx := protocol.MustGetBlockchainCtx(ctx)
   195  	featureCtx := protocol.MustGetFeatureCtx(ctx)
   196  	if featureCtx.AllowCorrectChainIDOnly && chainID != blkChainCtx.ChainID {
   197  		return errors.Wrapf(action.ErrChainID, "expecting %d, got %d", blkChainCtx.ChainID, chainID)
   198  	}
   199  	if featureCtx.AllowCorrectDefaultChainID && (chainID != blkChainCtx.ChainID && chainID != 0) {
   200  		return errors.Wrapf(action.ErrChainID, "expecting %d, got %d", blkChainCtx.ChainID, chainID)
   201  	}
   202  	return nil
   203  }
   204  
   205  func (ws *workingSet) finalize() error {
   206  	if ws.finalized {
   207  		return errors.New("Cannot finalize a working set twice")
   208  	}
   209  	if err := ws.store.Finalize(ws.height); err != nil {
   210  		return err
   211  	}
   212  	ws.finalized = true
   213  
   214  	return nil
   215  }
   216  
   217  func (ws *workingSet) Snapshot() int {
   218  	return ws.store.Snapshot()
   219  }
   220  
   221  func (ws *workingSet) Revert(snapshot int) error {
   222  	return ws.store.RevertSnapshot(snapshot)
   223  }
   224  
   225  func (ws *workingSet) ResetSnapshots() {
   226  	ws.store.ResetSnapshots()
   227  }
   228  
   229  // freshAccountConversion happens between UseZeroNonceForFreshAccount height
   230  // and RefactorFreshAccountConversion height
   231  func (ws *workingSet) freshAccountConversion(ctx context.Context, actCtx *protocol.ActionCtx) error {
   232  	// check legacy fresh account conversion
   233  	if protocol.MustGetFeatureCtx(ctx).UseZeroNonceForFreshAccount &&
   234  		!protocol.MustGetFeatureCtx(ctx).RefactorFreshAccountConversion {
   235  		sender, err := accountutil.AccountState(ctx, ws, actCtx.Caller)
   236  		if err != nil {
   237  			return errors.Wrapf(err, "failed to get the confirmed nonce of sender %s", actCtx.Caller.String())
   238  		}
   239  		if sender.ConvertFreshAccountToZeroNonceType(actCtx.Nonce) {
   240  			if err = accountutil.StoreAccount(ws, actCtx.Caller, sender); err != nil {
   241  				return errors.Wrapf(err, "failed to store converted sender %s", actCtx.Caller.String())
   242  			}
   243  		}
   244  	}
   245  	return nil
   246  }
   247  
   248  // Commit persists all changes in RunActions() into the DB
   249  func (ws *workingSet) Commit(ctx context.Context) error {
   250  	if err := protocolPreCommit(ctx, ws); err != nil {
   251  		return err
   252  	}
   253  	if err := ws.store.Commit(); err != nil {
   254  		return err
   255  	}
   256  	if err := protocolCommit(ctx, ws); err != nil {
   257  		// TODO (zhi): wrap the error and eventually panic it in caller side
   258  		return err
   259  	}
   260  	ws.Reset()
   261  	return nil
   262  }
   263  
   264  // State pulls a state from DB
   265  func (ws *workingSet) State(s interface{}, opts ...protocol.StateOption) (uint64, error) {
   266  	_stateDBMtc.WithLabelValues("get").Inc()
   267  	cfg, err := processOptions(opts...)
   268  	if err != nil {
   269  		return ws.height, err
   270  	}
   271  	value, err := ws.store.Get(cfg.Namespace, cfg.Key)
   272  	if err != nil {
   273  		return ws.height, err
   274  	}
   275  	return ws.height, state.Deserialize(s, value)
   276  }
   277  
   278  func (ws *workingSet) States(opts ...protocol.StateOption) (uint64, state.Iterator, error) {
   279  	cfg, err := processOptions(opts...)
   280  	if err != nil {
   281  		return ws.height, nil, err
   282  	}
   283  	if cfg.Key != nil {
   284  		return 0, nil, errors.Wrap(ErrNotSupported, "Read states with key option has not been implemented yet")
   285  	}
   286  	values, err := ws.store.States(cfg.Namespace, cfg.Keys)
   287  	if err != nil {
   288  		return 0, nil, err
   289  	}
   290  	return ws.height, state.NewIterator(values), nil
   291  }
   292  
   293  // PutState puts a state into DB
   294  func (ws *workingSet) PutState(s interface{}, opts ...protocol.StateOption) (uint64, error) {
   295  	_stateDBMtc.WithLabelValues("put").Inc()
   296  	cfg, err := processOptions(opts...)
   297  	if err != nil {
   298  		return ws.height, err
   299  	}
   300  	ss, err := state.Serialize(s)
   301  	if err != nil {
   302  		return ws.height, errors.Wrapf(err, "failed to convert account %v to bytes", s)
   303  	}
   304  	return ws.height, ws.store.Put(cfg.Namespace, cfg.Key, ss)
   305  }
   306  
   307  // DelState deletes a state from DB
   308  func (ws *workingSet) DelState(opts ...protocol.StateOption) (uint64, error) {
   309  	_stateDBMtc.WithLabelValues("delete").Inc()
   310  	cfg, err := processOptions(opts...)
   311  	if err != nil {
   312  		return ws.height, err
   313  	}
   314  	return ws.height, ws.store.Delete(cfg.Namespace, cfg.Key)
   315  }
   316  
   317  // ReadView reads the view
   318  func (ws *workingSet) ReadView(name string) (interface{}, error) {
   319  	return ws.store.ReadView(name)
   320  }
   321  
   322  // WriteView writeback the view to factory
   323  func (ws *workingSet) WriteView(name string, v interface{}) error {
   324  	return ws.store.WriteView(name, v)
   325  }
   326  
   327  func (ws *workingSet) ProtocolDirty(name string) bool {
   328  	return ws.dock.ProtocolDirty(name)
   329  }
   330  
   331  func (ws *workingSet) Load(name, key string, v interface{}) error {
   332  	return ws.dock.Load(name, key, v)
   333  }
   334  
   335  func (ws *workingSet) Unload(name, key string, v interface{}) error {
   336  	return ws.dock.Unload(name, key, v)
   337  }
   338  
   339  func (ws *workingSet) Reset() {
   340  	ws.dock.Reset()
   341  }
   342  
   343  // createGenesisStates initialize the genesis states
   344  func (ws *workingSet) CreateGenesisStates(ctx context.Context) error {
   345  	if reg, ok := protocol.GetRegistry(ctx); ok {
   346  		for _, p := range reg.All() {
   347  			if gsc, ok := p.(protocol.GenesisStateCreator); ok {
   348  				if err := gsc.CreateGenesisStates(ctx, ws); err != nil {
   349  					return errors.Wrap(err, "failed to create genesis states for protocol")
   350  				}
   351  			}
   352  		}
   353  	}
   354  
   355  	return ws.finalize()
   356  }
   357  
   358  func (ws *workingSet) validateNonce(ctx context.Context, blk *block.Block) error {
   359  	accountNonceMap := make(map[string][]uint64)
   360  	for _, selp := range blk.Actions {
   361  		caller := selp.SenderAddress()
   362  		if caller == nil {
   363  			return errors.New("failed to get address")
   364  		}
   365  		appendActionIndex(accountNonceMap, caller.String(), selp.Nonce())
   366  	}
   367  	return ws.checkNonceContinuity(ctx, accountNonceMap)
   368  }
   369  
   370  func (ws *workingSet) validateNonceSkipSystemAction(ctx context.Context, blk *block.Block) error {
   371  	accountNonceMap := make(map[string][]uint64)
   372  	for _, selp := range blk.Actions {
   373  		if action.IsSystemAction(selp) {
   374  			continue
   375  		}
   376  
   377  		caller := selp.SenderAddress()
   378  		if caller == nil {
   379  			return errors.New("failed to get address")
   380  		}
   381  		srcAddr := caller.String()
   382  		if _, ok := accountNonceMap[srcAddr]; !ok {
   383  			accountNonceMap[srcAddr] = make([]uint64, 0)
   384  		}
   385  		accountNonceMap[srcAddr] = append(accountNonceMap[srcAddr], selp.Nonce())
   386  	}
   387  	return ws.checkNonceContinuity(ctx, accountNonceMap)
   388  }
   389  
   390  func (ws *workingSet) checkNonceContinuity(ctx context.Context, accountNonceMap map[string][]uint64) error {
   391  	var (
   392  		pendingNonce uint64
   393  		useZeroNonce = protocol.MustGetFeatureCtx(ctx).UseZeroNonceForFreshAccount
   394  	)
   395  	// Verify each account's Nonce
   396  	for srcAddr, receivedNonces := range accountNonceMap {
   397  		addr, _ := address.FromString(srcAddr)
   398  		confirmedState, err := accountutil.AccountState(ctx, ws, addr)
   399  		if err != nil {
   400  			return errors.Wrapf(err, "failed to get the confirmed nonce of address %s", srcAddr)
   401  		}
   402  		sort.Slice(receivedNonces, func(i, j int) bool { return receivedNonces[i] < receivedNonces[j] })
   403  		if useZeroNonce {
   404  			pendingNonce = confirmedState.PendingNonceConsideringFreshAccount()
   405  		} else {
   406  			pendingNonce = confirmedState.PendingNonce()
   407  		}
   408  		for i, nonce := range receivedNonces {
   409  			if nonce != pendingNonce+uint64(i) {
   410  				return errors.Wrapf(
   411  					action.ErrNonceTooHigh,
   412  					"the %d-th nonce %d of address %s (init pending nonce %d) is not continuously increasing",
   413  					i,
   414  					nonce,
   415  					srcAddr,
   416  					pendingNonce,
   417  				)
   418  			}
   419  		}
   420  	}
   421  	return nil
   422  }
   423  
   424  func (ws *workingSet) Process(ctx context.Context, actions []*action.SealedEnvelope) error {
   425  	return ws.process(ctx, actions)
   426  }
   427  
   428  func (ws *workingSet) process(ctx context.Context, actions []*action.SealedEnvelope) error {
   429  	if err := ws.validate(ctx); err != nil {
   430  		return err
   431  	}
   432  
   433  	reg := protocol.MustGetRegistry(ctx)
   434  	for _, act := range actions {
   435  		ctxWithActionContext, err := withActionCtx(ctx, act)
   436  		if err != nil {
   437  			return err
   438  		}
   439  		for _, p := range reg.All() {
   440  			if validator, ok := p.(protocol.ActionValidator); ok {
   441  				if err := validator.Validate(ctxWithActionContext, act.Action(), ws); err != nil {
   442  					return err
   443  				}
   444  			}
   445  		}
   446  	}
   447  	for _, p := range reg.All() {
   448  		if pp, ok := p.(protocol.PreStatesCreator); ok {
   449  			if err := pp.CreatePreStates(ctx, ws); err != nil {
   450  				return err
   451  			}
   452  		}
   453  	}
   454  
   455  	receipts, err := ws.runActions(ctx, actions)
   456  	if err != nil {
   457  		return err
   458  	}
   459  	ws.receipts = receipts
   460  	return ws.finalize()
   461  }
   462  
   463  func (ws *workingSet) generateSystemActions(ctx context.Context) ([]action.Envelope, error) {
   464  	reg := protocol.MustGetRegistry(ctx)
   465  	postSystemActions := []action.Envelope{}
   466  	for _, p := range reg.All() {
   467  		if psc, ok := p.(protocol.PostSystemActionsCreator); ok {
   468  			elps, err := psc.CreatePostSystemActions(ctx, ws)
   469  			if err != nil {
   470  				return nil, err
   471  			}
   472  			postSystemActions = append(postSystemActions, elps...)
   473  		}
   474  	}
   475  	return postSystemActions, nil
   476  }
   477  
   478  // validateSystemActionLayout verify whether the post system actions are appended tail
   479  func (ws *workingSet) validateSystemActionLayout(ctx context.Context, actions []*action.SealedEnvelope) error {
   480  	postSystemActions, err := ws.generateSystemActions(ctx)
   481  	if err != nil {
   482  		return err
   483  	}
   484  	// system actions should be at the end of the action list, and they should be continuous
   485  	expectedStartIdx := len(actions) - len(postSystemActions)
   486  	sysActCnt := 0
   487  	for i := range actions {
   488  		if action.IsSystemAction(actions[i]) {
   489  			if i != expectedStartIdx+sysActCnt {
   490  				return errors.Wrapf(errInvalidSystemActionLayout, "the %d-th action should not be a system action", i)
   491  			}
   492  			if actions[i].Envelope.Proto().String() != postSystemActions[sysActCnt].Proto().String() {
   493  				return errors.Wrapf(errInvalidSystemActionLayout, "the %d-th action is not the expected system action", i)
   494  			}
   495  			sysActCnt++
   496  		}
   497  	}
   498  	if sysActCnt != len(postSystemActions) {
   499  		return errors.Wrapf(errInvalidSystemActionLayout, "the number of system actions is incorrect, expected %d, got %d", len(postSystemActions), sysActCnt)
   500  	}
   501  	return nil
   502  }
   503  
   504  func (ws *workingSet) pickAndRunActions(
   505  	ctx context.Context,
   506  	ap actpool.ActPool,
   507  	postSystemActions []*action.SealedEnvelope,
   508  	allowedBlockGasResidue uint64,
   509  ) ([]*action.SealedEnvelope, error) {
   510  	err := ws.validate(ctx)
   511  	if err != nil {
   512  		return nil, err
   513  	}
   514  	receipts := make([]*action.Receipt, 0)
   515  	executedActions := make([]*action.SealedEnvelope, 0)
   516  	reg := protocol.MustGetRegistry(ctx)
   517  
   518  	for _, p := range reg.All() {
   519  		if pp, ok := p.(protocol.PreStatesCreator); ok {
   520  			if err := pp.CreatePreStates(ctx, ws); err != nil {
   521  				return nil, err
   522  			}
   523  		}
   524  	}
   525  
   526  	// initial action iterator
   527  	blkCtx := protocol.MustGetBlockCtx(ctx)
   528  	ctxWithBlockContext := ctx
   529  	if ap != nil {
   530  		actionIterator := actioniterator.NewActionIterator(ap.PendingActionMap())
   531  		for {
   532  			nextAction, ok := actionIterator.Next()
   533  			if !ok {
   534  				break
   535  			}
   536  			if nextAction.GasLimit() > blkCtx.GasLimit {
   537  				actionIterator.PopAccount()
   538  				continue
   539  			}
   540  			actionCtx, err := withActionCtx(ctxWithBlockContext, nextAction)
   541  			if err == nil {
   542  				for _, p := range reg.All() {
   543  					if validator, ok := p.(protocol.ActionValidator); ok {
   544  						if err = validator.Validate(actionCtx, nextAction.Action(), ws); err != nil {
   545  							break
   546  						}
   547  					}
   548  				}
   549  			}
   550  			if err != nil {
   551  				caller := nextAction.SenderAddress()
   552  				if caller == nil {
   553  					return nil, errors.New("failed to get address")
   554  				}
   555  				ap.DeleteAction(caller)
   556  				actionIterator.PopAccount()
   557  				continue
   558  			}
   559  			receipt, err := ws.runAction(actionCtx, nextAction)
   560  			switch errors.Cause(err) {
   561  			case nil:
   562  				// do nothing
   563  			case action.ErrChainID:
   564  				continue
   565  			case action.ErrGasLimit:
   566  				actionIterator.PopAccount()
   567  				continue
   568  			default:
   569  				nextActionHash, hashErr := nextAction.Hash()
   570  				if hashErr != nil {
   571  					return nil, errors.Wrapf(hashErr, "Failed to get hash for %x", nextActionHash)
   572  				}
   573  				return nil, errors.Wrapf(err, "Failed to update state changes for selp %x", nextActionHash)
   574  			}
   575  			blkCtx.GasLimit -= receipt.GasConsumed
   576  			ctxWithBlockContext = protocol.WithBlockCtx(ctx, blkCtx)
   577  			receipts = append(receipts, receipt)
   578  			executedActions = append(executedActions, nextAction)
   579  
   580  			// To prevent loop all actions in act_pool, we stop processing action when remaining gas is below
   581  			// than certain threshold
   582  			if blkCtx.GasLimit < allowedBlockGasResidue {
   583  				break
   584  			}
   585  		}
   586  	}
   587  
   588  	for _, selp := range postSystemActions {
   589  		actionCtx, err := withActionCtx(ctxWithBlockContext, selp)
   590  		if err != nil {
   591  			return nil, err
   592  		}
   593  		receipt, err := ws.runAction(actionCtx, selp)
   594  		if err != nil {
   595  			return nil, err
   596  		}
   597  		receipts = append(receipts, receipt)
   598  		executedActions = append(executedActions, selp)
   599  	}
   600  	if protocol.MustGetFeatureCtx(ctx).CorrectTxLogIndex {
   601  		updateReceiptIndex(receipts)
   602  	}
   603  	ws.receipts = receipts
   604  
   605  	return executedActions, ws.finalize()
   606  }
   607  
   608  func updateReceiptIndex(receipts []*action.Receipt) {
   609  	var txIndex, logIndex uint32
   610  	for _, r := range receipts {
   611  		logIndex = r.UpdateIndex(txIndex, logIndex)
   612  		txIndex++
   613  	}
   614  }
   615  
   616  func (ws *workingSet) ValidateBlock(ctx context.Context, blk *block.Block) error {
   617  	if protocol.MustGetFeatureCtx(ctx).SkipSystemActionNonce {
   618  		if err := ws.validateNonceSkipSystemAction(ctx, blk); err != nil {
   619  			return errors.Wrap(err, "failed to validate nonce")
   620  		}
   621  	} else {
   622  		if err := ws.validateNonce(ctx, blk); err != nil {
   623  			return errors.Wrap(err, "failed to validate nonce")
   624  		}
   625  	}
   626  	if protocol.MustGetFeatureCtx(ctx).ValidateSystemAction {
   627  		if err := ws.validateSystemActionLayout(ctx, blk.RunnableActions().Actions()); err != nil {
   628  			return err
   629  		}
   630  	}
   631  
   632  	if err := ws.process(ctx, blk.RunnableActions().Actions()); err != nil {
   633  		log.L().Error("Failed to update state.", zap.Uint64("height", ws.height), zap.Error(err))
   634  		return err
   635  	}
   636  
   637  	digest, err := ws.digest()
   638  	if err != nil {
   639  		return err
   640  	}
   641  	if !blk.VerifyDeltaStateDigest(digest) {
   642  		return errors.Wrapf(block.ErrDeltaStateMismatch, "digest in block '%x' vs digest in workingset '%x'", blk.DeltaStateDigest(), digest)
   643  	}
   644  	receiptRoot := calculateReceiptRoot(ws.receipts)
   645  	if !blk.VerifyReceiptRoot(receiptRoot) {
   646  		return errors.Wrapf(block.ErrReceiptRootMismatch, "receipt root in block '%x' vs receipt root in workingset '%x'", blk.ReceiptRoot(), receiptRoot)
   647  	}
   648  
   649  	return nil
   650  }
   651  
   652  func (ws *workingSet) CreateBuilder(
   653  	ctx context.Context,
   654  	ap actpool.ActPool,
   655  	postSystemActions []*action.SealedEnvelope,
   656  	allowedBlockGasResidue uint64,
   657  ) (*block.Builder, error) {
   658  	actions, err := ws.pickAndRunActions(ctx, ap, postSystemActions, allowedBlockGasResidue)
   659  	if err != nil {
   660  		return nil, err
   661  	}
   662  
   663  	ra := block.NewRunnableActionsBuilder().
   664  		AddActions(actions...).
   665  		Build()
   666  
   667  	blkCtx := protocol.MustGetBlockCtx(ctx)
   668  	bcCtx := protocol.MustGetBlockchainCtx(ctx)
   669  	prevBlkHash := bcCtx.Tip.Hash
   670  	digest, err := ws.digest()
   671  	if err != nil {
   672  		return nil, errors.Wrap(err, "failed to get digest")
   673  	}
   674  
   675  	blkBuilder := block.NewBuilder(ra).
   676  		SetHeight(blkCtx.BlockHeight).
   677  		SetTimestamp(blkCtx.BlockTimeStamp).
   678  		SetPrevBlockHash(prevBlkHash).
   679  		SetDeltaStateDigest(digest).
   680  		SetReceipts(ws.receipts).
   681  		SetReceiptRoot(calculateReceiptRoot(ws.receipts)).
   682  		SetLogsBloom(calculateLogsBloom(ctx, ws.receipts))
   683  	return blkBuilder, nil
   684  }