From 18b44aae4ebd56f8e20db4aafb994b06616d8b29 Mon Sep 17 00:00:00 2001 From: Jordan Schalm Date: Wed, 29 May 2024 14:48:16 -0700 Subject: [PATCH 1/2] add test case for large script --- engine/collection/ingest/engine_test.go | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/engine/collection/ingest/engine_test.go b/engine/collection/ingest/engine_test.go index 97eab113c97..6db20d29e2b 100644 --- a/engine/collection/ingest/engine_test.go +++ b/engine/collection/ingest/engine_test.go @@ -172,6 +172,24 @@ func (suite *Suite) TestInvalidTransaction() { suite.Assert().True(errors.As(err, &access.InvalidScriptError{})) }) + suite.Run("transaction script exceeds parse token limit", func() { + unittest.SkipUnless(suite.T(), unittest.TEST_TODO, "https://github.com/dapperlabs/flow-go/issues/6964") + // https://github.com/onflow/cadence/blob/master/runtime/parser/lexer/lexer.go#L32 + const tokenLimit = 1 << 19 + script := "{};" + for len(script) < tokenLimit { + script += script + } + + tx := unittest.TransactionBodyFixture() + tx.ReferenceBlockID = suite.root.ID() + tx.Script = []byte("transaction { execute {" + script + "}}") + + err := suite.engine.ProcessTransaction(&tx) + suite.Assert().Error(err) + suite.Assert().True(errors.As(err, &access.InvalidScriptError{})) + }) + suite.Run("invalid signature format", func() { signer := flow.Testnet.Chain().ServiceAddress() keyIndex := uint32(0) From 1bcb914e7648ede21459ee15bf79891c1462f119 Mon Sep 17 00:00:00 2001 From: Jordan Schalm Date: Wed, 4 Sep 2024 09:14:07 -0700 Subject: [PATCH 2/2] add recover to validator, document test case --- access/validator.go | 17 +++++++++++++---- engine/collection/ingest/engine_test.go | 7 ++++--- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/access/validator.go b/access/validator.go index f0dec8071d0..00d902d0c10 100644 --- a/access/validator.go +++ b/access/validator.go @@ -320,11 +320,20 @@ 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} } } diff --git a/engine/collection/ingest/engine_test.go b/engine/collection/ingest/engine_test.go index 6db20d29e2b..f96cebc7908 100644 --- a/engine/collection/ingest/engine_test.go +++ b/engine/collection/ingest/engine_test.go @@ -172,9 +172,10 @@ func (suite *Suite) TestInvalidTransaction() { suite.Assert().True(errors.As(err, &access.InvalidScriptError{})) }) - suite.Run("transaction script exceeds parse token limit", func() { - unittest.SkipUnless(suite.T(), unittest.TEST_TODO, "https://github.com/dapperlabs/flow-go/issues/6964") - // https://github.com/onflow/cadence/blob/master/runtime/parser/lexer/lexer.go#L32 + // In some cases the Cadence parser will panic rather than return an error. + // If this happens, we should recover from the panic and return an InvalidScriptError. + // See: https://github.com/onflow/cadence/issues/3428, https://github.com/dapperlabs/flow-go/issues/6964 + suite.Run("transaction script exceeds parse token limit (Cadence parser panic should be caught)", func() { const tokenLimit = 1 << 19 script := "{};" for len(script) < tokenLimit {