/
generic_validator.go
75 lines (67 loc) · 2.32 KB
/
generic_validator.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
// Copyright (c) 2019 IoTeX Foundation
// This is an alpha (internal) release and is not suitable for production. This source code is provided 'as is' and no
// warranties are given as to title or non-infringement, merchantability or fitness for purpose and, to the extent
// permitted by law, all liability for your use of the code is disclaimed. This source code is governed by Apache
// License 2.0 that can be found in the LICENSE file.
package protocol
import (
"context"
"github.com/iotexproject/iotex-address/address"
"github.com/pkg/errors"
"github.com/iotexproject/iotex-core/action"
"github.com/iotexproject/iotex-core/state"
)
type (
// AccountState defines a function to return the account state of a given address
AccountState func(StateReader, string) (*state.Account, error)
// GenericValidator is the validator for generic action verification
GenericValidator struct {
accountState AccountState
sr StateReader
}
)
// NewGenericValidator constructs a new genericValidator
func NewGenericValidator(sr StateReader, accountState AccountState) *GenericValidator {
return &GenericValidator{
sr: sr,
accountState: accountState,
}
}
// Validate validates a generic action
func (v *GenericValidator) Validate(ctx context.Context, selp action.SealedEnvelope) error {
// Verify action using action sender's public key
if err := action.Verify(selp); err != nil {
return errors.Wrap(err, "failed to verify action signature")
}
caller, err := address.FromBytes(selp.SrcPubkey().Hash())
if err != nil {
return err
}
// Reject action if nonce is too low
confirmedState, err := v.accountState(v.sr, caller.String())
if err != nil {
return errors.Wrapf(err, "invalid state of account %s", caller.String())
}
pendingNonce := confirmedState.Nonce + 1
if selp.Nonce() > 0 && pendingNonce > selp.Nonce() {
return errors.Wrap(action.ErrNonce, "nonce is too low")
}
intrinsicGas, err := selp.IntrinsicGas()
if err != nil {
return err
}
ctx = WithActionCtx(ctx, ActionCtx{
Caller: caller,
ActionHash: selp.Hash(),
GasPrice: selp.GasPrice(),
IntrinsicGas: intrinsicGas,
Nonce: selp.Nonce(),
})
bcCtx := MustGetBlockchainCtx(ctx)
for _, validator := range bcCtx.Registry.All() {
if err := validator.Validate(ctx, selp.Action()); err != nil {
return err
}
}
return nil
}