Skip to content

Commit

Permalink
Merged with master
Browse files Browse the repository at this point in the history
  • Loading branch information
UlyanaAndrukhiv committed Sep 9, 2024
2 parents 93aa09f + 661a419 commit fba4e0b
Show file tree
Hide file tree
Showing 56 changed files with 1,203 additions and 319 deletions.
8 changes: 7 additions & 1 deletion .github/workflows/tools.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,18 @@ jobs:
make tool-bootstrap tool-transit
mkdir boot-tools
mv bootstrap transit boot-tools/
sha256sum boot-tools/bootstrap > boot-tools/bootstrap.sha256sum
cat boot-tools/bootstrap.sha256sum
sha256sum boot-tools/transit > boot-tools/transit.sha256sum
cat boot-tools/transit.sha256sum
tar -czf boot-tools.tar ./boot-tools/
gsutil cp boot-tools.tar gs://flow-genesis-bootstrap/tools/${{ inputs.tag }}/boot-tools.tar
- name: Build and upload util
run: |
make tool-util
tar -czf util.tar util
sha256sum util > util.sha256sum
cat util.sha256sum
tar -czf util.tar util util.sha256sum
gsutil cp util.tar gs://flow-genesis-bootstrap/tools/${{ inputs.tag }}/util.tar
- name: Promote boot-tools
run: |
Expand Down
21 changes: 21 additions & 0 deletions access/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,14 @@ type NetworkParameters struct {
ChainID flow.ChainID
}

// CompatibleRange contains the first and the last height that the version supports.
type CompatibleRange struct {
// The first block that the version supports.
StartHeight uint64
// The last block that the version supports.
EndHeight uint64
}

// NodeVersionInfo contains information about node, such as semver, commit, sporkID, protocolVersion, etc
type NodeVersionInfo struct {
Semver string
Expand All @@ -272,4 +280,17 @@ type NodeVersionInfo struct {
ProtocolVersion uint64
SporkRootBlockHeight uint64
NodeRootBlockHeight uint64
CompatibleRange *CompatibleRange
}

// CompatibleRangeToMessage converts a flow.CompatibleRange to a protobuf message
func CompatibleRangeToMessage(c *CompatibleRange) *entities.CompatibleRange {
if c != nil {
return &entities.CompatibleRange{
StartHeight: c.StartHeight,
EndHeight: c.EndHeight,
}
}

return nil
}
1 change: 1 addition & 0 deletions access/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ func (h *Handler) GetNodeVersionInfo(
ProtocolVersion: nodeVersionInfo.ProtocolVersion,
SporkRootBlockHeight: nodeVersionInfo.SporkRootBlockHeight,
NodeRootBlockHeight: nodeVersionInfo.NodeRootBlockHeight,
CompatibleRange: CompatibleRangeToMessage(nodeVersionInfo.CompatibleRange),
},
}, nil
}
Expand Down
157 changes: 84 additions & 73 deletions access/validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,21 @@ import (
"errors"
"fmt"

"github.com/rs/zerolog/log"

"github.com/onflow/cadence"
jsoncdc "github.com/onflow/cadence/encoding/json"
"github.com/onflow/cadence/runtime/parser"
"github.com/onflow/crypto"
"github.com/onflow/flow-core-contracts/lib/go/templates"
"github.com/rs/zerolog/log"

cadenceutils "github.com/onflow/flow-go/access/utils"
"github.com/onflow/flow-go/fvm"
"github.com/onflow/flow-go/fvm/systemcontracts"
"github.com/onflow/flow-go/model/flow"
"github.com/onflow/flow-go/module"
"github.com/onflow/flow-go/module/execution"
"github.com/onflow/flow-go/module/metrics"
"github.com/onflow/flow-go/state"
"github.com/onflow/flow-go/state/protocol"
)
Expand Down Expand Up @@ -87,19 +90,28 @@ type TransactionValidationOptions struct {
CheckPayerBalance bool
}

type ValidationStep struct {
check func(*flow.TransactionBody) error
failReason string
}

type TransactionValidator struct {
blocks Blocks // for looking up blocks to check transaction expiry
chain flow.Chain // for checking validity of addresses
options TransactionValidationOptions
serviceAccountAddress flow.Address
limiter RateLimiter
scriptExecutor execution.ScriptExecutor
verifyPayerBalanceScript []byte
blocks Blocks // for looking up blocks to check transaction expiry
chain flow.Chain // for checking validity of addresses
options TransactionValidationOptions
serviceAccountAddress flow.Address
limiter RateLimiter
scriptExecutor execution.ScriptExecutor
verifyPayerBalanceScript []byte
transactionValidationMetrics module.TransactionValidationMetrics

validationSteps []ValidationStep
}

func NewTransactionValidator(
blocks Blocks,
chain flow.Chain,
transactionValidationMetrics module.TransactionValidationMetrics,
options TransactionValidationOptions,
executor execution.ScriptExecutor,
) (*TransactionValidator, error) {
Expand All @@ -109,80 +121,68 @@ func NewTransactionValidator(

env := systemcontracts.SystemContractsForChain(chain.ChainID()).AsTemplateEnv()

return &TransactionValidator{
blocks: blocks,
chain: chain,
options: options,
serviceAccountAddress: chain.ServiceAddress(),
limiter: NewNoopLimiter(),
scriptExecutor: executor,
verifyPayerBalanceScript: templates.GenerateVerifyPayerBalanceForTxExecution(env),
}, nil
txValidator := &TransactionValidator{
blocks: blocks,
chain: chain,
options: options,
serviceAccountAddress: chain.ServiceAddress(),
limiter: NewNoopLimiter(),
scriptExecutor: executor,
verifyPayerBalanceScript: templates.GenerateVerifyPayerBalanceForTxExecution(env),
transactionValidationMetrics: transactionValidationMetrics,
}

txValidator.initValidationSteps()

return txValidator, nil
}

func NewTransactionValidatorWithLimiter(
blocks Blocks,
chain flow.Chain,
options TransactionValidationOptions,
transactionValidationMetrics module.TransactionValidationMetrics,
rateLimiter RateLimiter,
) *TransactionValidator {
return &TransactionValidator{
blocks: blocks,
chain: chain,
options: options,
serviceAccountAddress: chain.ServiceAddress(),
limiter: rateLimiter,
}
}

func (v *TransactionValidator) Validate(ctx context.Context, tx *flow.TransactionBody) (err error) {
// rate limit transactions for specific payers.
// a short term solution to prevent attacks that send too many failed transactions
// if a transaction is from a payer that should be rate limited, all the following
// checks will be skipped
err = v.checkRateLimitPayer(tx)
if err != nil {
return err
}

err = v.checkTxSizeLimit(tx)
if err != nil {
return err
}

err = v.checkMissingFields(tx)
if err != nil {
return err
}

err = v.checkGasLimit(tx)
if err != nil {
return err
txValidator := &TransactionValidator{
blocks: blocks,
chain: chain,
options: options,
serviceAccountAddress: chain.ServiceAddress(),
limiter: rateLimiter,
transactionValidationMetrics: transactionValidationMetrics,
}

err = v.checkExpiry(tx)
if err != nil {
return err
}
txValidator.initValidationSteps()

err = v.checkCanBeParsed(tx)
if err != nil {
return err
}
return txValidator
}

err = v.checkAddresses(tx)
if err != nil {
return err
func (v *TransactionValidator) initValidationSteps() {
v.validationSteps = []ValidationStep{
// rate limit transactions for specific payers.
// a short term solution to prevent attacks that send too many failed transactions
// if a transaction is from a payer that should be rate limited, all the following
// checks will be skipped
{v.checkRateLimitPayer, metrics.InvalidTransactionRateLimit},
{v.checkTxSizeLimit, metrics.InvalidTransactionByteSize},
{v.checkMissingFields, metrics.IncompleteTransaction},
{v.checkGasLimit, metrics.InvalidGasLimit},
{v.checkExpiry, metrics.ExpiredTransaction},
{v.checkCanBeParsed, metrics.InvalidScript},
{v.checkAddresses, metrics.InvalidAddresses},
{v.checkSignatureFormat, metrics.InvalidSignature},
{v.checkSignatureDuplications, metrics.DuplicatedSignature},
}
}

err = v.checkSignatureFormat(tx)
if err != nil {
return err
}
func (v *TransactionValidator) Validate(ctx context.Context, tx *flow.TransactionBody) (err error) {

err = v.checkSignatureDuplications(tx)
if err != nil {
return err
for _, step := range v.validationSteps {
if err = step.check(tx); err != nil {
v.transactionValidationMetrics.TransactionValidationFailed(step.failReason)
return err
}
}

err = v.checkSufficientBalanceToPayForTransaction(ctx, tx)
Expand All @@ -192,15 +192,19 @@ func (v *TransactionValidator) Validate(ctx context.Context, tx *flow.Transactio
// are 'internal' and related to script execution process. they shouldn't
// prevent the transaction from proceeding.
if IsInsufficientBalanceError(err) {
v.transactionValidationMetrics.TransactionValidationFailed(metrics.InsufficientBalance)
return err
}

// log and ignore all other errors
v.transactionValidationMetrics.TransactionValidationSkipped()
log.Info().Err(err).Msg("check payer validation skipped due to error")
}

// TODO replace checkSignatureFormat by verifying the account/payer signatures

v.transactionValidationMetrics.TransactionValidated()

return nil
}

Expand Down Expand Up @@ -316,19 +320,27 @@ func (v *TransactionValidator) checkExpiry(tx *flow.TransactionBody) error {
return nil
}

func (v *TransactionValidator) checkCanBeParsed(tx *flow.TransactionBody) error {
func (v *TransactionValidator) checkCanBeParsed(tx *flow.TransactionBody) (err error) {
defer func() {
if r := recover(); r != nil {
if panicErr, ok := r.(error); ok {
err = InvalidScriptError{ParserErr: panicErr}
} else {
err = InvalidScriptError{ParserErr: fmt.Errorf("non-error-typed panic: %v", r)}
}
}
}()
if v.options.CheckScriptsParse {
_, err := parser.ParseProgram(nil, tx.Script, parser.Config{})
if err != nil {
return InvalidScriptError{ParserErr: err}
_, parseErr := parser.ParseProgram(nil, tx.Script, parser.Config{})
if parseErr != nil {
return InvalidScriptError{ParserErr: parseErr}
}
}

return nil
}

func (v *TransactionValidator) checkAddresses(tx *flow.TransactionBody) error {

for _, address := range append(tx.Authorizers, tx.Payer) {
// we check whether this is a valid output of the address generator
if !v.chain.IsValid(address) {
Expand Down Expand Up @@ -356,7 +368,6 @@ func (v *TransactionValidator) checkSignatureDuplications(tx *flow.TransactionBo
}

func (v *TransactionValidator) checkSignatureFormat(tx *flow.TransactionBody) error {

for _, signature := range append(tx.PayloadSignatures, tx.EnvelopeSignatures...) {
// check the format of the signature is valid.
// a valid signature is an ECDSA signature of either P-256 or secp256k1 curve.
Expand Down
10 changes: 7 additions & 3 deletions access/validator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@ import (
accessmock "github.com/onflow/flow-go/access/mock"
"github.com/onflow/flow-go/fvm"
"github.com/onflow/flow-go/model/flow"
"github.com/onflow/flow-go/module"
execmock "github.com/onflow/flow-go/module/execution/mock"
"github.com/onflow/flow-go/module/metrics"
"github.com/onflow/flow-go/utils/unittest"
)

Expand All @@ -31,9 +33,11 @@ type TransactionValidatorSuite struct {
header *flow.Header
chain flow.Chain
validatorOptions access.TransactionValidationOptions
metrics module.TransactionValidationMetrics
}

func (s *TransactionValidatorSuite) SetupTest() {
s.metrics = metrics.NewNoopCollector()
s.blocks = accessmock.NewBlocks(s.T())
assert.NotNil(s.T(), s.blocks)

Expand Down Expand Up @@ -89,7 +93,7 @@ func (s *TransactionValidatorSuite) TestTransactionValidator_ScriptExecutorInter
Return(nil, errors.New("script executor internal error")).
Once()

validator, err := access.NewTransactionValidator(s.blocks, s.chain, s.validatorOptions, scriptExecutor)
validator, err := access.NewTransactionValidator(s.blocks, s.chain, s.metrics, s.validatorOptions, scriptExecutor)
assert.NoError(s.T(), err)
assert.NotNil(s.T(), validator)

Expand All @@ -116,7 +120,7 @@ func (s *TransactionValidatorSuite) TestTransactionValidator_SufficientBalance()
Return(actualResponse, nil).
Once()

validator, err := access.NewTransactionValidator(s.blocks, s.chain, s.validatorOptions, scriptExecutor)
validator, err := access.NewTransactionValidator(s.blocks, s.chain, s.metrics, s.validatorOptions, scriptExecutor)
assert.NoError(s.T(), err)
assert.NotNil(s.T(), validator)

Expand Down Expand Up @@ -147,7 +151,7 @@ func (s *TransactionValidatorSuite) TestTransactionValidator_InsufficientBalance
assert.NoError(s.T(), err)
assert.NotNil(s.T(), actualAccountResponse)

validator, err := access.NewTransactionValidator(s.blocks, s.chain, s.validatorOptions, scriptExecutor)
validator, err := access.NewTransactionValidator(s.blocks, s.chain, s.metrics, s.validatorOptions, scriptExecutor)
assert.NoError(s.T(), err)
assert.NotNil(s.T(), validator)

Expand Down
Loading

0 comments on commit fba4e0b

Please sign in to comment.