github.com/iotexproject/iotex-core@v1.14.1-rc1/action/protocol/generic_validator.go (about)

     1  // Copyright (c) 2019 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 protocol
     7  
     8  import (
     9  	"context"
    10  
    11  	"github.com/pkg/errors"
    12  
    13  	"github.com/iotexproject/iotex-address/address"
    14  
    15  	"github.com/iotexproject/iotex-core/action"
    16  	"github.com/iotexproject/iotex-core/state"
    17  )
    18  
    19  type (
    20  	// AccountState defines a function to return the account state of a given address
    21  	AccountState func(context.Context, StateReader, address.Address) (*state.Account, error)
    22  	// GenericValidator is the validator for generic action verification
    23  	GenericValidator struct {
    24  		accountState AccountState
    25  		sr           StateReader
    26  	}
    27  )
    28  
    29  // NewGenericValidator constructs a new genericValidator
    30  func NewGenericValidator(sr StateReader, accountState AccountState) *GenericValidator {
    31  	return &GenericValidator{
    32  		sr:           sr,
    33  		accountState: accountState,
    34  	}
    35  }
    36  
    37  // Validate validates a generic action
    38  func (v *GenericValidator) Validate(ctx context.Context, selp *action.SealedEnvelope) error {
    39  	intrinsicGas, err := selp.IntrinsicGas()
    40  	if err != nil {
    41  		return err
    42  	}
    43  	if intrinsicGas > selp.GasLimit() {
    44  		return action.ErrIntrinsicGas
    45  	}
    46  
    47  	// Verify action using action sender's public key
    48  	if err := selp.VerifySignature(); err != nil {
    49  		return err
    50  	}
    51  	caller := selp.SenderAddress()
    52  	if caller == nil {
    53  		return errors.New("failed to get address")
    54  	}
    55  	// Reject action if nonce is too low
    56  	if action.IsSystemAction(selp) {
    57  		if selp.Nonce() != 0 {
    58  			return action.ErrSystemActionNonce
    59  		}
    60  	} else {
    61  		var (
    62  			nonce          uint64
    63  			featureCtx, ok = GetFeatureCtx(ctx)
    64  		)
    65  		if ok && featureCtx.FixGasAndNonceUpdate || selp.Nonce() != 0 {
    66  			confirmedState, err := v.accountState(ctx, v.sr, caller)
    67  			if err != nil {
    68  				return errors.Wrapf(err, "invalid state of account %s", caller.String())
    69  			}
    70  			if featureCtx.UseZeroNonceForFreshAccount {
    71  				nonce = confirmedState.PendingNonceConsideringFreshAccount()
    72  			} else {
    73  				nonce = confirmedState.PendingNonce()
    74  			}
    75  			if nonce > selp.Nonce() {
    76  				return action.ErrNonceTooLow
    77  			}
    78  		}
    79  	}
    80  
    81  	return selp.Action().SanityCheck()
    82  }